Over the past year, I have been utilizing Nix and NixOS as my primary OS. This blog will be a series of posts that document my journey into Nix and NixOS, and my recovery from being an Arch Linux addict. Initially what drew me to NixOS was its claim to be fully declarative and reproducible, with the whole system being managed by a configuration file that can be copied over to other machines and used to replicate the exact same system. Another feature that highly interested me was the way it handled software repositories, making it possible to have a mix of stable and unstable packages on a single system. Lastly, NixOS has a proven track record and won’t just get abandoned or disappear in the night. In fact, despite the recent uptick in popularity, NixOS has been around for a long time, even predating Ubuntu Linux itself.
My introduction Link to heading
I first learned about NixOS thanks to the great and powerful YouTube algorithm /s. First it was a video by The Linux Experiment, then, it was a recommendation of a video by Tidus Tech Tips. By then I was installing NixOS on a VM to get my hands dirty and making a mess of things. Not long after that, I found myself looking up other people’s configs and using them as a guide/inspiration for creating my configs. My flake is based heavily on a mix of LibrePhoenix’s and EmergentMind’s configs, as well as some inspirations from VimJoyer.
Overview of my NixOS configuration Link to heading
With Nix, there are two ways to manage your configuration; the first being the traditional channels approach, the other is the more modern way of using flakes. I chose to use flakes, as flakes make sharing the configuration files easier, plus even though flakes is still considered to be an experimental feature, there is huge growth and adoption of them by the Nix community.
Anatomy of my flake Link to heading
By design, I wanted to have a modular and flexible way to have my flake structured that would easily allow supporting different hosts, as well as be flexible enough to work for not only NixOS, but other Linux distributions as well as macOS. Where I ended up so far is with the following structure:
flake.nix
: Entry point for host and user configurations.hosts
: NixOS host configurations.common
: Shared configurations consumed by the machine-specific ones.core
: Configurations present across all hosts.optional
: Optional configurations present across more than one host.users
: Host level user configurations present across at least one host.
<host>
: Host specific configurations, including disk partitioning, and hardware profiles.
home/<user>
: Home-manager configurations.common
: Shared home-manager configurations consumed by the user’s machine-specific ones.core
: Home-manager configurations present for users across all machines.optional
: Optional home-manager configurations that can be added for specific machines.
<host>
: Host specific configurations for the user.
lib
: Custom nix libraries for various nix expressions.modules
: Custom modules to enable special functionality for NixOS or home-manager oriented configurations.nixos-installer
: Custom flake and expressions for generating a customized NixOS minimal installer image.overlays
: Custom modifications to upstream packages.pkgs
: Custom packages meant to be shared or upstreamed.scripts
: Custom scripts for automation.`themes
: Various configurations for defining a system-wide theme via Stylix.vars
: Various variable definitions that are shared across the flake.
Goals for my configuration Link to heading
As mentioned previously, I wanted a configuration that would not only support multiple hosts, but also be cross-platform. As things currently stand, it has been tested on NixOS for both AMD64 and AARCH64 CPU architectures, and ChromeOS. For the systems running NixOS, I had the additional goal of having everything being declared programmatically, and making use of ephemeral root storage. Luckily, there are two Nix modules maintained by the Nix community that make both of these goals possible. The first being Disko which makes it possible to partition and format disk(s) in a declarative way, and the second being Impermanence to make it possible to work with persistent state.
With these two modules I am able to have my disk(s) partitioned and formatted with BTRFS, have a blank snapshot created, do the installation, and configure what data should persist between reboots. Everything else gets discarded, as part of the boot process is restoring that blank snapshot putting the filesystem back in a state before I installed NixOS.
Closing remarks Link to heading
This was just a brief introduction to my NixOS setup. In the upcoming posts in this series, I’ll delve deeper into the specifics of my configuration, including:
- A step-by-step guide to configuring a declarative NixOS system with flakes.
- Exploring the power of home-manager for managing user environments.
- Advanced topics like ephemeral root storage and system theming.
Stay tuned for more insights and discoveries on my NixOS journey!