NixOS: Into the deep end
My first experience with a
Linux-based operating system was in the early 2000s. I remember a friend and I got hold of a
Red Hat installation disk, and thought we’d give it a test run. We managed to boot the image and I remember us ending up in quite an unfamiliar shell environment. We didn’t know how to launch programs, we didn’t even know which programs were accessible. Eventually we did manage to start Pidgin (called
GAIM at the time), most likely using some kind of a
DOS-inspired command, only working by accident.
I’ve been using several
Linux distributions to various degrees over the years since those initial baby steps.
Linux-based systems have been my OS of choice for my entire professional career, and for the last couple of years I’ve been using my work laptop as my main home computer as well. I can’t remember exactly which distros I’ve been using over the years, but to name a few, in no particular order: Slackware, Debian, Arch, Ubuntu, and, for the sake of completeness, a very brief stint with
BSD (I don’t even remember which).
Ubuntu is the only distribution I can say I’ve been running for a significant amount of time.
Linux distributions have come a long way with regards to usability, no
Linux setup is without its issues or challenges. This post is a consolidation of some of my notes and remarks on how to get
NixOS installed, and running.
Well, why not? I didn’t really have any particular reason as to why I wanted to try
NixOS. I guess it sounded luring for an entire operating system to be based off the
Nix build/package management system. Build recipies consumed by
Nix (the tool) are written using
Nix (the language), which is a pure, lazy programming language. The functional nature of the
Nix language makes it ideal for the declarative and deterministic domain of dependency and build management. Using
NixOS wouldn’t be possible without me fully embracing the
I was also growing a bit tired of my
Ubuntu installations. Both my laptop and desktop workstation had accumulated quite a bit of cruft over the years. Wanting to clean up my laptop would probably resulted in a full reinstall anyways. In the end, I guess I didn’t really need a whole lot of convincing. Once I heard some colleagues were also trying out
NixOS, that was enough for me. If somehow it didn’t work out, switching back wouldn’t mean much of a sunk cost.
Having made my decision, I quickly made an encrypted1 backup of my laptop’s home directory using duplicity, which turned out to be a pleasantly simple and useful little tool. I only used the full backup that
duplicity makes initially, but it also supports incremental backups, which I’ll keep in mind for later.
Bookmarks & resources
Access to documentation is vital whenever jumping into new tech. I found that the documentation hosted at nixos.org covered most of the questions and guidance I needed for the initial installation. Here are links to some of the resources I found the most useful:
Furthermore, there is also the
#nixos IRC channel on
freenode, and the NixOS Discourse wiki.
It’s worth noting that
Nix is quite the mouthful for newcomers, to put it mildly. In its attempt to be the one and only build and packaging system it has evolved into a large ecosystem of packages, libraries, conventions, and contributors. As a user you might get along nicely with
NixOS without having to dive deep into the tech, but as a developer creating your own
Nix expressions becomes inevitable fairly quickly2.
Of course we can’t start installing anything before having a boot medium with the installer on it.
NixOS can be downloaded from here. I don’t exactly remember how I created the installation
USB stick that I used, but I would guess I just used
# dd if=nixos.iso of=/dev/usb-device bs=4MB
About the installer
Linux users3, actually installing a distribution isn’t something you do all that often. Yet, it’s the installation process we’re first presented with when trying out a new distribution. Making installation as smooth as possible is crucial in order to drive adoption.
The boot menu of the
NixOS installer doesn’t let you choose between graphical or terminal based installation. However, you are dropped into a root shell which then notes how to start a graphical user interface. For the novice user, this might be a bit intimidating, seeing just the command line. It is very trivial to spawn the graphical user interface following the notes though. That the distribution chose to default to not starting the GUI does mean quicker boot times.
It is possible to install
NixOS using just the command line, meaning you never need to launch the graphical interface. The graphical installer does provide some benefits in that it includes a full browser (
Firefox), along with a link to the
NixOS manual on the desktop. This helps a lot if you don’t have access to another machine to look up documentation while installing, or if you end up having to do some extra troubleshooting.
Disk partitioning & encryption
NixOS installer doesn’t come with a managed partitioning wizard, like
Ubuntu does. This does imply a bit more fiddling for the user, unfortunately. Even more so for me, as I wanted to run with an encrypted file system as this was for my laptop. The
NixOS manual does include some notes regarding disk encryption, but I didn’t find it exhaustive enough, and had to read up on some of the
LUKS commands as well.
If I recall correctly, I had success following mostly just the steps from a couple of “Installing NixOS” blog posts: this one and this one. Following is a (hopefully complete) summary of the required partitioning commands4.
Create a partition table
# parted /dev/sda -- mklabel gpt
Add a boot partition
# parted /dev/sda -- mkpart ESP fat32 1MiB 512MiB # parted /dev/sda -- set 1 boot on
Add a root partition
# parted /dev/sda -- mkpart primary 512MiB -8GiB
Initialize an empty partition
# cryptsetup luksFormat /dev/sda2
Open the partition
# cryptsetup luksOpen /dev/sda3 enc-pv
Create lvm groups and volumes
# pvcreate /dev/mapper/enc-pv # vgcreate vg /dev/mapper/enc-pv # lvcreate -n swap vg -L 10G # lvcreate -n root vg -l 100%FREE
# mkfs.vfat -n BOOT /dev/sda2 # mkfs.ext4 -L root /dev/vg/root # mkswap -L swap /dev/vg/swap
Configuration and installation
Once the file system is correctly setup, it’s time to generate the initial configuration:
# nixos-generate-config --root /mnt
nixos-generate-config command just generates a default
configuration.nix file under
/mnt/etc/nixos/configuration.nix. This file is the system-wide configuration file, which declaratively specifies how the base system should be setup.
It’s not uncommon for other distro installers to have some kind of wizard guiding the user through the initial configuration steps. In
NixOS though, you’re shot right into your first
Nix expression, which is the format in which
configuration.nix is written.
The configuration file won’t change after the initial installation, and later system-wide changes have to be made in the same file. It’s worth noting that prior to installing the root filesystem is mounted under
/mnt, so on a running system the configuration file is to be found under
Depending on the desktop manager5 (or lack thereof), it might be necessary to enable
networking.networkmanager in order to gain network connectivity:
Users should mostly stick to installing whatever they need into their own user environment. Yet the
environment.systemPackages option allows specifying which packages should be exposed by default to all users. Some packages are obviously handy to install globally:
There are some
NixOS options related to
LUKS which are needed to successfully boot the system from the encrypted volume:
Users can also be defined declaratively (add the
networkmanager group to grant access to network settings):
configuration.nix, it’s time to install everything according to it:
Nix to start fetching packages, then symlinking everything into place. The install command is idempotent, so running it several times is perfectly fine. That’s also required in order to apply changes made to the configuration. The new system is ready to be booted into once the
nixos-install command terminates.
Just a few days after I installed
NixOS on my laptop a new stable branch was released:
19.036. Switching branches basically means switching the “nixos” channel, then upgrade all the packages to the derivations listed by the new channel:
# nix-channel --add https://nixos.org/channels/nixos-19.03 nixos # nixos-rebuild --upgrade boot
All in all after using
NixOS for a couple of months now, I can safely say I’m satisfied with both the distribution and my decision to try it out. There were several things I’ve spent a considerable amount of time scratching my head over, as well as other issues which I frankly haven’t figured out how to best do yet. I do consider this a long term learning experience, and so hopefully I’ll resolve most of these with time and a bit of effort. I plan to write one or more follow-up posts focusing more on
NixOS usage, and mainly how I use it for development. So stay tuned!
In case I had to move it off-site to have access to it.↩
Even just setting up development environments require basic knowledge of
Dev/Sysops people might in fact do this quite often. In this case, however, it’s basically about spawning replicated setups across a multitude of machines.↩
The plan was to write down all of the formatting and crypt setup steps immediately after having a successful install… yeah, that didn’t happen. ¯\_(ツ)_/¯↩
Gnomedoes seem to depend on network manager, while
NixOSshare a similar release cycle/naming scheme as
Ubuntu. Stable releases every ~6 months, with the year and month on the version number.↩