Through the Looking Glass

NixOS Experience Report

Posted on November 26, 2014

Introduction

I don’t remember exactly why I decided to start looking at NixOS but about a month ago I started looking at it. I began by installing it in a VM, then installed it on a pair of test machines: a ThinkPad X60s (the 32-bit test machine) and an Acer C720 (the 64-bit test machine). Two weeks ago, I installed it on a spare drive on my main laptop and have been spending most of my time in it. I’ve found myself fairly productive and the experience has been on par with Ubuntu, my previous primary Linux distribution; notably, the installation experience was much better than my Ubuntu experience in most cases.

The X230 install is comparable to my previous Ubuntu install: I have a LUKS-encrypted main partition and most of the same software installed.

There were a few places where I didn’t know how to do something; I typically found the answer quickly via the NixOS wiki. I’ve been lurking in the IRC channel but haven’t found the need to pay much attention or ask for help there.

Requirements

In order to place my experience in context, a brief description of what I look for out of an operating system is in order. I’ve been using *nix-based systems (mostly, NetBSD, OpenBSD, and Linux) as my primary operating system for over a decade and I have a well-established work flow now; while it’s not perfect, it’s at the point of being past sweeping changes.

The first and most important rule for my computers is that they stay out of my way. My primary use for computers is to get things done, and I expect my machines to service this purpose. A system that requires a lot of maintenance or hand-holding isn’t acceptable.

The second thing is that I look for systems that are hackable; I should be able to fix the pain points. As an example, I like emacs because I can adapt it to as new needs arise or when I find better ways of doing things, immediately apply those changes, and keep going.

The third thing is that I don’t want to spend much time doing #2, so I look for systems that fit well 90% of the time; only when warranted do I have to resort to #2.

I don’t mind investing time learning something new as long as it enables me to get things done better; examples include emacs, C, assembly, Plan 9, org-mode, Common Lisp, Coq, and Haskell. For all but Coq, it was important to immediately start solving problems while continuing to learn. I’ve come to accept that my initial efforts will be crude and primitive, but cement important principles and again, allow me to keep solving problems more effectively.

I also don’t mind swapping out pieces if they perform the equivalent job; for example, NixOS defaults to using slim as the display manager. This works fine, and I don’t have a need to change this behaviour.

First impressions

The typical Ubuntu installation is rather annoying. The installer will ask a question, perform some work, then block while waiting for the answer to the next question. In contrast, the best installer I’ve experienced is OpenBSD’s: all the questions are asked up front, then it does work.

NixOS’s installation reminded me a bit of Arch Linux’s. First, you set up your disks. Then, a skeleton configuration.nix is generated; finally, nixos-install performs all the work.

One advantage of the Ubuntu installer is how much easier it is to set up an encrypted root. I found the article “Installing NixOS on a ThinkPad W540 with encrypted root” to be instrumental in getting the encrypted root set up. I’ve also had experience manually setting up encrypted roots with OpenBSD, Gentoo, and Arch Linux.

Another thing that complicated the mix is that my network connection is a hotspot via my phone. Ubuntu contains the base software on disk, but NixOS fetched it remotely. This was slow and error-prone, as my connection often timed out. I ended up going somewhere else for the better internet to do this. This is also the reason certain packages aren’t in my configuration.nix; most notable of these is texlive.

Changes

There were a few changes to my normal setup to accomodate NixOS. Previously, I’d been using StumpWM as my window manager. I haven’t spent the time to figure out how to run this in NixOS, and a tiling window manager is a requirement; many of the people I saw using NixOS were using XMonad, which was as good an option as any.

I am also using slim as the display manager where previously I used xdm; this is due to slim being the default and working well enough to not warrant a change.

On systemd

I do not count myself a proponent of systemd, for reasons others have more eloquently elucidated elsehwere. That being said, it’s not worth fighting this battle after the decision has been made or continuing to burn out the people responsible for making these decisions with inhuman vitriol. Where appropriate, I will note my dissent, but I’d prefer to return to getting work done. As it stands, I currently use some combination of docker, virtual machines, circus, runit, and salt to handle process startup and supervision on my servers; this generally isn’t a consideration on my personal machine. Circumstances currently require that I run Linux, otherwise I would be using OpenBSD as my primary OS; I ran it for a long while previously and only stopped due to the need for certain Linux-specific features that are not germane to this report. I did consider other options, including a custom buildroot installation to set up an immutable, minimum base image to build on; the work required to build and maintain this system for my primary operating system was deemed untenable.

configuration.nix

Easily, my favourite feature of NixOS is configuration.nix. This file is the source from which the entire operating system is built. Here is a snapshot of the version I am using now on the X230:

# ono-sendai is a Lenovo X230 Thinkpad.

{ config, pkgs, ... }:

