On Replacing Ubuntu with NixOS (part 1)
After I heard a great talk (at FrOSCon) given by @fpletz on NixOS, which is a Linux distribution built on top of the purely functional Nix package manager, … and I am on holiday this week … I decided to give it a try.
So I backed up my homedir and started replacing my Ubuntu installation, without much of a clue on NixOS … just being experienced with other more or less custom Linux installations (like Linux From Scratch back in the days, various Gentoo boxes, etc.)
Here’s my report and a collection of first experiences with my own very fresh installation, underlining findings which seem important to me. This is the first part (and I intend to add at least two more: one on package customisation and one on development environments)…
Requirements & Constraints
- my laptop: Thinkpad X220, 8 GB RAM, 120 GB SSD
- NixOS replacing Ubuntu (preserving nothing)
- fully encrypted root filesystem & swap space (LUKS)
- i3 improved tiling window manager among screen locking et al
Starting out
First read NixOS’ manual, at least the first major chapter (Installation) and the Wiki page on Encrypted Root on NixOS.
On NixOS’ Download Page there are effectively two choices, a Graphical live CD and a minimal installation. The Thinkpad X220 doesn’t have a CD-ROM drive, and the only USB stick I could find was just a few megabytes too small to fit the graphical live cd … so I went with the minimal installation …
First steps are fairly common, using fdisk
to create a new partition table, add a small /boot
partition and another big one taking the rest of the space (for LUKS). Then configure LUKS like
$ cryptsetup luksFormat /dev/sda2
$ cryptsetup luksOpen /dev/sda2 crypted
… and create a LVM volume group from it + three logical volumes (swap, root filesystem and /home
)
$ pvcreate /dev/mapper/crypted
$ vgcreate cryptedpool /dev/mapper/crypted
$ lvcreate -n swap cryptedpool -L 8GB
$ lvcreate -n root cryptedpool -L 50GB
$ lvcreate -n home cryptedpool -L 20GB
… last not least format those partitions …
$ mkfs.ext2 /dev/sda1
$ mkfs.ext4 /dev/cryptedpool/root
$ mkfs.ext4 /dev/cryptedpool/home
$ mkswap /dev/cryptedpool/swap
… and finally mount them …
$ mount /dev/cryptedpool/root /mnt
$ mkdir /mnt/{boot,home}
$ mount /dev/sda1 /mnt/boot
$ mount /dev/cryptedpool/home /mnt/home
$ swapon /dev/cryptedpool/swap
Initial Configuration
So we’re now ready to install, … and with other distributions we would now just launch the installer application. Not so with NixOS however, it expects you to create a configuration file first … to simplify this it provides a small generator tool:
$ nixos-generate-config --root /mnt
… which generates two files in /mnt/etc/nixos
:
-
hardware-configuration.nix
which mainly lists the required mounts -
configuration.nix
, after all the config file you’re expected to edit (primarily)
The installation image comes with nano
pre-installed, so let’s use it to modify the
hardware-configuration.nix
file to amend some filesystem options:
- configure root filesystem to not store access times and enable discard
- configure
/home
to support discard as well
… so let’s add option
blocks (and leave the rest untouched):
fileSystems."/" =
{ device = "/dev/disk/by-uuid/9d347599-a960-4076-8aa3-614bb9524322";
fsType = "ext4";
options = [ "noatime" "nodiratime" "discard" ];
};
fileSystems."/home" =
{ device = "/dev/disk/by-uuid/d4057681-2533-41b0-9175-18f134d7401f";
fsType = "ext4";
options = [ "discard" ];
};
I have enabled (online) discard on the encrypted filesystems as well as on the LUKS device (see below), also known as TRIM support. TRIM tells the SSD hardware which parts of the filesystem are unused and hence benefits wear leveling. However using discard in combination with encrypted filesystems makes some information (which blocks are unused) leak through the full disk encryption … an attacker might e.g. guess the filesystem type from the pattern of unused blocks. For me this doesn’t matter much but YMMV ;-)
So let’s continue and edit (read: add more stuff to) configuration.nix
. First some general system configuration:
# Define on which hard drive you want to install Grub.
boot.loader.grub.device = "/dev/sda";
# Tell initrd to unlock LUKS on /dev/sda2
boot.initrd.luks.devices = [
{ name = "crypted"; device = "/dev/sda2"; preLVM = true; allowDiscards = true; }
];
networking.hostName = "faulobst"; # Define your hostname.
# create a self-resolving hostname entry in /etc/hosts
networking.extraHosts = "127.0.1.1 faulobst";
# Let NetworkManager handle Network (mainly Wifi)
networking.networkmanager.enable = true;
# Select internationalisation properties.
i18n = {
consoleFont = "Lat2-Terminus16";
defaultLocale = "en_US.UTF-8";
# keyboard layout for your Linux console (i.e. off X11), dvp is for "Programmer Dvorak",
# if unsure pick "us" or "de" :)
consoleKeyMap = "dvp";
};
# Set your time zone.
time.timeZone = "Europe/Berlin";
# Enable the X11 windowing system.
services.xserver.enable = true;
services.xserver.layout = "us";
services.xserver.xkbVariant = "dvp"; # again, pick whichever layout you'd like to have
services.xserver.xkbOptions = "lv3:ralt_switch";
# Use i3 window manager
services.xserver.windowManager.i3.enable = true;
Packages
Of course our Linux installation should have some software installed. Unlike other distributions, where you typically install software every now and then and thus gradually mutate system state, NixOS allows a more declarative approach: you just list all system packages you’d like to have. Once you don’t want to have a package anymore you simply remove it from the list and Nix will arrange that it’s not available any longer.
Long story short, you have this central list of system packages (which you can also modify any time later) you’d like to have installed and NixOS will ensure they are installed:
… here is my current selection:
environment.systemPackages = with pkgs; [
bc
bwm_ng
coreutils
curl
file
gitAndTools.gitFull
gnupg
htop
libxml2 # xmllint
libxslt
lsof
mosh
psmisc # pstree, killall et al
pwgen
quilt
tmux
tree
unzip
utillinux
vim
w3m
wget
which
zip
chromium
firefox
gimp
i3 i3lock i3status dmenu
inkscape
keepassx2
libreoffice
networkmanagerapplet networkmanager_openvpn
xdg_utils
xfontsel
# gtk icons & themes
gtk gnome.gnomeicontheme hicolor_icon_theme shared_mime_info
dunst libnotify
xautolock
xss-lock
xfce.exo
xfce.gtk_xfce_engine
xfce.gvfs
xfce.terminal
xfce.thunar
xfce.thunar_volman
xfce.xfce4icontheme
xfce.xfce4settings
xfce.xfconf
];
… and we need to configure our Xsession startup …
- I went with
xfsettingsd
, the settings daemon from Xfce (inspiration from here) - NetworkManager applet, sitting in the task tray
-
xautolock
to lock the screen (usingi3lock
) after 1 minute (including a notification 10 seconds before actually locking the screen) -
xss-lock
to lock the screen on suspend (including keyboard hotkey)
services.xserver.displayManager.sessionCommands = ''
# Set GTK_PATH so that GTK+ can find the Xfce theme engine.
export GTK_PATH=${pkgs.xfce.gtk_xfce_engine}/lib/gtk-2.0
# Set GTK_DATA_PREFIX so that GTK+ can find the Xfce themes.
export GTK_DATA_PREFIX=${config.system.path}
# Set GIO_EXTRA_MODULES so that gvfs works.
export GIO_EXTRA_MODULES=${pkgs.xfce.gvfs}/lib/gio/modules
# Launch xfce settings daemon.
${pkgs.xfce.xfce4settings}/bin/xfsettingsd &
# Network Manager Applet
${pkgs.networkmanagerapplet}/bin/nm-applet &
# Screen Locking (time-based & on suspend)
${pkgs.xautolock}/bin/xautolock -detectsleep -time 1 \
-locker "${pkgs.i3lock}/bin/i3lock -c 000070" \
-notify 10 -notifier "${pkgs.libnotify}/bin/notify-send -u critical -t 10000 -- 'Screen will be locked in 10 seconds'" &
${pkgs.xss-lock}/bin/xss-lock -- ${pkgs.i3lock}/bin/i3lock -c 000070 &
User Configuration
… and our system needs a user account of course :)
NixOS allows for “mutable users”, i.e. you are allowed to create, modify and delete user accounts
at runtime (including changig the user’s password). Contrary you can disable mutable users and
controlling user accounts from configuration.nix
. As NixOS is about system purity I went with the
latter approach, so some more statements for the beloved configuration.nix
file:
users.mutableUsers = false;
users.extraUsers.stesie = {
isNormalUser = true;
home = "/home/stesie";
description = "Stefan Siegl";
extraGroups = [ "wheel" "networkmanager" ];
hashedPassword = "$6$VInXo5W.....$dVaVu.....cmmm09Q26r/";
};
… and finally we’re ready to go:
$ nixos-install
… if everything went well, just reboot
and say hello to your new system. If you’ve mis-typed
something fear not, simply fix it and re-run nixos-install
.
After you’ve finished installation and rebooted into your new system you can always come back and
further modify configuration.nix
file, just run nixos-rebuild switch
to apply the changes.