First steps to NixOS

I finally made my first steps with NixOS! I started to thnik about how to set up a multi-machine-multi-purpose configuration environment a few days ago, when I wasn’t able to sleep half of the night.

And, surprisingly, it works! So here is what I’ve done…

The idea

My idae was to have one setup which can be combined for every machine I have. So, it must fit:

  • My (future) desktop machine, which will have mutliple drives and multiple monitors. It will be a backup server for my other machines as well. It will be a development/gaming (as little gaming as I do - I still do it)/everything machine.
  • My current main machine: my Thinkpad. It is my current development machine as well as my machine for my university stuff etc.
  • My old notebook, which I play with (in manner of trying out nix configurations). I created the setup on this machine, as it already runs NixOS).
  • My old desktop computer, which is my “home-server” at the moment, mainly for my music and for storage.
  • Eventually for a root server I will have at any time in the future - who knows?

The problem

I had several problems with that. None of these machines will have the same setup, none of them need all packages and hell none of these machines will have the same services running. But all of them will have packages from a specific set of packages. Some of these machines will have the same services with the same configurations. So, I created a matrix of packages and one of services.

Packages

(Well, lets leak my new host names here as well…)

|           | Package-Set   | base  | dev   | desktop   | server    |
| Machine   |               |       |       |           |           |
| --------- | ------------- | ----- | ----- | --------- | --------- |
| lucy      |               | x     | x     | x         | x         |
| nyu       |               | x     | x     | x         |           |
| nox       |               | x     |       | x         |           |
| light     |               | x     |       |           | x         |

Explanation:

  • Hostnames, retreived from “Elfenlied” and “Deathnote” (nox is the opposite from “lumos” from Harry Potter)
    • “lucy” will be my tower machine
    • “nyu” will be my thinkpad
    • “nox” will be (and already is) my second notebook
    • “light” will be my home server
  • Packages
    • “base” is just the basic stuff, like “awk”, “vim”, “coreutils”, htop, etc
    • “dev” is my development stuff, so vim, gdb, git, cmake, make, valgrind, ruby, python, haskell, lua, etc.
    • “desktop” is everything graphical, so a browser, email client, irc client, etc.
    • “server” is everything which a server needs, so things like htop and other utilities

Maybe I will create even more package sets for music, music modifying (tags for example), music creation, movies, gaming, etc. But these are the basic sets I actually created.

As you can see, all hosts will get the basic package set. All desktop machines and notebooks will get the desktop set and just lucy and light will get the server set. Development will be on my current and my future main machine, but not on nox.

Services

When it comes to services, there are also some stuff each hosts needs and others don’t:

|           | Service-Type  | X | synergyClient | sshServer | printing  |
| Machine   |               |   |               |           |           |
| --------- | ------------- | - | ------------- | --------- | --------- |
| lucy      |               | x |               |           | x         |
| nyu       |               | x | x             | x         | x         |
| nox       |               | x | x             | x         |           |
| light     |               |   |               | x         |           |

Explanation:

  • “X” is the x server including my i3 setup and so on
  • “synergyClient” is the synergy configuration for the client
  • “sshServer” - nothing to explain here, I assume
  • “printing” - nothing to explain here as well…

Of course, lucy won’t have the ssh server enabled (maybe it will, but I’m rather sure I won’t need it on lucy). It will be the synergy server, so it doesn’t need a synergy client configuration as well.

Filesystem

I already mentioned that lucy will be a storage server as well as my main machine. I’m currently thinking about a 2 * 2 TiB configuration for the host itself but attaching 2 * 1 TiB and 1 * 2 TiB external USB storage as well. This would make “light” outdated, as this is my storage machine by now, but I will continue using it to play around with, especially with NixOps maybe.

So, I have a different filesystem configuration for each host. But that’s not a problem, as the next section shows…

The Solution

Of course, this was not everything. More services, more package sets and so on will follow, but they can be attached to my current setup really easily.

So, how did I do it? First, I want to thank “Lethalman” from the NixOS IRC channel, he helped me a lot!

