Note: Commands prefixed with # have to be run as root, either requiring to login as root user or temporarily switching to it using sudo for example.

If you encounter problems, please report them on the Discourse or on the #nixos channel on Freenode . Bugs should be reported in NixOS’ GitHub issue tracker .

Additional information regarding the Nix package manager and the Nixpkgs project can be found in respectively the Nix manual and the Nixpkgs manual .

This manual describes how to install, use and extend NixOS, a Linux distribution based on the purely functional package management system Nix , that is composed using modules and packages defined in the Nixpkgs project.

This enables a periodically executed systemd service named nixos-upgrade.service . If the allowReboot option is false , it runs nixos-rebuild switch --upgrade to upgrade NixOS to the latest version in the current channel. (To see when the service runs, see systemctl list-timers .) If allowReboot is true , then the system will automatically reboot if the new generation contains a different kernel, initrd or kernel modules. You can also specify a channel explicitly, e.g.

You can keep a NixOS system up-to-date automatically by adding the following to configuration.nix :

Warning: It is generally safe to switch back and forth between channels. The only exception is that a newer NixOS may also have a newer Nix version, which may involve an upgrade of Nix’s database schema. This cannot be undone easily, so in that case you will not be able to go back to your original channel.

Note: Channels are set per user. This means that running nix-channel --add as a non root user (or without sudo) will not affect configuration in /etc/nixos/configuration.nix

which is equivalent to the more verbose nix-channel --update nixos; nixos-rebuild switch .

You can then upgrade NixOS to the latest version in your chosen channel by running

And if you want to live on the bleeding edge:

If you have a server, you may want to use the “small” channel instead:

(Be sure to include the nixos parameter at the end.) For instance, to use the NixOS 20.03 stable channel:

When you first install NixOS, you’re automatically subscribed to the NixOS channel that corresponds to your installation source. For instance, if you installed from a 20.03 ISO, you will be subscribed to the nixos-20.03 channel. To see which NixOS channel you’re subscribed to, run the following as root:

To see what channels are available, go to https://nixos.org/channels . (Note that the URIs of the various channels redirect to a directory that contains the channel’s latest version and includes ISO images and VirtualBox appliances.) Please note that during the release process, channels that are not yet released will be present here as well. See the Getting NixOS page https://nixos.org/nixos/download.html to find the newest supported stable release.

Small channels, such as nixos-20.03-small or nixos-unstable-small . These are identical to the stable and unstable channels described above, except that they contain fewer binary packages. This means they get updated faster than the regular channels (for instance, when a critical security patch is committed to NixOS’s source tree), but may require more packages to be built from source than usual. They’re mostly intended for server environments and as such contain few GUI applications.

The unstable channel, nixos-unstable . This corresponds to NixOS’s main development branch, and may thus see radical changes between channel updates. It’s not recommended for production systems.

Stable channels, such as nixos-20.03 . These only get conservative bug fixes and package upgrades. For instance, a channel update may cause the Linux kernel on your system to be upgraded from 4.19.34 to 4.19.38 (a minor bug fix), but not from 4.19. x to 4.20. x (a major change that has the potential to break things). Stable channels are generally maintained until the next stable branch is created.

The best way to keep your NixOS installation up to date is to use one of the NixOS channels. A channel is a Nix mechanism for distributing Nix expressions and associated binaries. The NixOS channels are updated automatically from NixOS’s Git repository after certain tests have passed and all packages have been built. These channels are:

allowing you to log in via SSH (assuming you have set the appropriate passwords or SSH authorized keys):

Important: delete the $hostname.qcow2 file if you have started the virtual machine at least once without the right users, otherwise the changes will not get picked up. You can forward ports on the host to the guest. For instance, the following will forward host port 2222 to guest port 22 (SSH):

The VM does not have any data from your host system, so your existing user accounts and home directories will not be available unless you have set mutableUsers = false . Another way is to temporarily add the following to your configuration:

If you have a machine that supports hardware virtualisation, you can also test the new configuration in a sandbox by building and running a QEMU virtual machine that contains the desired configuration. Just do

to build the configuration but nothing more. This is useful to see whether everything compiles cleanly.

which causes the new configuration (and previous ones created using -p test ) to show up in the GRUB submenu “NixOS - Profile 'test'”. This can be useful to separate test configurations from “stable” configurations.

You can make your configuration show up in a different submenu of the GRUB 2 boot screen by giving it a different profile name, e.g.

to build the configuration and make it the boot default, but not switch to it now (so it will only take effect after the next reboot).

to build the configuration and switch the running system to it, but without making it the boot default. So if (say) the configuration locks up your machine, you can just reboot to get back to a working configuration.

Warning: These commands must be executed as root, so you should either run them from a root shell or by prefixing them with sudo -i .

to build the new configuration, make it the default configuration for booting, and try to realise the configuration in the running system (e.g., by restarting system services).

The file /etc/nixos/configuration.nix contains the current configuration of your machine. Whenever you’ve changed something in that file, you should do

If you are switching networks with different proxy configurations, use theoption into switch proxies at runtime. Refer to Appendix A, Configuration Options for more information.

Setup the proxy environment variables in the shell where you are running nixos-install .

Update proxy configuration in /mnt/etc/nixos/configuration.nix to keep the internet accessible after reboot.

To install NixOS behind a proxy, do the following before running nixos-install .

It's also worth noting that this whole process can be automated. This is especially useful for Cloud VMs, where provider do not provide NixOS. For instance, nixos-infect uses the lustrate process to convert Digital Ocean droplets to NixOS from other distributions automatically.

And of course, if you're happy with NixOS and no longer need the old distribution:

This may work as is or you might also need to reinstall the boot loader

If for some reason you want to revert to the old distribution, you'll need to boot on a USB rescue disk and do something along these lines:

Cross your fingers, reboot, hopefully you should get a NixOS prompt!

Warning: Once you complete this step, your current distribution will no longer be bootable! If you didn't get all the NixOS configuration right, especially those settings pertaining to boot loading and root partition, NixOS may not be bootable either. Have a USB rescue device ready in case this happens.