{
  imports =
    [ # Include the results of the hardware scan.
      ./hardware-configuration.nix
    ];

  boot.loader.grub.enable = true;
  boot.loader.grub.version = 2;
  boot.loader.grub.device = "/dev/sda";
  boot.initrd.luks.devices = [{
    name = "nixos";
    device = "/dev/sda3";
    preLVM = true;
  }];

  # use wicd instead of network manager
  networking.hostName = "ono-sendai"; # Define your hostname.
  networking.interfaceMonitor.enable = false;
  networking.useDHCP = false;
  networking.wicd.enable = true;

  # List packages installed in system profile. To search by name, run:
  # -env -qaP | grep wget
  environment.systemPackages = with pkgs; [
      lynx
      emacs24
      mg
      haskellPackages.ghc
      haskellPackages.xmonad
      dhcp 
      pmutils
      xscreensaver
      xlibs.xmodmap
      git
      clang
      mercurial
      automake
      autoconf
      libtool
      dmenu
      gnupg
      cmus
      tmux
      fish
  ];

  services.openssh.enable = true;
  services.upower.enable = true;

  services.xserver.enable = true;
  services.xserver.layout = "us";
  services.xserver.windowManager.xmonad.enable = true;
  services.xserver.windowManager.default = "xmonad";
  services.xserver.desktopManager.default = "none";
  services.xserver.windowManager.xmonad.enableContribAndExtras = true;

  # load xmodmap, xscreensaver.
  services.xserver.displayManager.sessionCommands = ''
    # Export the config/themes for slimlock.
    export SLIM_THEMESDIR=/nix/store/b3p1w1bn3vz68ijpqbz6
    $HOME/.xsession
  '';

  environment.shells = [
    "/run/current-system/sw/bin/fish"
  ];

  time.timeZone = "PST8PDT";

  networking.firewall.enable = true;
  networking.firewall.allowedTCPPorts = [ 80 443 ];

  # this should enable the trackpoint
  hardware.trackpoint.enable = true;
  hardware.trackpoint.emulateWheel = true;
}

The beautiful thing about this is that I can save this (for example, on Github) and back up my data as usual. If the need arises to perform a recovery, I follow the normal NixOS installation except that I swap in my configuration.nix (either via Github or flash drive), run nixos-install and my system is set up properly.

The use of this style of configuration does bring some other changes. Most of the base file system is left to be changed through this mechanism; instead of most software ending up in one of the various FHS bin directories, there are links in /run/current-system/sw/. This requires more use of /usr/bin/env, but the use of env generally makes for more portable scripts. (A common annoyance with, for example, OpenBSD, is the assumption that bash is both installed and in /bin/bash.)

The nixos-rebuild switch command updates the system to the current configuration.nix, handling starting (or stopping) services, installing required software, and so forth. As much as can be done without rebooting, the system switches over to the new configuration. The things that are generally not changed are the running kernel (which requires a reboot) and restarting the display manager (abruptly terminating any current X sessions is typically a rude thing to do).

Nix

As the name implies, NixOS uses Nix as its package manager.

Nix is not intuitive.

Software is organised into hierarchies; an example is nixos.pkgs.haskellPackages.xmonad. Often times, a package can be referred to its basename (e.g. xmonad); I haven’t spent a lot of time reading the Nix manual, so I’m not entirely certain when it needs the fully-qualified name.

Installation is done with nix-env -i; software can be rolled back if an update breaks. I did like this part, and had cause to use it when the conkeror package was broken at one point. The -i option, shorthand for --install, doesn’t seem to work with a fully-qualified name; this is done with -iA instead. This is the difference between the following two examples:

nix-env -i xmonad
nix-env -iA nixos.pkgs.haskellPackages.xmonad

Finding software is done with nix-env -qaP | grep <package>. This is tedious (and also not intuitive), but there are examples early in the NixOS manual that serve as a sort of crash-course in package management with Nix. I’ve aliased nix-search $1 to nix-env -qaP | grep $1. (Yes, I know about ag and yes, I still chose to use grep here.) Installed software can be updated with --upgrade.

Update: Georges Dubus pointed out on Twitter his nox tool that makes searching for packages easier. I haven’t installed it yet, but I plan to.

Software is found via channels; channels are manipulated through the nix-channel command. The current channels may be listed with the --list~ option, the channel can be updated with --update, and adding and removing are done with --add and --remove. One quirk is that --add operates on URLs, while --remove operates on names. Channels are semantically equivalent to repositories in /etc/apt/sources.list{,.d/}.

Knowing this much about Nix has been enough for the past two weeks.

There are certain pieces of software that I install manually (e.g. Go and StumpWM); I did this in Ubuntu as well so this isn’t a change from the status quo. Some of the packages (e.g. Go) were as outdated as they were in the Ubuntu repos.

Pain points

NixOS isn’t perfect, as one might expect from a relatively new and different distribution. I haven’t gotten dropbox to work (admittedly without spending much time trying to figure out why); this isn’t a showstopper, though.

I wanted to get Overtone working, but couldn’t figure out how to get PulseAudio working. This isn’t a big deal to me, though.

I haven’t figured out how to get my FIDO Yubikey working. I had problems with this in Ubuntu as well, and then it started working. I’m optimistic that with some further digging, I’ll get it working.

When Nix fails to fetch packages, it seems to need to re-download all the dependency packages, as well. This hurts on my current connection.

Conclusions

The past two weeks have been relatively unproblematic, and I have no plans to discontinue using NixOS at this time. It works well, so far stays out of my way (despite upgrading from the stable to unstable version), and though the system model is a bit different in respect to the FHS and configuration, I find that the benefits outweight the disadvantages here. The system is also stable, boots quickly, and after a day or two of setup and learning the system, I was up to speed (and working in the interim, as well). It quickly gave me a base system to start getting things done and I’ve been able to incrementally change things as needed.

Comments

If you have useful feedback, I can be found on Twitter. From there, if a longer discussion is called for, I can distribute my email address and/or XMPP handle.

Update: I’ve posted the story to Lobste.rs.