So, I have a base configuration file, which looks like this:

{ config, pkgs, ... }:

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

  # Use the GRUB 2 boot loader.
  boot.loader.grub.enable = true;
  boot.loader.grub.version = 2;

  networking.firewall = {
    enable = true;
    allowedUDPPorts = [ ... ];
  };

  # Select internationalisation properties.
  i18n = {
    consoleFont = "lat9w-16";
    consoleKeyMap = "de";
    defaultLocale = "de_DE.UTF-8";
  };

  users.defaultUserShell = "/var/run/current-system/sw/bin/fish";

  # Define a user account. Don't forget to set a password with ‘passwd’.
  users.extraUsers.m = {
    name = "m";
    group = "users";
    uid = 1000;
    createHome = true;
    home = "/home/m";
    extraGroups = [ "wheel" "audio" "video" "power" ];
    shell = "/var/run/current-system/sw/bin/fish";
    openssh.authorizedKeys.keys = [ ... ];
  };

  time.timeZone = "Europe/Berlin";
}

(sadly, the fish shell does not work yet and I don’t know why).

As you can see, the grub configuration is just partly set, I did not mention on which drive grub shall be installed. Of course, this follows in the host-specific configuration file:

{ config, pkgs, ... }:

let
  configDir = /home/m/config/nixos;
in

{
  imports = [
    # Base configuration
    "${configDir}/base-configuration.nix"

    # Filesystem additions
    "${configDir}/fs/tmpfs.nix"

    # Services
    "${configDir}/services/synergyClient.nix"
    "${configDir}/services/x.nix"
    "${configDir}/services/sshServer.nix"
    "${configDir}/services/printing.nix"
  ];

  # Define on which hard drive you want to install Grub.
  boot.loader.grub.device = "/dev/sda";

  networking.hostName = "nox";
  networking.wireless.enable = true;

  nixpkgs.config = {
    allowUnfree = true;

  # Overrides for chromium, as stated in http://nixos.org/wiki/Enable_Browser_Plugins
    chromium = {
      enablePepperFlash = true; # Chromium removed support for Mozilla (NPAPI) plugins so Adobe Flash no longer works
        enablePepperPDF = true;
    };
  };

  environment.systemPackages = let
    basePkgs    = import "${configDir}/pkgs/basePackages.nix" pkgs;
    devPkgs     = import "${configDir}/pkgs/devPackages.nix" pkgs;
    desktopPkgs = import "${configDir}/pkgs/desktopPackages.nix" pkgs;
  in
    pkgs.lib.attrValues (basePkgs // devPkgs // desktopPkgs);

}

In this file, which is the host configuration for “nox”, I put grub on “/dev/sda”, included some service configuration files and imported some package sets as well as I did some more host-specific configuration.

The service files would look like this:

{
  # Enable the X11 windowing system.
  services.xserver = {
    enable = true;
    layout = "de";
    xkbOptions = "eurosign:e";

    # Display manager configuration
    displayManager.slim.enable = true;

    # Enable the i3 window manager.
    windowManager.i3.enable = true;
    windowManager.default = "i3";
  };
}

for the X-Server configuration. The package files look like this:

pkgs: {
  inherit (pkgs)
  acpid
  acpitool
  bashCompletion
  ...
  zip
  ;
}

And it works like a real charm!

Even more beneficial…

I can actually put this in a git repository. I actually already did this! I have a git repository on the host which will be named “nyu” after the port to NixOS. This git repository contains all my dotfiles. At the moment, I run Archlinux (without nix) on this machine, but I will keep the dotfiles repo, of course, and this enables me to just get the git repository and start using the already modified dotfiles.

More hosts can now be added really easily, as I just have to write one file for them, including everything I need from the other files and add some custom flags and configurations if I want. This file gets then symlinked from /etc/nixos/configuration.nix and I can run nixos-rebuild switch and I’m ready - setup for the machine and dotfiles are present and I can start using it! Awesome!

If you have suggestions how to improve this setup, let me know. If this article helped you with your setup, let me know as well!