Finally, move the /boot directory of your current distribution out of the way (the lustrate process will take care of the rest once you reboot, but this one must be moved out now because NixOS needs to install its own boot files:

Let's also make sure the NixOS configuration files are kept once we reboot on NixOS:

Support for NIXOS_LUSTRATE was added in NixOS 16.09. The act of "lustrating" refers to the wiping of the existing distribution. Creating /etc/NIXOS_LUSTRATE can also be used on NixOS to remove all mutable files from your root partition (anything that's not in /nix or /boot gets "lustrated" on the next boot.

Any file or directory listed in /etc/NIXOS_LUSTRATE (one per line)

/etc/NIXOS_LUSTRATE tells the NixOS bootup scripts to move everything that's in the root partition to /old-root . This will move your existing distribution out of the way in the very early stages of the NixOS bootup. There are exceptions (we do need to keep NixOS there after all), so the NixOS lustrate process will not touch:

/etc/NIXOS officializes that this is now a NixOS partition (the bootup scripts require its presence).

Change ownership of the /nix tree to root (since your Nix install was probably single user):

Build the NixOS closure and install it in the system profile:

You'll likely want to set a root password for your first boot using the configuration files because you won't have a chance to enter a password until after you reboot. You can initalize the root password to an empty one with this line: (and of course don't forget to set one once you've rebooted or to lock the account with sudo passwd -l root if you use sudo )

Note that this will place the generated configuration files in /etc/nixos . You'll probably want to edit the configuration files. Refer to the nixos-generate-config step in Chapter 2, Installing NixOS for more information.

Note: The following steps are only for installing NixOS in place using NIXOS_LUSTRATE :

If you do not wish to keep the Nix package manager installed either, run something like sudo rm -rv ~/.nix-* /nix and remove the line that the Nix installer added to your ~/.profile .

Optionally, you may want to clean up your non-NixOS distribution:

That should be it for installation to another partition!

Again, please refer to the nixos-install step in Chapter 2, Installing NixOS for more information.

Warning: Once you complete this step, you might no longer be able to boot on existing systems without the help of a rescue USB drive or similar.

(You can find the appropriate UUID for your partition in /dev/disk/by-uuid )

Consider setting up the NixOS bootloader to give you the ability to boot on your existing Linux partition. For instance, if you're using GRUB and your existing distribution is running Ubuntu, you may want to add something like this to your configuration.nix :

You'll probably want to edit the configuration files. Refer to the nixos-generate-config step in Chapter 2, Installing NixOS for more information.

If you're about to install NixOS in place using NIXOS_LUSTRATE there is nothing to do for this step.

At this point it is time to prepare your target partition. Please refer to the partitioning, file-system creation, and mounting steps of Chapter 2, Installing NixOS

Note: The following 5 steps are only for installing NixOS to another partition. For installing NixOS in place using NIXOS_LUSTRATE , skip ahead.

You'll need nixos-generate-config and nixos-install and we'll throw in some man pages and nixos-enter just in case you want to chroot into your NixOS partition. They are installed by default on NixOS, but you don't have NixOS yet..

You may want to throw in a nix-channel --update for good measure.

As that channel gets released without running the NixOS tests, it will be safer to use the nixos-* channels instead:

If you've just installed Nix on a non-NixOS distribution, you will be on the nixpkgs channel by default.

The first steps to all these are the same:

Install NixOS on your hard drive from the Live CD of any Linux distribution.

Install NixOS on the same partition (in place!), from your existing non-NixOS Linux distribution using NIXOS_LUSTRATE .

Install NixOS on another partition, from your existing Linux distribution (without the use of a USB or optical device!)

Because Nix (the package manager) & Nixpkgs (the Nix packages collection) can both be installed on any (most?) Linux distributions, they can be used to install NixOS in various creative ways. You can, for instance:

The folder will be available directly under the root directory.

Shared folders can be given a name and a path in the host system in the VirtualBox settings (Machine / Settings / Shared Folders, then click on the "Add" icon). Add the following to the /etc/nixos/configuration.nix to auto-mount them. If you do not add "nofail" , the system will no boot properly. The same goes for disabling rngd which is normally used to get randomness but this does not work in virtual machines.

Also remove the fsck that runs at startup. It will always fail to run, stopping your boot until you press * .

There are a few modifications you should make in configuration.nix. Enable booting:

Mount the CD-ROM with the NixOS ISO (by clicking on CD/DVD-ROM)

Installing NixOS into a VirtualBox guest is convenient for users who want to try NixOS without installing it on bare metal. If you want to use a pre-made VirtualBox appliance, it is available at the downloads page . If you want to set up a VirtualBox guest manually, follow these instructions:

In the future we may begin making these files available as build products from hydra at which point we will update this documentation with instructions on how to obtain them either for placing on a dedicated TFTP server or to boot them directly over the internet.

If you’re using iPXE, depending on how your HTTP/FTP/etc. server is configured you may be able to use netboot.ipxe unmodified, or you may need to update the paths to the files to match your server’s directory layout

If you’re using plain PXE, configure your boot loader to use the bzImage and initrd files and have it provide the same kernel command line arguments found in netboot.ipxe .

This will create a result directory containing: * bzImage – the Linux kernel * initrd – the initrd file * netboot.ipxe – an example ipxe script demonstrating the appropriate kernel command line arguments for this image

These instructions assume that you have an existing PXE or iPXE infrastructure and simply want to add the NixOS installer as another option. To build the necessary files from a recent version of nixpkgs, you can run:

Advanced users may wish to install NixOS using an existing PXE or iPXE setup.

The dd utility will write the image verbatim to the drive, making it the recommended option for both UEFI and non-UEFI installations.

Using the 'raw' rdiskN device instead of diskN completes in minutes instead of hours. After dd completes, a GUI dialog "The disk you inserted was not readable by this computer" will pop up, which can be ignored.

For systems without CD drive, the NixOS live CD can be booted from a USB stick. You can use the dd utility to write the image: dd if= path-to-image of= /dev/sdX . Be careful about specifying the correct drive; you can use the lsblk command to get a list of block devices.

To summarise, Example 2.3, “Commands for Installing NixOS on /dev/sda ” shows a typical sequence of commands for installing NixOS on an empty hard drive (here /dev/sda ). Example 2.4, “NixOS Configuration” shows a corresponding configuration Nix expression.

You may also want to install some software. For instance,

You’ll probably want to create some user accounts as well, which can be done with useradd :

You should log in and change the root password with passwd .

You should now be able to boot into the installed NixOS. The GRUB boot menu shows a list of available configurations (initially just one). Every time you change the NixOS configuration (see Changing Configuration ), a new item is added to the menu. This allows you to easily roll back to a previous configuration if something goes wrong.

Note: For unattended installations, it is possible to use nixos-install --no-root-passwd in order to disable the password prompt entirely.

As the last step, nixos-install will ask you to set the password for the root user, e.g.

This will install your system based on the configuration you provided. If anything fails due to a configuration problem or any other issue (such as a network outage while downloading binaries from the NixOS binary cache), you can re-run nixos-install after fixing your configuration.nix .

Note: Depending on your hardware configuration or type of file system, you may need to set the option boot.initrd.kernelModules to include the kernel modules that are necessary for mounting the root file system, otherwise the installed system will not be able to boot. (If this happens, boot from the installation media again, mount the target file system on /mnt , fix /mnt/etc/nixos/configuration.nix and rerun nixos-install .) In most cases, nixos-generate-config will figure out the required modules.

Another critical option is fileSystems , specifying the file systems that need to be mounted by NixOS. However, you typically don’t need to set it yourself, because nixos-generate-config sets it automatically in /mnt/etc/nixos/hardware-configuration.nix from your currently mounted file systems. (The configuration file hardware-configuration.nix is included from configuration.nix and will be overwritten by future invocations of nixos-generate-config ; thus, you generally should not modify it.) Additionally, you may want to look at Hardware configuration for known-hardware at this point or after installation.

If you need to configure networking for your machine the configuration options are described in Chapter 11, Networking . In particular, while wifi is supported on the installation image, it is not enabled by default in the configuration generated by nixos-generate-config .

If there are other operating systems running on the machine before installing NixOS, the boot.loader.grub.useOSProber option can be set to true to automatically add them to the grub menu.

You may want to look at the options starting with boot.loader.efi and boot.loader.systemd as well.

You must set the option boot.loader.systemd-boot.enable to true . nixos-generate-config should do this automatically for new configurations when booted in UEFI mode.

You must set the option boot.loader.grub.device to specify on which disk the GRUB boot loader is to be installed. Without it, NixOS cannot boot.

If you’re using the graphical ISO image, other editors may be available (such as vim ). If you have network access, you can also install other editors — for instance, you can install Emacs by running nix-env -f '<nixpkgs>' -iA emacs .

You should then edit /mnt/etc/nixos/configuration.nix to suit your needs:

The command nixos-generate-config can generate an initial configuration file for you:

You now need to create a file /mnt/etc/nixos/configuration.nix that specifies the intended configuration of the system. This is because NixOS has a declarative configuration model: you create or edit a description of the desired configuration of your system, and then NixOS takes care of making it happen. The syntax of the NixOS configuration file is described in Chapter 5, Configuration Syntax , while a list of available configuration options appears in Appendix A, Configuration Options . A minimal example is shown in Example 2.4, “NixOS Configuration” .

If your machine has a limited amount of memory, you may want to activate swap devices now ( swapon device ). The installer (or rather, the build actions that it may spawn) may need quite a bit of RAM, depending on your configuration.

Mount the target file system on which NixOS should be installed on /mnt , e.g.

For creating boot partitions: mkfs.fat . Again it’s recommended to assign a label to the boot partition: -n label . For example:

For creating swap partitions: mkswap . Again it’s recommended to assign a label to the swap partition: -L label . For example:

For initialising Ext4 partitions: mkfs.ext4 . It is recommended that you assign a unique symbolic label to the file system using the option -L label , since this makes the file system configuration independent from device changes. For example:

Note: The swap partition size rules are no different than for other Linux distributions.

Finally, add a swap partition. The size required will vary according to needs, here a 8GiB one is created.

Add the root partition. This will fill the the disk except for the end part, where the swap will live.

Here's an example partition scheme for Legacy Boot, using /dev/sda as the device.

Finally, the boot partition. NixOS by default uses the ESP (EFI system partition) as its /boot partition. It uses the initially reserved 512MiB at the start of the disk.

Note: The swap partition size rules are no different than for other Linux distributions.

Next, add a swap partition. The size required will vary according to needs, here a 8GiB one is created.

Add the root partition. This will fill the disk except for the end part, where the swap will live, and the space left in front (512MiB) which will be used by the boot partition.

Here's an example partition scheme for UEFI, using /dev/sda as the device.

The recommended partition scheme differs depending if the computer uses Legacy Boot or UEFI.

The NixOS installer ships with multiple partitioning tools. The examples below use parted , but also provides fdisk , gdisk , cfdisk , and cgdisk .

The NixOS installer doesn’t do any partitioning or formatting, so you need to do that yourself.

If you would like to continue the installation from a different machine you need to activate the SSH daemon via systemctl start sshd . You then must set a password for either root or nixos with passwd to be able to login.

To manually configure the wifi on the minimal installer, run wpa_supplicant -B -i interface -c <(wpa_passphrase 'SSID' 'key') .

To manually configure the network on the graphical installer, first disable network-manager with systemctl stop NetworkManager .

The boot process should have brought up networking (check ip a ). Networking is necessary for the installer, since it will download lots of stuff (such as source tarballs or Nixpkgs channel binaries). It’s best if you have a DHCP server on your network. Otherwise configure networking manually using ifconfig .

If you downloaded the graphical ISO image, you can run systemctl start display-manager to start the desktop environment. If you want to continue on the terminal, you can use loadkeys to switch to your preferred keyboard layout. (We even provide neo2 via loadkeys de neo !)

You are logged-in automatically as nixos . The nixos user account has an empty password so you can use sudo without a password.

The NixOS manual is available on virtual console 8 (press Alt+F8 to access) or by running nixos-help .

The installation media contains a basic NixOS installation. When it’s finished booting, it should have detected most of your hardware.

The installation media can be burned to a CD, or now more commonly, "burned" to a USB drive (see Section 2.5.1, “Booting from a USB Drive” ).

NixOS can be installed on BIOS or UEFI systems. The procedure for a UEFI installation is by and large the same as a BIOS installation. The differences are mentioned in the steps that follow.

Using NixOps, the NixOS-based cloud deployment tool, which allows you to provision VirtualBox and EC2 NixOS instances from declarative specifications. Check out the NixOps homepage for details.

Using AMIs for Amazon’s EC2. To find one for your region and instance type, please refer to the list of most recent AMIs .

Using virtual appliances in Open Virtualization Format (OVF) that can be imported into VirtualBox. These are available from the NixOS download page .

As an alternative to installing NixOS yourself, you can get a running NixOS system through several other means:

NixOS ISO images can be downloaded from the NixOS download page . There are a number of installation options. If you happen to have an optical drive and a spare CD, burning the image to CD and booting from that is probably the easiest option. Most people will need to prepare a USB stick to boot from. Section 2.5.1, “Booting from a USB Drive” describes the preferred method to prepare a USB stick. A number of alternative methods are presented in the NixOS Wiki .

This section describes how to obtain, install, and configure NixOS for first-time use.

Part II. Configuration

Chapter 5. Configuration Syntax Table of Contents 5.1. NixOS Configuration File 5.2. Abstractions 5.3. Modularity 5.4. Syntax Summary The NixOS configuration file /etc/nixos/configuration.nix is actually a Nix expression, which is the Nix package manager’s purely functional language for describing how to build packages and configurations. This means you have all the expressive power of that language at your disposal, including the ability to abstract over common patterns, which is very useful when managing complex systems. The syntax and semantics of the Nix language are fully described in the Nix manual, but here we give a short overview of the most important constructs useful in NixOS configuration files. 5.1. NixOS Configuration File The NixOS configuration file generally looks like this: { config, pkgs, ... }: { option definitions } The first line ( { config, pkgs, ... }: ) denotes that this is actually a function that takes at least the two arguments config and pkgs . (These are explained later.) The function returns a set of option definitions ( { ... } ). These definitions have the form name = value , where name is the name of an option and value is its value. For example, { config, pkgs, ... }: { services.httpd.enable = true; services.httpd.adminAddr = "alice@example.org"; services.httpd.virtualHosts.localhost.documentRoot = "/webroot"; } defines a configuration with three option definitions that together enable the Apache HTTP Server with /webroot as the document root. Sets can be nested, and in fact dots in option names are shorthand for defining a set containing another set. For instance, services.httpd.enable defines a set named services that contains a set named httpd , which in turn contains an option definition named enable with value true . This means that the example above can also be written as: { config, pkgs, ... }: { services = { httpd = { enable = true; adminAddr = "alice@example.org"; virtualHosts = { localhost = { documentRoot = "/webroot"; }; }; }; }; } which may be more convenient if you have lots of option definitions that share the same prefix (such as services.httpd ). NixOS checks your option definitions for correctness. For instance, if you try to define an option that doesn’t exist (that is, doesn’t have a corresponding option declaration), nixos-rebuild will give an error like: The option `services.httpd.enable' defined in `/etc/nixos/configuration.nix' does not exist. Likewise, values in option definitions must have a correct type. For instance, services.httpd.enable must be a Boolean ( true or false ). Trying to give it a value of another type, such as a string, will cause an error: The option value `services.httpd.enable' in `/etc/nixos/configuration.nix' is not a boolean. Options have various types of values. The most important are: Strings Strings are enclosed in double quotes, e.g. networking.hostName = "dexter"; Special characters can be escaped by prefixing them with a backslash (e.g. \" ). Multi-line strings can be enclosed in double single quotes, e.g. networking.extraHosts = '' 127.0.0.2 other-localhost 10.0.0.1 server ''; The main difference is that it strips from each line a number of spaces equal to the minimal indentation of the string as a whole (disregarding the indentation of empty lines), and that characters like " and \ are not special (making it more convenient for including things like shell code). See more info about this in the Nix manual here. Booleans These can be true or false , e.g. networking.firewall.enable = true; networking.firewall.allowPing = false; Integers For example, boot.kernel.sysctl ."net.ipv4.tcp_keepalive_time" = 60; (Note that here the attribute name net.ipv4.tcp_keepalive_time is enclosed in quotes to prevent it from being interpreted as a set named net containing a set named ipv4 , and so on. This is because it’s not a NixOS option but the literal name of a Linux kernel setting.) Sets Sets were introduced above. They are name/value pairs enclosed in braces, as in the option definition fileSystems ."/boot" = { device = "/dev/sda1"; fsType = "ext4"; options = [ "rw" "data=ordered" "relatime" ]; }; Lists The important thing to note about lists is that list elements are separated by whitespace, like this: boot.kernelModules = [ "fuse" "kvm-intel" "coretemp" ]; List elements can be any other type, e.g. sets: swapDevices = [ { device = "/dev/disk/by-label/swap"; } ]; Packages Usually, the packages you need are already part of the Nix Packages collection, which is a set that can be accessed through the function argument pkgs . Typical uses: environment.systemPackages = [ pkgs.thunderbird pkgs.emacs ]; services.postgresql.package = pkgs.postgresql_10; The latter option definition changes the default PostgreSQL package used by NixOS’s PostgreSQL service to 10.x. For more information on packages, including how to add new ones, see Section 6.1.2, “Adding Custom Packages”. 5.2. Abstractions If you find yourself repeating yourself over and over, it’s time to abstract. Take, for instance, this Apache HTTP Server configuration: { services.httpd.virtualHosts = { "blog.example.org" = { documentRoot = "/webroot/blog.example.org"; adminAddr = "alice@example.org"; forceSSL = true; enableACME = true; enablePHP = true; }; "wiki.example.org" = { documentRoot = "/webroot/wiki.example.org"; adminAddr = "alice@example.org"; forceSSL = true; enableACME = true; enablePHP = true; }; }; } It defines two virtual hosts with nearly identical configuration; the only difference is the document root directories. To prevent this duplication, we can use a let : let commonConfig = { adminAddr = "alice@example.org"; forceSSL = true; enableACME = true; }; in { services.httpd.virtualHosts = { "blog.example.org" = (commonConfig // { documentRoot = "/webroot/blog.example.org"; }); "wiki.example.org" = (commonConfig // { documentRoot = "/webroot/wiki.example.com"; }); }; } The let commonConfig = ... defines a variable named commonConfig . The // operator merges two attribute sets, so the configuration of the second virtual host is the set commonConfig extended with the document root option. You can write a let wherever an expression is allowed. Thus, you also could have written: { services.httpd.virtualHosts = let commonConfig = ... ; in { "blog.example.org" = (commonConfig // { ... }) "wiki.example.org" = (commonConfig // { ... }) }; } but not { let commonConfig = ... ; in ... ; } since attributes (as opposed to attribute values) are not expressions. Functions provide another method of abstraction. For instance, suppose that we want to generate lots of different virtual hosts, all with identical configuration except for the document root. This can be done as follows: { services.httpd.virtualHosts = let makeVirtualHost = webroot: { documentRoot = webroot; adminAddr = "alice@example.org"; forceSSL = true; enableACME = true; }; in { "example.org" = (makeVirtualHost "/webroot/example.org"); "example.com" = (makeVirtualHost "/webroot/example.com"); "example.gov" = (makeVirtualHost "/webroot/example.gov"); "example.nl" = (makeVirtualHost "/webroot/example.nl"); }; } Here, makeVirtualHost is a function that takes a single argument webroot and returns the configuration for a virtual host. That function is then called for several names to produce the list of virtual host configurations. 5.3. Modularity The NixOS configuration mechanism is modular. If your configuration.nix becomes too big, you can split it into multiple files. Likewise, if you have multiple NixOS configurations (e.g. for different computers) with some commonality, you can move the common configuration into a shared file. Modules have exactly the same syntax as configuration.nix . In fact, configuration.nix is itself a module. You can use other modules by including them from configuration.nix , e.g.: { config, pkgs, ... }: { imports = [ ./vpn.nix ./kde.nix ]; services.httpd.enable = true; environment.systemPackages = [ pkgs.emacs ]; ... } Here, we include two modules from the same directory, vpn.nix and kde.nix . The latter might look like this: { config, pkgs, ... }: { services.xserver.enable = true; services.xserver.displayManager.sddm.enable = true; services.xserver.desktopManager.plasma5.enable = true; } Note that both configuration.nix and kde.nix define the option environment.systemPackages . When multiple modules define an option, NixOS will try to merge the definitions. In the case of environment.systemPackages , that’s easy: the lists of packages can simply be concatenated. The value in configuration.nix is merged last, so for list-type options, it will appear at the end of the merged list. If you want it to appear first, you can use mkBefore : boot.kernelModules = mkBefore [ "kvm-intel" ]; This causes the kvm-intel kernel module to be loaded before any other kernel modules. For other types of options, a merge may not be possible. For instance, if two modules define services.httpd.adminAddr , nixos-rebuild will give an error: The unique option `services.httpd.adminAddr' is defined multiple times, in `/etc/nixos/httpd.nix' and `/etc/nixos/configuration.nix'. When that happens, it’s possible to force one definition take precedence over the others: services.httpd.adminAddr = pkgs.lib.mkForce "bob@example.org"; When using multiple modules, you may need to access configuration values defined in other modules. This is what the config function argument is for: it contains the complete, merged system configuration. That is, config is the result of combining the configurations returned by every module . For example, here is a module that adds some packages to environment.systemPackages only if services.xserver.enable is set to true somewhere else: { config, pkgs, ... }: { environment.systemPackages = if config. services.xserver.enable then [ pkgs.firefox pkgs.thunderbird ] else [ ]; } With multiple modules, it may not be obvious what the final value of a configuration option is. The command nixos-option allows you to find out: $ nixos-option services.xserver.enable true $ nixos-option boot.kernelModules [ "tun" "ipv6" "loop" ... ] Interactive exploration of the configuration is possible using nix repl, a read-eval-print loop for Nix expressions. A typical use: $ nix repl '<nixpkgs/nixos>' nix-repl> config. networking.hostName "mandark" nix-repl> map (x: x.hostName) config. services.httpd.virtualHosts [ "example.org" "example.gov" ] While abstracting your configuration, you may find it useful to generate modules using code, instead of writing files. The example below would have the same effect as importing a file which sets those options. { config, pkgs, ... }: let netConfig = { hostName }: { networking.hostName = hostName; networking.useDHCP = false; }; in { imports = [ (netConfig "nixos.localdomain") ]; } 5.4. Syntax Summary Below is a summary of the most important syntactic constructs in the Nix expression language. It’s not complete. In particular, there are many other built-in functions. See the Nix manual for the rest. Example Description Basic values "Hello world" A string "${pkgs.bash}/bin/sh" A string containing an expression (expands to "/nix/store/ hash -bash- version /bin/sh" ) true , false Booleans 123 An integer ./foo.png A path (relative to the containing Nix expression) Compound values { x = 1; y = 2; } A set with attributes named x and y { foo.bar = 1; } A nested set, equivalent to { foo = { bar = 1; }; } rec { x = "foo"; y = x + "bar"; } A recursive set, equivalent to { x = "foo"; y = "foobar"; } [ "foo" "bar" ] A list with two elements Operators "foo" + "bar" String concatenation 1 + 2 Integer addition "foo" == "f" + "oo" Equality test (evaluates to true ) "foo" != "bar" Inequality test (evaluates to true ) !true Boolean negation { x = 1; y = 2; }.x Attribute selection (evaluates to 1 ) { x = 1; y = 2; }.z or 3 Attribute selection with default (evaluates to 3 ) { x = 1; y = 2; } // { z = 3; } Merge two sets (attributes in the right-hand set taking precedence) Control structures if 1 + 1 == 2 then "yes!" else "no!" Conditional expression assert 1 + 1 == 2; "yes!" Assertion check (evaluates to "yes!" ). See Section 44.4, “Warnings and Assertions” for using assertions in modules let x = "foo"; y = "bar"; in x + y Variable definition with pkgs.lib; head [ 1 2 3 ] Add all attributes from the given set to the scope (evaluates to 1 ) Functions (lambdas) x: x + 1 A function that expects an integer and returns it increased by 1 (x: x + 1) 100 A function call (evaluates to 101) let inc = x: x + 1; in inc (inc (inc 100)) A function bound to a variable and subsequently called by name (evaluates to 103) { x, y }: x + y A function that expects a set with required attributes x and y and concatenates them { x, y ? "bar" }: x + y A function that expects a set with required attribute x and optional y , using "bar" as default value for y { x, y, ... }: x + y A function that expects a set with required attributes x and y and ignores any other attributes { x, y } @ args: x + y A function that expects a set with required attributes x and y , and binds the whole set to args Built-in functions import ./foo.nix Load and return Nix expression in given file map (x: x + x) [ 1 2 3 ] Apply a function to every element of a list (evaluates to [ 2 4 6 ] )

Chapter 6. Package Management Table of Contents 6.1. Declarative Package Management 6.2. Ad-Hoc Package Management This section describes how to add additional packages to your system. NixOS has two distinct styles of package management: Declarative, where you declare what packages you want in your configuration.nix . Every time you run nixos-rebuild , NixOS will ensure that you get a consistent set of binaries corresponding to your specification.

Ad hoc, where you install, upgrade and uninstall packages via the nix-env command. This style allows mixing packages from different Nixpkgs versions. It’s the only choice for non-root users. 6.1. Declarative Package Management With declarative package management, you specify which packages you want on your system by setting the option environment.systemPackages . For instance, adding the following line to configuration.nix enables the Mozilla Thunderbird email application: environment.systemPackages = [ pkgs.thunderbird ]; The effect of this specification is that the Thunderbird package from Nixpkgs will be built or downloaded as part of the system when you run nixos-rebuild switch. Note: Some packages require additional global configuration such as D-Bus or systemd service registration so adding them to Some packages require additional global configuration such as D-Bus or systemd service registration so adding them to environment.systemPackages might not be sufficient. You are advised to check the list of options whether a NixOS module for the package does not exist. You can get a list of the available packages as follows: $ nix-env -qaP '*' --description nixos.firefox firefox-23.0 Mozilla Firefox - the browser, reloaded ... The first column in the output is the attribute name, such as nixos.thunderbird . Note: the nixos prefix tells us that we want to get the package from the nixos channel and works only in CLI tools. In declarative configuration use pkgs prefix (variable). To “uninstall” a package, simply remove it from environment.systemPackages and run nixos-rebuild switch. 6.1.1. Customising Packages Some packages in Nixpkgs have options to enable or disable optional functionality or change other aspects of the package. For instance, the Firefox wrapper package (which provides Firefox with a set of plugins such as the Adobe Flash player) has an option to enable the Google Talk plugin. It can be set in configuration.nix as follows: nixpkgs.config.firefox.enableGoogleTalkPlugin = true; Warning: Unfortunately, Nixpkgs currently lacks a way to query available configuration options. Apart from high-level options, it’s possible to tweak a package in almost arbitrary ways, such as changing or disabling dependencies of a package. For instance, the Emacs package in Nixpkgs by default has a dependency on GTK 2. If you want to build it against GTK 3, you can specify that as follows: environment.systemPackages = [ (pkgs.emacs.override { gtk = pkgs.gtk3; }) ]; The function override performs the call to the Nix function that produces Emacs, with the original arguments amended by the set of arguments specified by you. So here the function argument gtk gets the value pkgs.gtk3 , causing Emacs to depend on GTK 3. (The parentheses are necessary because in Nix, function application binds more weakly than list construction, so without them, environment.systemPackages would be a list with two elements.) Even greater customisation is possible using the function overrideAttrs . While the override mechanism above overrides the arguments of a package function, overrideAttrs allows changing the attributes passed to mkDerivation . This permits changing any aspect of the package, such as the source code. For instance, if you want to override the source code of Emacs, you can say: environment.systemPackages = [ (pkgs.emacs.overrideAttrs (oldAttrs: { name = "emacs-25.0-pre"; src = /path/to/my/emacs/tree; })) ]; Here, overrideAttrs takes the Nix derivation specified by pkgs.emacs and produces a new derivation in which the original’s name and src attribute have been replaced by the given values by re-calling stdenv.mkDerivation . The original attributes are accessible via the function argument, which is conventionally named oldAttrs . The overrides shown above are not global. They do not affect the original package; other packages in Nixpkgs continue to depend on the original rather than the customised package. This means that if another package in your system depends on the original package, you end up with two instances of the package. If you want to have everything depend on your customised instance, you can apply a global override as follows: nixpkgs.config.packageOverrides = pkgs: { emacs = pkgs.emacs.override { gtk = pkgs.gtk3; }; }; The effect of this definition is essentially equivalent to modifying the emacs attribute in the Nixpkgs source tree. Any package in Nixpkgs that depends on emacs will be passed your customised instance. (However, the value pkgs.emacs in nixpkgs.config.packageOverrides refers to the original rather than overridden instance, to prevent an infinite recursion.) 6.1.2. Adding Custom Packages It’s possible that a package you need is not available in NixOS. In that case, you can do two things. First, you can clone the Nixpkgs repository, add the package to your clone, and (optionally) submit a patch or pull request to have it accepted into the main Nixpkgs repository. This is described in detail in the Nixpkgs manual. In short, you clone Nixpkgs: $ git clone https://github.com/NixOS/nixpkgs $ cd nixpkgs Then you write and test the package as described in the Nixpkgs manual. Finally, you add it to environment.systemPackages , e.g. environment.systemPackages = [ pkgs.my-package ]; and you run nixos-rebuild, specifying your own Nixpkgs tree: # nixos-rebuild switch -I nixpkgs=/path/to/my/nixpkgs The second possibility is to add the package outside of the Nixpkgs tree. For instance, here is how you specify a build of the GNU Hello package directly in configuration.nix : environment.systemPackages = let my-hello = with pkgs; stdenv.mkDerivation rec { name = "hello-2.8"; src = fetchurl { url = "mirror://gnu/hello/${name}.tar.gz"; sha256 = "0wqd8sjmxfskrflaxywc7gqw7sfawrfvdxd9skxawzfgyy0pzdz6"; }; }; in [ my-hello ]; Of course, you can also move the definition of my-hello into a separate Nix expression, e.g. environment.systemPackages = [ (import ./my-hello.nix) ]; where my-hello.nix contains: with import <nixpkgs> {}; # bring all of Nixpkgs into scope stdenv.mkDerivation rec { name = "hello-2.8"; src = fetchurl { url = "mirror://gnu/hello/${name}.tar.gz"; sha256 = "0wqd8sjmxfskrflaxywc7gqw7sfawrfvdxd9skxawzfgyy0pzdz6"; }; } This allows testing the package easily: $ nix-build my-hello.nix $ ./result/bin/hello Hello, world! 6.2. Ad-Hoc Package Management With the command nix-env, you can install and uninstall packages from the command line. For instance, to install Mozilla Thunderbird: $ nix-env -iA nixos.thunderbird If you invoke this as root, the package is installed in the Nix profile /nix/var/nix/profiles/default and visible to all users of the system; otherwise, the package ends up in /nix/var/nix/profiles/per-user/ username /profile and is not visible to other users. 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. Packages come from the NixOS channel. You typically upgrade a package by updating to the latest version of the NixOS channel: $ nix-channel --update nixos and then running nix-env -i again. Other packages in the profile are not affected; this is the crucial difference with the declarative style of package management, where running nixos-rebuild switch causes all packages to be updated to their current versions in the NixOS channel. You can however upgrade all packages for which there is a newer version by doing: $ nix-env -u '*' A package can be uninstalled using the -e flag: $ nix-env -e thunderbird Finally, you can roll back an undesirable nix-env action: $ nix-env --rollback nix-env has many more flags. For details, see the nix-env(1) manpage or the Nix manual.

Chapter 7. User Management NixOS supports both declarative and imperative styles of user management. In the declarative style, users are specified in configuration.nix . For instance, the following states that a user account named alice shall exist: users.users .alice = { isNormalUser = true; home = "/home/alice"; description = "Alice Foobar"; extraGroups = [ "wheel" "networkmanager" ]; openssh.authorizedKeys.keys = [ "ssh-dss AAAAB3Nza... alice@foobar" ]; }; Note that alice is a member of the wheel and networkmanager groups, which allows her to use sudo to execute commands as root and to configure the network, respectively. Also note the SSH public key that allows remote logins with the corresponding private key. Users created in this way do not have a password by default, so they cannot log in via mechanisms that require a password. However, you can use the passwd program to set a password, which is retained across invocations of nixos-rebuild. If you set users.mutableUsers to false, then the contents of /etc/passwd and /etc/group will be congruent to your NixOS configuration. For instance, if you remove a user from users.users and run nixos-rebuild, the user account will cease to exist. Also, imperative commands for managing users and groups, such as useradd, are no longer available. Passwords may still be assigned by setting the user's hashedPassword option. A hashed password can be generated using mkpasswd -m sha-512 after installing the mkpasswd package. A user ID (uid) is assigned automatically. You can also specify a uid manually by adding uid = 1000; to the user specification. Groups can be specified similarly. The following states that a group named students shall exist: users.groups .students.gid = 1000; As with users, the group ID (gid) is optional and will be assigned automatically if it’s missing. In the imperative style, users and groups are managed by commands such as useradd, groupmod and so on. For instance, to create a user account named alice : # useradd -m alice To make all nix tools available to this new user use `su - USER` which opens a login shell (==shell that loads the profile) for given user. This will create the ~/.nix-defexpr symlink. So run: # su - alice -c "true" The flag -m causes the creation of a home directory for the new user, which is generally what you want. The user does not have an initial password and therefore cannot log in. A password can be set using the passwd utility: # passwd alice Enter new UNIX password: *** Retype new UNIX password: *** A user can be deleted using userdel: # userdel -r alice The flag -r deletes the user’s home directory. Accounts can be modified using usermod. Unix groups can be managed using groupadd, groupmod and groupdel.

Chapter 8. File Systems Table of Contents 8.1. LUKS-Encrypted File Systems You can define file systems using the fileSystems configuration option. For instance, the following definition causes NixOS to mount the Ext4 file system on device /dev/disk/by-label/data onto the mount point /data : fileSystems ."/data" = { device = "/dev/disk/by-label/data"; fsType = "ext4"; }; Mount points are created automatically if they don’t already exist. For device , it’s best to use the topology-independent device aliases in /dev/disk/by-label and /dev/disk/by-uuid , as these don’t change if the topology changes (e.g. if a disk is moved to another IDE controller). You can usually omit the file system type ( fsType ), since mount can usually detect the type and load the necessary kernel module automatically. However, if the file system is needed at early boot (in the initial ramdisk) and is not ext2 , ext3 or ext4 , then it’s best to specify fsType to ensure that the kernel module is available. Note: System startup will fail if any of the filesystems fails to mount, dropping you to the emergency shell. You can make a mount asynchronous and non-critical by adding options = [ "nofail" ]; . System startup will fail if any of the filesystems fails to mount, dropping you to the emergency shell. You can make a mount asynchronous and non-critical by adding 8.1. LUKS-Encrypted File Systems NixOS supports file systems that are encrypted using LUKS (Linux Unified Key Setup). For example, here is how you create an encrypted Ext4 file system on the device /dev/disk/by-uuid/3f6b0024-3a44-4fde-a43a-767b872abe5d : # cryptsetup luksFormat /dev/disk/by-uuid/3f6b0024-3a44-4fde-a43a-767b872abe5d WARNING! ======== This will overwrite data on /dev/disk/by-uuid/3f6b0024-3a44-4fde-a43a-767b872abe5d irrevocably. Are you sure? (Type uppercase yes): YES Enter LUKS passphrase: *** Verify passphrase: *** # cryptsetup luksOpen /dev/disk/by-uuid/3f6b0024-3a44-4fde-a43a-767b872abe5d crypted Enter passphrase for /dev/disk/by-uuid/3f6b0024-3a44-4fde-a43a-767b872abe5d: *** # mkfs.ext4 /dev/mapper/crypted To ensure that this file system is automatically mounted at boot time as / , add the following to configuration.nix : boot.initrd.luks.devices.crypted.device = "/dev/disk/by-uuid/3f6b0024-3a44-4fde-a43a-767b872abe5d"; fileSystems ."/".device = "/dev/mapper/crypted"; Should grub be used as bootloader, and /boot is located on an encrypted partition, it is necessary to add the following grub option: boot.loader.grub.enableCryptodisk = true; 8.1.1. FIDO2 NixOS also supports unlocking your LUKS-Encrypted file system using a FIDO2 compatible token. In the following example, we will create a new FIDO2 credential and add it as a new key to our existing device /dev/sda2 : # export FIDO2_LABEL="/dev/sda2 @ $HOSTNAME" # fido2luks credential "$FIDO2_LABEL" f1d00200108b9d6e849a8b388da457688e3dd653b4e53770012d8f28e5d3b269865038c346802f36f3da7278b13ad6a3bb6a1452e24ebeeaa24ba40eef559b1b287d2a2f80b7 # fido2luks -i add-key /dev/sda2 f1d00200108b9d6e849a8b388da457688e3dd653b4e53770012d8f28e5d3b269865038c346802f36f3da7278b13ad6a3bb6a1452e24ebeeaa24ba40eef559b1b287d2a2f80b7 Password: Password (again): Old password: Old password (again): Added to key to device /dev/sda2, slot: 2 To ensure that this file system is decrypted using the FIDO2 compatible key, add the following to configuration.nix : boot.initrd.luks.fido2Support = true; boot.initrd.luks.devices."/dev/sda2".fido2.credential = "f1d00200108b9d6e849a8b388da457688e3dd653b4e53770012d8f28e5d3b269865038c346802f36f3da7278b13ad6a3bb6a1452e24ebeeaa24ba40eef559b1b287d2a2f80b7"; You can also use the FIDO2 passwordless setup, but for security reasons, you might want to enable it only when your device is PIN protected, such as Trezor. boot.initrd.luks.devices."/dev/sda2".fido2.passwordLess = true;

Chapter 9. X Window System The X Window System (X11) provides the basis of NixOS’ graphical user interface. It can be enabled as follows: services.xserver.enable = true; The X server will automatically detect and use the appropriate video driver from a set of X.org drivers (such as vesa and intel ). You can also specify a driver manually, e.g. services.xserver.videoDrivers = [ "r128" ]; to enable X.org’s xf86-video-r128 driver. You also need to enable at least one desktop or window manager. Otherwise, you can only log into a plain undecorated xterm window. Thus you should pick one or more of the following lines: services.xserver.desktopManager.plasma5.enable = true; services.xserver.desktopManager.xfce.enable = true; services.xserver.desktopManager.gnome3.enable = true; services.xserver.desktopManager.mate.enable = true; services.xserver.windowManager.xmonad.enable = true; services.xserver.windowManager.twm.enable = true; services.xserver.windowManager.icewm.enable = true; services.xserver.windowManager.i3.enable = true; NixOS’s default display manager (the program that provides a graphical login prompt and manages the X server) is LightDM. You can select an alternative one by picking one of the following lines: services.xserver.displayManager.sddm.enable = true; services.xserver.displayManager.gdm.enable = true; You can set the keyboard layout (and optionally the layout variant): services.xserver.layout = "de"; services.xserver.xkbVariant = "neo"; The X server is started automatically at boot time. If you don’t want this to happen, you can set: services.xserver.autorun = false; The X server can then be started manually: # systemctl start display-manager.service On 64-bit systems, if you want OpenGL for 32-bit programs such as in Wine, you should also set the following: hardware.opengl.driSupport32Bit = true; Auto-login The x11 login screen can be skipped entirely, automatically logging you into your window manager and desktop environment when you boot your computer. This is especially helpful if you have disk encryption enabled. Since you already have to provide a password to decrypt your disk, entering a second password to login can be redundant. To enable auto-login, you need to define your default window manager and desktop environment. If you wanted no desktop environment and i3 as your your window manager, you'd define: services.xserver.displayManager.defaultSession = "none+i3"; Every display manager in NixOS supports auto-login, here is an example using lightdm for a user alice : services.xserver.displayManager.lightdm.enable = true; services.xserver.displayManager.lightdm.autoLogin.enable = true; services.xserver.displayManager.lightdm.autoLogin.user = "alice"; The options are named identically for all other display managers. Proprietary NVIDIA drivers NVIDIA provides a proprietary driver for its graphics cards that has better 3D performance than the X.org drivers. It is not enabled by default because it’s not free software. You can enable it as follows: services.xserver.videoDrivers = [ "nvidia" ]; Or if you have an older card, you may have to use one of the legacy drivers: services.xserver.videoDrivers = [ "nvidiaLegacy390" ]; services.xserver.videoDrivers = [ "nvidiaLegacy340" ]; services.xserver.videoDrivers = [ "nvidiaLegacy304" ]; services.xserver.videoDrivers = [ "nvidiaLegacy173" ]; You may need to reboot after enabling this driver to prevent a clash with other kernel modules. Proprietary AMD drivers AMD provides a proprietary driver for its graphics cards that has better 3D performance than the X.org drivers. It is not enabled by default because it’s not free software. You can enable it as follows: services.xserver.videoDrivers = [ "ati_unfree" ]; You will need to reboot after enabling this driver to prevent a clash with other kernel modules. Note: For recent AMD GPUs you most likely want to keep either the defaults or "amdgpu" (both free). Touchpads Support for Synaptics touchpads (found in many laptops such as the Dell Latitude series) can be enabled as follows: services.xserver.libinput.enable = true; The driver has many options (see Appendix A, Configuration Options). For instance, the following disables tap-to-click behavior: services.xserver.libinput.tapping = false; Note: the use of services.xserver.synaptics is deprecated since NixOS 17.09. GTK/Qt themes GTK themes can be installed either to user profile or system-wide (via environment.systemPackages ). To make Qt 5 applications look similar to GTK2 ones, you can install qt5.qtbase.gtk package into your system environment. It should work for all Qt 5 library versions. Custom XKB layouts It is possible to install custom XKB keyboard layouts using the option services.xserver.extraLayouts . As a first example, we are going to create a layout based on the basic US layout, with an additional layer to type some greek symbols by pressing the right-alt key. To do this we are going to create a us-greek file with a xkb_symbols section. xkb_symbols "us-greek" { include "us(basic)" // includes the base US keys include "level3(ralt_switch)" // configures right alt as a third level switch key <LatA> { [ a, A, Greek_alpha ] }; key <LatB> { [ b, B, Greek_beta ] }; key <LatG> { [ g, G, Greek_gamma ] }; key <LatD> { [ d, D, Greek_delta ] }; key <LatZ> { [ z, Z, Greek_zeta ] }; }; To install the layout, the filepath, a description and the list of languages must be given: services.xserver.extraLayouts .us-greek = { description = "US layout with alt-gr greek"; languages = [ "eng" ]; symbolsFile = /path/to/us-greek; } Note: The name should match the one given to the xkb_symbols block. The layout should now be installed and ready to use: try it by running setxkbmap us-greek and type <alt>+a . To change the default the usual services.xserver.layout option can still be used. A layout can have several other components besides xkb_symbols , for example we will define new keycodes for some multimedia key and bind these to some symbol. Use the xev utility from pkgs.xorg.xev to find the codes of the keys of interest, then create a media-key file to hold the keycodes definitions xkb_keycodes "media" { <volUp> = 123; <volDown> = 456; } Now use the newly define keycodes in media-sym : xkb_symbols "media" { key.type = "ONE_LEVEL"; key <volUp> { [ XF86AudioLowerVolume ] }; key <volDown> { [ XF86AudioRaiseVolume ] }; } As before, to install the layout do services.xserver.extraLayouts .media = { description = "Multimedia keys remapping"; languages = [ "eng" ]; symbolsFile = /path/to/media-key; keycodesFile = /path/to/media-sym; }; Note: The function pkgs.writeText <filename> <content> can be useful if you prefer to keep the layout definitions inside the NixOS configuration. Unfortunately, the Xorg server does not (currently) support setting a keymap directly but relies instead on XKB rules to select the matching components (keycodes, types, ...) of a layout. This means that components other than symbols won't be loaded by default. As a workaround, you can set the keymap using setxkbmap at the start of the session with: services.xserver.displayManager.sessionCommands = "setxkbmap -keycodes media"; If you are manually starting the X server, you should set the argument -xkbdir /etc/X11/xkb , otherwise X won't find your layout files. For example with xinit run $ xinit -- -xkbdir /etc/X11/xkb To learn how to write layouts take a look at the XKB documentation . More example layouts can also be found here .

Chapter 10. Xfce Desktop Environment To enable the Xfce Desktop Environment, set services.xserver.desktopManager.xfce.enable = true; services.xserver.displayManager.defaultSession = "xfce"; Optionally, picom can be enabled for nice graphical effects, some example settings: services.picom = { enable = true; fade = true; inactiveOpacity = "0.9"; shadow = true; fadeDelta = 4; }; Some Xfce programs are not installed automatically. To install them manually (system wide), put them into your environment.systemPackages from pkgs.xfce . Thunar Plugins If you'd like to add extra plugins to Thunar, add them to services.xserver.desktopManager.xfce.thunarPlugins . You shouldn't just add them to environment.systemPackages . Troubleshooting Even after enabling udisks2, volume management might not work. Thunar and/or the desktop takes time to show up. Thunar will spit out this kind of message on start (look at journalctl --user -b). Thunar:2410): GVFS-RemoteVolumeMonitor-WARNING **: remote volume monitor with dbus name org.gtk.Private.UDisks2VolumeMonitor is not supported This is caused by some needed GNOME services not running. This is all fixed by enabling "Launch GNOME services on startup" in the Advanced tab of the Session and Startup settings panel. Alternatively, you can run this command to do the same thing. $ xfconf-query -c xfce4-session -p /compat/LaunchGNOME -s true A log-out and re-log will be needed for this to take effect.

Chapter 11. Networking Table of Contents 11.1. NetworkManager 11.2. Secure Shell Access 11.3. IPv4 Configuration 11.4. IPv6 Configuration 11.5. Firewall 11.6. Wireless Networks 11.7. Ad-Hoc Configuration This section describes how to configure networking components on your NixOS machine. 11.1. NetworkManager To facilitate network configuration, some desktop environments use NetworkManager. You can enable NetworkManager by setting: networking.networkmanager.enable = true; some desktop managers (e.g., GNOME) enable NetworkManager automatically for you. All users that should have permission to change network settings must belong to the networkmanager group: users.users.alice.extraGroups = [ "networkmanager" ]; NetworkManager is controlled using either nmcli or nmtui (curses-based terminal user interface). See their manual pages for details on their usage. Some desktop environments (GNOME, KDE) have their own configuration tools for NetworkManager. On XFCE, there is no configuration tool for NetworkManager by default: by enabling programs.nm-applet.enable , the graphical applet will be installed and will launch automatically when the graphical session is started. Note networking.networkmanager and networking.wireless (WPA Supplicant) can be used together if desired. To do this you need to instruct NetworkManager to ignore those interfaces like: networking.networkmanager.unmanaged = [ "*" "except:type:wwan" "except:type:gsm" ]; Refer to the option description for the exact syntax and references to external documentation. 11.2. Secure Shell Access Secure shell (SSH) access to your machine can be enabled by setting: services.openssh.enable = true; By default, root logins using a password are disallowed. They can be disabled entirely by setting services.openssh.permitRootLogin to "no" . You can declaratively specify authorised RSA/DSA public keys for a user as follows: users.users.alice.openssh.authorizedKeys.keys = [ "ssh-dss AAAAB3NzaC1kc3MAAACBAPIkGWVEt4..." ]; 11.3. IPv4 Configuration By default, NixOS uses DHCP (specifically, dhcpcd) to automatically configure network interfaces. However, you can configure an interface manually as follows: networking.interfaces.eth0.ipv4.addresses = [ { address = "192.168.1.2"; prefixLength = 24; } ]; Typically you’ll also want to set a default gateway and set of name servers: networking.defaultGateway = "192.168.1.1"; networking.nameservers = [ "8.8.8.8" ]; Note: Statically configured interfaces are set up by the systemd service interface-name -cfg.service . The default gateway and name server configuration is performed by network-setup.service . The host name is set using networking.hostName : networking.hostName = "cartman"; The default host name is nixos . Set it to the empty string ( "" ) to allow the DHCP server to provide the host name. 11.4. IPv6 Configuration IPv6 is enabled by default. Stateless address autoconfiguration is used to automatically assign IPv6 addresses to all interfaces. You can disable IPv6 support globally by setting: networking.enableIPv6 = false; You can disable IPv6 on a single interface using a normal sysctl (in this example, we use interface eth0 ): boot.kernel.sysctl ."net.ipv6.conf.eth0.disable_ipv6" = true; As with IPv4 networking interfaces are automatically configured via DHCPv6. You can configure an interface manually: networking.interfaces.eth0.ipv6.addresses = [ { address = "fe00:aa:bb:cc::2"; prefixLength = 64; } ]; For configuring a gateway, optionally with explicitly specified interface: networking.defaultGateway6 = { address = "fe00::1"; interface = "enp0s3"; }; See Section 11.3, “IPv4 Configuration” for similar examples and additional information. 11.5. Firewall NixOS has a simple stateful firewall that blocks incoming connections and other unexpected packets. The firewall applies to both IPv4 and IPv6 traffic. It is enabled by default. It can be disabled as follows: networking.firewall.enable = false; If the firewall is enabled, you can open specific TCP ports to the outside world: networking.firewall.allowedTCPPorts = [ 80 443 ]; Note that TCP port 22 (ssh) is opened automatically if the SSH daemon is enabled ( services.openssh.enable = true ). UDP ports can be opened through networking.firewall.allowedUDPPorts . To open ranges of TCP ports: networking.firewall.allowedTCPPortRanges = [ { from = 4000; to = 4007; } { from = 8000; to = 8010; } ]; Similarly, UDP port ranges can be opened through networking.firewall.allowedUDPPortRanges . 11.6. Wireless Networks For a desktop installation using NetworkManager (e.g., GNOME), you just have to make sure the user is in the networkmanager group and you can skip the rest of this section on wireless networks. NixOS will start wpa_supplicant for you if you enable this setting: networking.wireless.enable = true; NixOS lets you specify networks for wpa_supplicant declaratively: networking.wireless.networks = { echelon = { # SSID with no spaces or special characters psk = "abcdefgh"; }; "echelon's AP" = { # SSID with spaces and/or special characters psk = "ijklmnop"; }; echelon = { # Hidden SSID hidden = true; psk = "qrstuvwx"; }; free.wifi = {}; # Public wireless network }; Be aware that keys will be written to the nix store in plaintext! When no networks are set, it will default to using a configuration file at /etc/wpa_supplicant.conf . You should edit this file yourself to define wireless networks, WPA keys and so on (see wpa_supplicant.conf(5)). If you are using WPA2 you can generate pskRaw key using wpa_passphrase: $ wpa_passphrase ESSID PSK network={ ssid="echelon" #psk="abcdefgh" psk=dca6d6ed41f4ab5a984c9f55f6f66d4efdc720ebf66959810f4329bb391c5435 } networking.wireless.networks = { echelon = { pskRaw = "dca6d6ed41f4ab5a984c9f55f6f66d4efdc720ebf66959810f4329bb391c5435"; }; } or you can use it to directly generate the wpa_supplicant.conf : # wpa_passphrase ESSID PSK > /etc/wpa_supplicant.conf After you have edited the wpa_supplicant.conf , you need to restart the wpa_supplicant service. # systemctl restart wpa_supplicant.service 11.7. Ad-Hoc Configuration You can use networking.localCommands to specify shell commands to be run at the end of network-setup.service . This is useful for doing network configuration not covered by the existing NixOS modules. For instance, to statically configure an IPv6 address: networking.localCommands = '' ip -6 addr add 2001:610:685:1::1/64 dev eth0 '';

Chapter 12. Linux Kernel Table of Contents 12.1. Customize your kernel 12.2. Developing kernel modules You can override the Linux kernel and associated packages using the option boot.kernelPackages . For instance, this selects the Linux 3.10 kernel: boot.kernelPackages = pkgs.linuxPackages_3_10; Note that this not only replaces the kernel, but also packages that are specific to the kernel version, such as the NVIDIA video drivers. This ensures that driver packages are consistent with the kernel. The default Linux kernel configuration should be fine for most users. You can see the configuration of your current kernel with the following command: zcat /proc/config.gz If you want to change the kernel configuration, you can use the packageOverrides feature (see Section 6.1.1, “Customising Packages”). For instance, to enable support for the kernel debugger KGDB: nixpkgs.config.packageOverrides = pkgs: { linux_3_4 = pkgs.linux_3_4.override { extraConfig = '' KGDB y ''; }; }; extraConfig takes a list of Linux kernel configuration options, one per line. The name of the option should not include the prefix CONFIG_ . The option value is typically y , n or m (to build something as a kernel module). Kernel modules for hardware devices are generally loaded automatically by udev. You can force a module to be loaded via boot.kernelModules , e.g. boot.kernelModules = [ "fuse" "kvm-intel" "coretemp" ]; If the module is required early during the boot (e.g. to mount the root file system), you can use boot.initrd.kernelModules : boot.initrd.kernelModules = [ "cifs" ]; This causes the specified modules and their dependencies to be added to the initial ramdisk. Kernel runtime parameters can be set through boot.kernel.sysctl , e.g. boot.kernel.sysctl ."net.ipv4.tcp_keepalive_time" = 120; sets the kernel’s TCP keepalive time to 120 seconds. To see the available parameters, run sysctl -a. 12.1. Customize your kernel The first step before compiling the kernel is to generate an appropriate .config configuration. Either you pass your own config via the configfile setting of linuxManualConfig : custom-kernel = super.linuxManualConfig { inherit (super) stdenv hostPlatform; inherit (linux_4_9) src; version = "${linux_4_9.version}-custom"; configfile = /home/me/my_kernel_config; allowImportFromDerivation = true; }; You can edit the config with this snippet (by default make menuconfig won't work out of the box on nixos): nix-shell -E 'with import <nixpkgs> {}; kernelToOverride.overrideAttrs (o: {nativeBuildInputs=o.nativeBuildInputs ++ [ pkgconfig ncurses ];})' or you can let nixpkgs generate the configuration. Nixpkgs generates it via answering the interactive kernel utility make config. The answers depend on parameters passed to pkgs/os-specific/linux/kernel/generic.nix (which you can influence by overriding extraConfig, autoModules, modDirVersion, preferBuiltin, extraConfig ). mptcp93.override ({ name="mptcp-local"; ignoreConfigErrors = true; autoModules = false; kernelPreferBuiltin = true; enableParallelBuilding = true; extraConfig = '' DEBUG_KERNEL y FRAME_POINTER y KGDB y KGDB_SERIAL_CONSOLE y DEBUG_INFO y ''; }); 12.2. Developing kernel modules When developing kernel modules it's often convenient to run edit-compile-run loop as quickly as possible. See below snippet as an example of developing mellanox drivers. $ nix-build '<nixpkgs>' -A linuxPackages.kernel.dev $ nix-shell '<nixpkgs>' -A linuxPackages.kernel $ unpackPhase $ cd linux-* $ make -C $dev/lib/modules/*/build M=$(pwd)/drivers/net/ethernet/mellanox modules # insmod ./drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.ko

Chapter 13. Pantheon Desktop Table of Contents 13.1. Enabling Pantheon 13.2. Wingpanel and Switchboard plugins 13.3. FAQ Pantheon is the desktop environment created for the elementary OS distribution. It is written from scratch in Vala, utilizing GNOME technologies with GTK 3 and Granite. 13.1. Enabling Pantheon All of Pantheon is working in NixOS and the applications should be available, aside from a few exceptions. To enable Pantheon, set services.xserver.desktopManager.pantheon.enable = true; This automatically enables LightDM and Pantheon's LightDM greeter. If you'd like to disable this, set services.xserver.displayManager.lightdm.greeters.pantheon.enable = false; services.xserver.displayManager.lightdm.enable = false; but please be aware using Pantheon without LightDM as a display manager will break screenlocking from the UI. The NixOS module for Pantheon installs all of Pantheon's default applications. If you'd like to not install Pantheon's apps, set services.pantheon.apps.enable = false; You can also use environment.pantheon.excludePackages to remove any other app (like geary). 13.2. Wingpanel and Switchboard plugins Wingpanel and Switchboard work differently than they do in other distributions, as far as using plugins. You cannot install a plugin globally (like with environment.systemPackages ) to start using it. You should instead be using the following options: services.xserver.desktopManager.pantheon.extraWingpanelIndicators

services.xserver.desktopManager.pantheon.extraSwitchboardPlugs to configure the programs with plugs or indicators. The difference in NixOS is both these programs are patched to load plugins from a directory that is the value of an environment variable. All of which is controlled in Nix. If you need to configure the particular packages manually you can override the packages like: wingpanel-with-indicators.override { indicators = [ pkgs.some-special-indicator ]; }; switchboard-with-plugs.override { plugs = [ pkgs.some-special-plug ]; }; please note that, like how the NixOS options describe these as extra plugins, this would only add to the default plugins included with the programs. If for some reason you'd like to configure which plugins to use exactly, both packages have an argument for this: wingpanel-with-indicators.override { useDefaultIndicators = false; indicators = specialListOfIndicators; }; switchboard-with-plugs.override { useDefaultPlugs = false; plugs = specialListOfPlugs; }; this could be most useful for testing a particular plug-in in isolation. 13.3. FAQ I have switched from a different desktop and Pantheon’s theming looks messed up. Open Switchboard and go to: Administration → About → Restore Default Settings → Restore Settings. This will reset any dconf settings to their Pantheon defaults. Note this could reset certain GNOME specific preferences if that desktop was used prior. I cannot enable both GNOME 3 and Pantheon. This is a known issue and there is no known workaround. Does AppCenter work, or is it available? AppCenter has been available since 20.03, but it is of little use. This is because there is no functioning PackageKit backend for Nix 2.0. In the near future you will be able to install Flatpak applications from AppCenter on NixOS. See this issue.

Chapter 14. Matomo Table of Contents 14.1. Database Setup 14.2. Archive Processing 14.3. Backup 14.4. Issues 14.5. Using other Web Servers than nginx Matomo is a real-time web analytics application. This module configures php-fpm as backend for Matomo, optionally configuring an nginx vhost as well. An automatic setup is not suported by Matomo, so you need to configure Matomo itself in the browser-based Matomo setup. 14.1. Database Setup You also need to configure a MariaDB or MySQL database and -user for Matomo yourself, and enter those credentials in your browser. You can use passwordless database authentication via the UNIX_SOCKET authentication plugin with the following SQL commands: # For MariaDB INSTALL PLUGIN unix_socket SONAME 'auth_socket'; CREATE DATABASE matomo; CREATE USER 'matomo'@'localhost' IDENTIFIED WITH unix_socket; GRANT ALL PRIVILEGES ON matomo.* TO 'matomo'@'localhost'; # For MySQL INSTALL PLUGIN auth_socket SONAME 'auth_socket.so'; CREATE DATABASE matomo; CREATE USER 'matomo'@'localhost' IDENTIFIED WITH auth_socket; GRANT ALL PRIVILEGES ON matomo.* TO 'matomo'@'localhost'; Then fill in matomo as database user and database name, and leave the password field blank. This authentication works by allowing only the matomo unix user to authenticate as the matomo database user (without needing a password), but no other users. For more information on passwordless login, see https://mariadb.com/kb/en/mariadb/unix_socket-authentication-plugin/. Of course, you can use password based authentication as well, e.g. when the database is not on the same host. 14.2. Archive Processing This module comes with the systemd service matomo-archive-processing.service and a timer that automatically triggers archive processing every hour. This means that you can safely disable browser triggers for Matomo archiving at Administration > System > General Settings . With automatic archive processing, you can now also enable to delete old visitor logs at Administration > System > Privacy , but make sure that you run systemctl start matomo-archive-processing.service at least once without errors if you have already collected data before, so that the reports get archived before the source data gets deleted. 14.3. Backup You only need to take backups of your MySQL database and the /var/lib/matomo/config/config.ini.php file. Use a user in the matomo group or root to access the file. For more information, see https://matomo.org/faq/how-to-install/faq_138/. 14.4. Issues Matomo will warn you that the JavaScript tracker is not writable. This is because it's located in the read-only nix store. You can safely ignore this, unless you need a plugin that needs JavaScript tracker access. 14.5. Using other Web Servers than nginx You can use other web servers by forwarding calls for index.php and piwik.php to the services.phpfpm.pools.<name>.socket fastcgi unix socket. You can use the nginx configuration in the module code as a reference to what else should be configured.

Chapter 15. Nextcloud Table of Contents 15.1. Basic usage 15.2. Pitfalls 15.3. Maintainer information Nextcloud is an open-source, self-hostable cloud platform. The server setup can be automated using services.nextcloud. A desktop client is packaged at pkgs.nextcloud-client . 15.1. Basic usage Nextcloud is a PHP-based application which requires an HTTP server ( services.nextcloud optionally supports services.nginx ) and a database (it's recommended to use services.postgresql ). A very basic configuration may look like this: { pkgs, ... }: { services.nextcloud = { enable = true; hostName = "nextcloud.tld"; nginx.enable = true; config = { dbtype = "pgsql"; dbuser = "nextcloud"; dbhost = "/run/postgresql"; # nextcloud will add /.s.PGSQL.5432 by itself dbname = "nextcloud"; adminpassFile = "/path/to/admin-pass-file"; adminuser = "root"; }; }; services.postgresql = { enable = true; ensureDatabases = [ "nextcloud" ]; ensureUsers = [ { name = "nextcloud"; ensurePermissions."DATABASE nextcloud" = "ALL PRIVILEGES"; } ]; }; # ensure that postgres is running *before* running the setup systemd.services."nextcloud-setup" = { requires = ["postgresql.service"]; after = ["postgresql.service"]; }; networking.firewall.allowedTCPPorts = [ 80 443 ]; } The options hostName and nginx.enable are used internally to configure an HTTP server using PHP-FPM and nginx . The config attribute set is used by the imperative installer and all values are written to an additional file to ensure that changes can be applied by changing the module's options. In case the application serves multiple domains (those are checked with $_SERVER['HTTP_HOST'] ) it's needed to add them to services.nextcloud.config.extraTrustedDomains . Auto updates for Nextcloud apps can be enabled using services.nextcloud.autoUpdateApps . 15.2. Pitfalls Unfortunately Nextcloud appears to be very stateful when it comes to managing its own configuration. The config file lives in the home directory of the nextcloud user (by default /var/lib/nextcloud/config/config.php ) and is also used to track several states of the application (e.g. whether installed or not). All configuration parameters are also stored in /var/lib/nextcloud/config/override.config.php which is generated by the module and linked from the store to ensure that all values from config.php can be modified by the module. However config.php manages the application's state and shouldn't be touched manually because of that. Warning: Don't delete config.php ! This file tracks the application's state and a deletion can cause unwanted side-effects! Warning: Don't rerun nextcloud-occ maintenance:install ! This command tries to install the application and can cause unwanted side-effects! Nextcloud doesn't allow to move more than one major-version forward. If you're e.g. on v16 , you cannot upgrade to v18 , you need to upgrade to v17 first. This is ensured automatically as long as the stateVersion is declared properly. In that case the oldest version available (one major behind the one from the previous NixOS release) will be selected by default and the module will generate a warning that reminds the user to upgrade to latest Nextcloud after that deploy. 15.3. Maintainer information As stated in the previous paragraph, we must provide a clean upgrade-path for Nextcloud since it cannot move more than one major version forward on a single upgrade. This chapter adds some notes how Nextcloud updates should be rolled out in the future. While minor and patch-level updates are no problem and can be done directly in the package-expression (and should be backported to supported stable branches after that), major-releases should be added in a new attribute (e.g. Nextcloud v19.0.0 should be available in nixpkgs as pkgs.nextcloud19 ). To provide simple upgrade paths it's generally useful to backport those as well to stable branches. As long as the package-default isn't altered, this won't break existing setups. After that, the versioning-warning in the nextcloud -module should be updated to make sure that the package-option selects the latest version on fresh setups. If major-releases will be abandoned by upstream, we should check first if those are needed in NixOS for a safe upgrade-path before removing those. In that case we shold keep those packages, but mark them as insecure in an expression like this (in <nixpkgs/pkgs/servers/nextcloud/default.nix> ): /* ... */ { nextcloud17 = generic { version = "17.0.x"; sha256 = "0000000000000000000000000000000000000000000000000000"; insecure = true; }; }

Chapter 16. Grocy Table of Contents 16.1. Basic usage 16.2. Settings Grocy is a web-based self-hosted groceries & household management solution for your home. 16.1. Basic usage A very basic configuration may look like this: { pkgs, ... }: { services.grocy = { enable = true; hostName = "grocy.tld"; }; } This configures a simple vhost using nginx which listens to grocy.tld with fully configured ACME/LE (this can be disabled by setting services.grocy.nginx.enableSSL to false ). After the initial setup the credentials admin:admin can be used to login. The application's state is persisted at /var/lib/grocy/grocy.db in a sqlite3 database. The migration is applied when requesting the / -route of the application. 16.2. Settings The configuration for grocy is located at /etc/grocy/config.php . By default, the following settings can be defined in the NixOS-configuration: { pkgs, ... }: { services.grocy.settings = { # The default currency in the system for invoices etc. # Please note that exchange rates aren't taken into account, this # is just the setting for what's shown in the frontend. currency = "EUR"; # The display language (and locale configuration) for grocy. culture = "de"; calendar = { # Whether or not to show the week-numbers # in the calendar. showWeekNumber = true; # Index of the first day to be shown in the calendar (0=Sunday, 1=Monday, # 2=Tuesday and so on). firstDayOfWeek = 2; }; }; } If you want to alter the configuration file on your own, you can do this manually with an expression like this: { lib, ... }: { environment.etc."grocy/config.php".text = lib.mkAfter '' // Arbitrary PHP code in grocy's configuration file ''; }

Chapter 17. Prometheus exporters Table of Contents 17.1. Configuration 17.2. Adding a new exporter 17.3. Updating an exporter module Prometheus exporters provide metrics for the prometheus monitoring system. 17.1. Configuration One of the most common exporters is the node exporter, it provides hardware and OS metrics from the host it's running on. The exporter could be configured as follows: services.prometheus.exporters.node = { enable = true; enabledCollectors = [ "logind" "systemd" ]; disabledCollectors = [ "textfile" ]; openFirewall = true; firewallFilter = "-i br0 -p tcp -m tcp --dport 9100"; }; It should now serve all metrics from the collectors that are explicitly enabled and the ones that are enabled by default, via http under /metrics . In this example the firewall should just allow incoming connections to the exporter's port on the bridge interface br0 (this would have to be configured seperately of course). For more information about configuration see man configuration.nix or search through the available options. 17.2. Adding a new exporter To add a new exporter, it has to be packaged first (see nixpkgs/pkgs/servers/monitoring/prometheus/ for examples), then a module can be added. The postfix exporter is used in this example: Some default options for all exporters are provided by nixpkgs/nixos/modules/services/monitoring/prometheus/exporters.nix :

enable port listenAddress extraFlags openFirewall firewallFilter user group

As there is already a package available, the module can now be added. This is accomplished by adding a new file to the nixos/modules/services/monitoring/prometheus/exporters/ directory, which will be called postfix.nix and contains all exporter specific options and configuration: # nixpgs/nixos/modules/services/prometheus/exporters/postfix.nix { config, lib, pkgs, options }: with lib; let # for convenience we define cfg here cfg = config.services.prometheus.exporters.postfix; in { port = 9154; # The postfix exporter listens on this port by default # `extraOpts` is an attribute set which contains additional options # (and optional overrides for default options). # Note that this attribute is optional. extraOpts = { telemetryPath = mkOption { type = types.str; default = "/metrics"; description = '' Path under which to expose metrics. ''; }; logfilePath = mkOption { type = types.path; default = /var/log/postfix_exporter_input.log; example = /var/log/mail.log; description = '' Path where Postfix writes log entries. This file will be truncated by this exporter! ''; }; showqPath = mkOption { type = types.path; default = /var/spool/postfix/public/showq; example = /var/lib/postfix/queue/public/showq; description = '' Path at which Postfix places its showq socket. ''; }; }; # `serviceOpts` is an attribute set which contains configuration # for the exporter's systemd service. One of # `serviceOpts.script` and `serviceOpts.serviceConfig.ExecStart` # has to be specified here. This will be merged with the default # service confiuration. # Note that by default 'DynamicUser' is 'true'. serviceOpts = { serviceConfig = { DynamicUser = false; ExecStart = '' ${pkgs.prometheus-postfix-exporter}/bin/postfix_exporter \ --web.listen-address ${cfg.listenAddress}:${toString cfg.port} \ --web.telemetry-path ${cfg.telemetryPath} \ ${concatStringsSep " \\

" cfg.extraFlags} ''; }; }; }

This should already be enough for the postfix exporter. Additionally one could now add assertions and conditional default values. This can be done in the 'meta-module' that combines all exporter definitions and generates the submodules: nixpkgs/nixos/modules/services/prometheus/exporters.nix Should an exporter option change at some point, it is possible to add information about the change to the exporter definition similar to nixpkgs/nixos/modules/rename.nix : { config, lib, pkgs, options }: with lib; let cfg = config.services.prometheus.exporters.nginx; in { port = 9113; extraOpts = { # additional module options # ... }; serviceOpts = { # service configuration # ... }; imports = [ # 'services.prometheus.exporters.nginx.telemetryEndpoint' -> 'services.prometheus.exporters.nginx.telemetryPath' (mkRenamedOptionModule [ "telemetryEndpoint" ] [ "telemetryPath" ]) # removed option 'services.prometheus.exporters.nginx.insecure' (mkRemovedOptionModule [ "insecure" ] '' This option was replaced by 'prometheus.exporters.nginx.sslVerify' which defaults to true. '') ({ options.warnings = options.warnings; }) ]; }

Chapter 18. WeeChat Table of Contents 18.1. Basic Usage 18.2. Re-attaching to WeeChat WeeChat is a fast and extensible IRC client. 18.1. Basic Usage By default, the module creates a systemd unit which runs the chat client in a detached screen session. This can be done by enabling the weechat service: { ... }: { services.weechat.enable = true; } The service is managed by a dedicated user named weechat in the state directory /var/lib/weechat . 18.2. Re-attaching to WeeChat WeeChat runs in a screen session owned by a dedicated user. To explicitly allow your another user to attach to this session, the screenrc needs to be tweaked by adding multiuser support: { programs.screen.screenrc = '' multiuser on acladd normal_user ''; } Now, the session can be re-attached like this: screen -x weechat/weechat-screen The session name can be changed using services.weechat.sessionName.

Chapter 19. Taskserver Table of Contents 19.1. Configuration 19.2. The nixos-taskserver tool 19.3. Declarative/automatic CA management 19.4. Manual CA management Taskserver is the server component of Taskwarrior, a free and open source todo list application. Upstream documentation: https://taskwarrior.org/docs/#taskd 19.1. Configuration Taskserver does all of its authentication via TLS using client certificates, so you either need to roll your own CA or purchase a certificate from a known CA, which allows creation of client certificates. These certificates are usually advertised as “server certificates”. So in order to make it easier to handle your own CA, there is a helper tool called nixos-taskserver which manages the custom CA along with Taskserver organisations, users and groups. While the client certificates in Taskserver only authenticate whether a user is allowed to connect, every user has its own UUID which identifies it as an entity. With nixos-taskserver the client certificate is created along with the UUID of the user, so it handles all of the credentials needed in order to setup the Taskwarrior client to work with a Taskserver. 19.2. The nixos-taskserver tool Because Taskserver by default only provides scripts to setup users imperatively, the nixos-taskserver tool is used for addition and deletion of organisations along with users and groups defined by services.taskserver.organisations and as well for imperative set up. The tool is designed to not interfere if the command is used to manually set up some organisations, users or groups. For example if you add a new organisation using nixos-taskserver org add foo, the organisation is not modified and deleted no matter what you define in services.taskserver.organisations , even if you're adding the same organisation in that option. The tool is modelled to imitate the official taskd command, documentation for each subcommand can be shown by using the --help switch. 19.3. Declarative/automatic CA management Everything is done according to what you specify in the module options, however in order to set up a Taskwarrior client for synchronisation with a Taskserver instance, you have to transfer the keys and certificates to the client machine. This is done using nixos-taskserver user export $orgname $username which is printing a shell script fragment to stdout which can either be used verbatim or adjusted to import the user on the client machine. For example, let's say you have the following configuration: { services.taskserver.enable = true; services.taskserver.fqdn = "server"; services.taskserver.listenHost = "::"; services.taskserver.organisations.my-company.users = [ "alice" ]; } This creates an organisation called my-company with the user alice . Now in order to import the alice user to another machine alicebox , all we need to do is something like this: $ ssh server nixos-taskserver user export my-company alice | sh Of course, if no SSH daemon is available on the server you can also copy & paste it directly into a shell. After this step the user should be set up and you can start synchronising your tasks for the first time with task sync init on alicebox . Subsequent synchronisation requests merely require the command task sync after that stage. 19.4. Manual CA management If you set any options within service.taskserver.pki.manual.*, nixos-taskserver won't issue certificates, but you can still use it for adding or removing user accounts.

Chapter 21. Gitlab Table of Contents 21.1. Prerequisites 21.2. Configuring 21.3. Maintenance Gitlab is a feature-rich git hosting service. 21.1. Prerequisites The gitlab service exposes only an Unix socket at /run/gitlab/gitlab-workhorse.socket . You need to configure a webserver to proxy HTTP requests to the socket. For instance, the following configuration could be used to use nginx as frontend proxy: services.nginx = { enable = true; recommendedGzipSettings = true; recommendedOptimisation = true; recommendedProxySettings = true; recommendedTlsSettings = true; virtualHosts."git.example.com" = { enableACME = true; forceSSL = true; locations."/".proxyPass = "http://unix:/run/gitlab/gitlab-workhorse.socket"; }; }; 21.2. Configuring Gitlab depends on both PostgreSQL and Redis and will automatically enable both services. In the case of PostgreSQL, a database and a role will be created. The default state dir is /var/gitlab/state . This is where all data like the repositories and uploads will be stored. A basic configuration with some custom settings could look like this: services.gitlab = { enable = true; databasePasswordFile = "/var/keys/gitlab/db_password"; initialRootPasswordFile = "/var/keys/gitlab/root_password"; https = true; host = "git.example.com"; port = 443; user = "git"; group = "git"; smtp = { enable = true; address = "localhost"; port = 25; }; secrets = { dbFile = "/var/keys/gitlab/db"; secretFile = "/var/keys/gitlab/secret"; otpFile = "/var/keys/gitlab/otp"; jwsFile = "/var/keys/gitlab/jws"; }; extraConfig = { gitlab = { email_from = "gitlab-no-reply@example.com"; email_display_name = "Example GitLab"; email_reply_to = "gitlab-no-reply@example.com"; default_projects_features = { builds = false; }; }; }; }; If you're setting up a new Gitlab instance, generate new secrets. You for instance use tr -dc A-Za-z0-9 < /dev/urandom | head -c 128 > /var/keys/gitlab/db to generate a new db secret. Make sure the files can be read by, and only by, the user specified by services.gitlab.user. Gitlab encrypts sensitive data stored in the database. If you're restoring an existing Gitlab instance, you must specify the secrets secret from config/secrets.yml located in your Gitlab state folder. Refer to Appendix A, Configuration Options for all available configuration options for the services.gitlab module. 21.3. Maintenance You can run Gitlab's rake tasks with gitlab-rake which will be available on the system when gitlab is enabled. You will have to run the command as the user that you configured to run gitlab with. For example, to backup a Gitlab instance: $ sudo -u git -H gitlab-rake gitlab:backup:create A list of all availabe rake tasks can be obtained by running: $ sudo -u git -H gitlab-rake -T

Chapter 22. Trezor Trezor is an open-source cryptocurrency hardware wallet and security token allowing secure storage of private keys. It offers advanced features such U2F two-factor authorization, SSH login through Trezor SSH agent, GPG and a password manager. For more information, guides and documentation, see https://wiki.trezor.io. To enable Trezor support, add the following to your configuration.nix : services.trezord.enable = true; This will add all necessary udev rules and start Trezor Bridge.

Chapter 24. Flatpak Source: modules/services/desktop/flatpak.nix Upstream documentation: https://github.com/flatpak/flatpak/wiki Flatpak is a system for building, distributing, and running sandboxed desktop applications on Linux. To enable Flatpak, add the following to your configuration.nix : services.flatpak.enable = true; For the sandboxed apps to work correctly, desktop integration portals need to be installed. If you run GNOME, this will be handled automatically for you; in other cases, you will need to add something like the following to your configuration.nix : xdg.portal.extraPortals = [ pkgs.xdg-desktop-portal-gtk ]; Then, you will need to add a repository, for example, Flathub, either using the following commands: $ flatpak remote-add --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo $ flatpak update or by opening the repository file in GNOME Software. Finally, you can search and install programs: $ flatpak search bustle $ flatpak install flathub org.freedesktop.Bustle $ flatpak run org.freedesktop.Bustle Again, GNOME Software offers graphical interface for these tasks.

Chapter 25. PostgreSQL Table of Contents 25.1. Configuring 25.2. Upgrading 25.3. Options 25.4. Plugins Source: modules/services/databases/postgresql.nix Upstream documentation: http://www.postgresql.org/docs/ PostgreSQL is an advanced, free relational database. 25.1. Configuring To enable PostgreSQL, add the following to your configuration.nix : services.postgresql.enable = true; services.postgresql.package = pkgs.postgresql_11; Note that you are required to specify the desired version of PostgreSQL (e.g. pkgs.postgresql_11 ). Since upgrading your PostgreSQL version requires a database dump and reload (see below), NixOS cannot provide a default value for services.postgresql.package such as the most recent release of PostgreSQL. By default, PostgreSQL stores its databases in /var/lib/postgresql/$psqlSchema . You can override this using services.postgresql.dataDir , e.g. services.postgresql.dataDir = "/data/postgresql"; 25.2. Upgrading Major PostgreSQL upgrade requires PostgreSQL downtime and a few imperative steps to be called. To simplify this process, use the following NixOS module: containers.temp-pg.config.services.postgresql = { enable = true; package = pkgs.postgresql_12; ## set a custom new dataDir # dataDir = "/some/data/dir"; }; environment.systemPackages = let newpg = config.containers.temp-pg.config.services.postgresql; in [ (pkgs.writeScriptBin "upgrade-pg-cluster" '' set -x export OLDDATA="${config.services.postgresql.dataDir}" export NEWDATA="${newpg.dataDir}" export OLDBIN="${config.services.postgresql.package}/bin" export NEWBIN="${newpg.package}/bin" install -d -m 0700 -o postgres -g postgres "$NEWDATA" cd "$NEWDATA" sudo -u postgres $NEWBIN/initdb -D "$NEWDATA" systemctl stop postgresql # old one sudo -u postgres $NEWBIN/pg_upgrade \ --old-datadir "$OLDDATA" --new-datadir "$NEWDATA" \ --old-bindir $OLDBIN --new-bindir $NEWBIN \ "$@" '') ]; The upgrade process is: Rebuild nixos configuration with the configuration above added to your configuration.nix . Alternatively, add that into separate file and reference it in imports list. Login as root ( sudo su - ) Run upgrade-pg-cluster . It will stop old postgresql, initialize new one and migrate old one to new one. You may supply arguments like --jobs 4 and --link to speedup migration process. See https://www.postgresql.org/docs/current/pgupgrade.html for details. Change postgresql package in NixOS configuration to the one you were upgrading to, and change dataDir to the one you have migrated to. Rebuild NixOS. This should start new postgres us