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 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 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/sda2
Open the partition
# cryptsetup luksOpen /dev/sda2 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
Format 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
root
partition on/mnt
mount /dev/vg/root /mnt
Mount the
boot
partition on/mnt/boot
mkdir /mnt/boot mount /dev/sda1 /mnt/boot
Enable 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:
true; networking.networkmanager.enable =
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:
with pkgs; [
environment.systemPackages =
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.03
6. 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
Nix
and theNixpkgs
repository.↩︎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. ¯\_(ツ)_/¯↩︎
Gnome
does seem to depend on network manager, whileKDE
did not.↩︎NixOS
share a similar release cycle/naming scheme asUbuntu
. Stable releases every ~6 months, with the year and month on the version number.↩︎