NixOS Configuration

November 7, 2020 Linux 5 minutes, 10 seconds

The main config file of NixOS is /etc/nixos/configuration.nix. After each modification the changes must be propagate to the system (see NixOS Commands).

{ config, pkgs, ... }: defines a function with at least to arguments returning { option definitions} which are a set of name = value pairs.

Example for enabling apache2 service

{ config, pkgs, ... }:

{ services.httpd.enable = true;
  services.httpd.adminAddr = "";
  services.httpd.documentRoot = "/webroot";

which is equal to

{ config, pkgs, ... }:

{ services = {
    httpd = {
      enable = true;
      adminAddr = "";
      documentRoot = "/webroot";

Dots in option names are shorthand for a set containing another set

Options have a specified type. The most important are:

  1. Strings

    networking.hostName = "dexter";. Special characters need to be escaped with \. Multi-line strings are enclosed with double single quotes, e.g.

    networking.extraHosts =
  2. Booleans

    Can be true or false, e.g. networking.firewall.enable = true;

  3. Integers

    boot.kernel.sysctl."net.ipv4.tcp_keepalive_time" = 60;. Here, net.ivp4 is enclosed in quotes to prevent it from being interprated is set of sets. This is just the name of the kernel option

  4. Sets

        fileSystems."/boot" =
      { device = "/dev/sda1";
        fsType = "ext4";
        options = [ "rw" "data=ordered" "relatime" ];
  5. Lists

    boot.kernelModules = [ "fuse" "kvm-intel" "coretemp" ];. Note that elements are separated by whitespaces and can be of any type, e.g. sets swapDevices = [ { device = "/dev/disk/by-label/swap"; } ];

  6. Packages

      environment.systemPackages =
      [ pkgs.thunderbird
    postgresql.package = pkgs.postgresql90;

A comprehensive list of options can be found at NixOS options.

Abstractions provide a way to reduce redundancy in your configuration.

  exampleOrgCommon =
    { hostName = "";
      documentRoot = "/webroot";
      adminAddr = "";
      enableUserDir = true;
  services.httpd.virtualHosts =
    [ exampleOrgCommon
      (exampleOrgCommon // {
        enableSSL = true;
        sslServerCert = "/root/ssl-example-org.crt";
        sslServerKey = "/root/ssl-example-org.key";

This method also works on functions, here we generade a couple of virtual hosts which only differs by their hostnames:

  services.httpd.virtualHosts =
      makeVirtualHost = name:
        { hostName = name;
          documentRoot = "/webroot";
          adminAddr = "";
      [ (makeVirtualHost "")
        (makeVirtualHost "")
        (makeVirtualHost "")
        (makeVirtualHost "")

A further improvement of this configuration is the use of map

  services.httpd.virtualHosts =
      makeVirtualHost = ...;
    in map makeVirtualHost
      [ "" "" "" "" ];

Functions can also have more than one argument:

      makeVirtualHost = { name, root }:
        { hostName = name;
          documentRoot = root;
          adminAddr = "";
    in map makeVirtualHost

NixOS configuration can be split into different *.nix files and imported with imports = [ ./mod1.nix ./mod2.nix ]; into the main configuration. The modules have the same syntax as the main file. When necessary you can specify the ordering and the preference of settings. the config variable contains all options merged accross all config files. Access to this value is possible in your config

if then
      [ pkgs.firefox
      [ ];

and by using the command nixos-option OPTION which prints the value to stdout.

NixOS supports two styles of package managemetn:

  1. Declarative with your configuration.nix and nixos-rebuildwhere NixOS will ensure a consistet set of binaries
  2. Ad hoc with nix-env similar to traditional package management allowing to mix packages from different Nixpkgs versions.This is the only choice for non-root users.

By adding the desired package to environment.systemPackages = [ ... ];. Executing nix-env -qaP '*' --description lists all available packages. To uninstall a package simple remove it from the file. After modifying your packages run e.g. nixos-rebuild switch

Some packages allow further configuration e.g. firefox nixpkgs.config.firefox.enableGoogleTalkPlugin = true;

Unfortunately, Nixpkgs currently lacks a way to query available configuration options.

  • Even more advanced customisation is possible!
  • When a package is not available you can build your own package and optionally patch the official repo.

Installing a package can be done with nix-env -iA nixos.thunderbird. As root the package is saved in the nix profile /nix/var/nix/profiles/default and visible in the whole system. Otherwise as user it is installed in /nix/var/nix/profiles/per-user/username/profile and only visible to that user. The -A flag specifies the package by its attribute name; without it, the package is installed by matching against its package name (e.g. thunderbird). The latter is slower because it requires matching against all available Nix packages, and is ambiguous if there are multiple matching packages.

For updating packages run nix-channel --update nixos and than nix-env -i again. Other packages in the profile are not affectet and that's a crucial difference to the declarative method where 'nixos-rebuild' updates all packages from the channel. However, you can update all packages with nix-env -u '*'.

Unistalling works with nix-env -e thunderbird and rollback with nix-env --rollback.

system.autoUpgrade.enable = true;

Like in Package Management declarative and ad hoc style is possible.

  users.extraUsers.USERNAME = {
    createHome = true;
    home = "/home/user";
    extraGroups = [ "wheel" ];
    shell = pkgs.bashInteractive;
    openssh.authorizedKeys.keys = [ "ssh-rsa ..." ];
    uid = 1000;

This user has no password and is only able to login with its private ssh key. In order to use sudo -i a pasword is required. To set a password loin as root und execute passwd USERNAME.

As ad hoc style you can use standarf linux commands such as useradd, usermod, groupadd, etc.

nix.gc = {
  automatic = true;
  dates = "weekly";
  options = "--delete-older-than 30d";

In configuration.nix

  environment.systemPackages = with pkgs; [

  programs.zsh.enable = true;
  programs.zsh.interactiveShellInit = ''
    export ZSH=${pkgs.oh-my-zsh}/share/oh-my-zsh/

    # Customize your oh-my-zsh options here
    plugins=(git docker)

    bindkey '\e[5~' history-beginning-search-backward
    bindkey '\e[6~' history-beginning-search-forward

    setopt SHARE_HISTORY
    autoload -U compinit && compinit
    unsetopt menu_complete
    setopt completealiases

    if [ -f ~/.aliases ]; then
      source ~/.aliases

    source $ZSH/
  programs.zsh.promptInit = "";

  users.extraUsers.USER = {
    shell = pkgs.zsh;

NixOS comes with a simple staeful firewall wich is enabled per default. You can disable it with networking.firewall.enable = false;. To allow TCP/UDP ports use networking.firewall.allowedTCPPorts = [ 80 443 ]; (respective networking.firewall.allowedUDPPorts).