NixOS: Into the deep end
Contents
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.
Although 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.
Why NixOS?
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 Nix
ecosystem.
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.
Downloading NixOS
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:
# dd if=nixos.iso of=/dev/usb-device bs=4MB
About the installer
For most 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
The 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 LVM and 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.
Find hard drive
The lsblk command lists block devices on the system. Find the name of the hard
drive to install NixOS on.
# lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
sda 8:0 0 24.5G 0 disk /
Partitioning with parted
Create a partition table
# parted /dev/sda -- mklabel gptAdd a boot partition
# parted /dev/sda -- mkpart ESP fat32 1MiB 512MiB # parted /dev/sda -- set 1 boot onAdd a root partition
# parted /dev/sda -- mkpart primary 512MiB 100%
Setting up LUKS
In order to run with disk encryption the hard drive must be setup with LUKS
through cryptsetup.
Initialize an empty partition
# cryptsetup luksFormat /dev/sda2Open the partition
# cryptsetup luksOpen /dev/sda2 enc-pvCreate 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%FREEFormat partitions
# mkfs.vfat -n BOOT /dev/sda1 # mkfs.ext4 -L root /dev/vg/root # mkswap -L swap /dev/vg/swap
Mount partitions and enable swap
Mount the
rootpartition on/mntmount /dev/vg/root /mntMount the
bootpartition on/mnt/bootmkdir /mnt/boot mount /dev/sda1 /mnt/bootEnable swap
swapon /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
The 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 /etc/nixos.
Depending on the desktop manager5 (or lack thereof), it might be necessary to
enable networking.networkmanager in order to gain network connectivity:
networking.networkmanager.enable = true;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:
environment.systemPackages = with pkgs; [
vim
w3m
wget
];There are some NixOS options related to LUKS which are needed to
successfully boot the system from the encrypted volume:
# LVM
boot.initrd.luks.devices.root = {
device = "/dev/disk/by-uuid/<disk-uuid-here>";
preLVM = true;
allowDiscards = true;
};Users can also be defined declaratively (add the networkmanager group to grant
access to network settings):
users.users.someuser = {
isNormalUser = true;
home = "/home/someuser";
description = "Some User";
extraGroups = [ "wheel" "networkmanager" ];
shell = pkgs.zsh;
};After saving configuration.nix, it’s time to install everything according to
it:
# nixos-install
This causes 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.
# reboot
Distribution upgrade
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-21.05 nixos
# nixos-rebuild --upgrade boot
First impressions
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!
Footnotes
In case I had to move it off-site to have access to it.↩︎
Even just setting up development environments require basic knowledge of
Nixand theNixpkgsrepository.↩︎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, whileKDEdid not.↩︎NixOSshare a similar release cycle/naming scheme asUbuntu. Stable releases every ~6 months, with the year and month on the version number.↩︎