Configuring NixOS This chapter describes how to configure various aspects of a NixOS machine through the configuration file /etc/nixos/configuration.nix. As described in , changes to this file only take effect after you run nixos-rebuild.
Configuration syntax
The basics 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. 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.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, 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"; 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.enabl' defined in `/etc/nixos/configuration.nix' does not exist. Likewise, values in option definitions must have a correct type. For instance, 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 preceding whitespace is automatically stripped from each line, and that characters like " and \ are not special (making it more convenient for including things like shell code). 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 ]; postgresql.package = pkgs.postgresql90; The latter option definition changes the default PostgreSQL package used by NixOS’s PostgreSQL service to 9.0. For more information on packages, including how to add new ones, see .
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 = [ { hostName = "example.org"; documentRoot = "/webroot"; adminAddr = "alice@example.org"; enableUserDir = true; } { hostName = "example.org"; documentRoot = "/webroot"; adminAddr = "alice@example.org"; enableUserDir = true; enableSSL = true; sslServerCert = "/root/ssl-example-org.crt"; sslServerKey = "/root/ssl-example-org.key"; } ]; } It defines two virtual hosts with nearly identical configuration; the only difference is that the second one has SSL enabled. To prevent this duplication, we can use a let: let exampleOrgCommon = { hostName = "example.org"; documentRoot = "/webroot"; adminAddr = "alice@example.org"; enableUserDir = true; }; in { services.httpd.virtualHosts = [ exampleOrgCommon (exampleOrgCommon // { enableSSL = true; sslServerCert = "/root/ssl-example-org.crt"; sslServerKey = "/root/ssl-example-org.key"; }) ]; } The let exampleOrgCommon = ... defines a variable named exampleOrgCommon. The // operator merges two attribute sets, so the configuration of the second virtual host is the set exampleOrgCommon extended with the SSL options. You can write a let wherever an expression is allowed. Thus, you also could have written: { services.httpd.virtualHosts = let exampleOrgCommon = ...; in [ exampleOrgCommon (exampleOrgCommon // { ... }) ]; } but not { let exampleOrgCommon = ...; 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 host name. This can be done as follows: { services.httpd.virtualHosts = let makeVirtualHost = name: { hostName = name; documentRoot = "/webroot"; adminAddr = "alice@example.org"; }; in [ (makeVirtualHost "example.org") (makeVirtualHost "example.com") (makeVirtualHost "example.gov") (makeVirtualHost "example.nl") ]; } Here, makeVirtualHost is a function that takes a single argument name and returns the configuration for a virtual host. That function is then called for several names to produce the list of virtual host configurations. We can further improve on this by using the function map, which applies another function to every element in a list: { services.httpd.virtualHosts = let makeVirtualHost = ...; in map makeVirtualHost [ "example.org" "example.com" "example.gov" "example.nl" ]; } (The function map is called a higher-order function because it takes another function as an argument.) What if you need more than one argument, for instance, if we want to use a different documentRoot for each virtual host? Then we can make makeVirtualHost a function that takes a set as its argument, like this: { services.httpd.virtualHosts = let makeVirtualHost = { name, root }: { hostName = name; documentRoot = root; adminAddr = "alice@example.org"; }; in map makeVirtualHost [ { name = "example.org"; root = "/sites/example.org"; } { name = "example.com"; root = "/sites/example.com"; } { name = "example.gov"; root = "/sites/example.gov"; } { name = "example.nl"; root = "/sites/example.nl"; } ]; } But in this case (where every root is a subdirectory of /sites named after the virtual host), it would have been shorter to define makeVirtualHost as makeVirtualHost = name: { hostName = name; documentRoot = "/sites/${name}"; adminAddr = "alice@example.org"; }; Here, the construct ${...} allows the result of an expression to be spliced into a string.
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.kdm.enable = true; services.xserver.desktopManager.kde4.enable = true; environment.systemPackages = [ pkgs.kde4.kscreensaver ]; } Note that both configuration.nix and kde.nix define the option . When multiple modules define an option, NixOS will try to merge the definitions. In the case of , that’s easy: the lists of packages can simply be concatenated. For other types of options, a merge may not be possible: for instance, if two modules define , 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 moduleIf you’re wondering how it’s possible that the (indirect) result of a function is passed as an input to that same function: that’s because Nix is a “lazy” language — it only computes values when they are needed. This works as long as no individual configuration value depends on itself.. For example, here is a module that adds some packages to only if 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 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. It’s not installed by default; run nix-env -i nix-repl to get it. A typical use: $ nix-repl '<nixos>' nix-repl> config.networking.hostName "mandark" nix-repl> map (x: x.hostName) config.services.httpd.virtualHosts [ "example.org" "example.gov" ]
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; } An set with attributes names x and y { foo.bar = 1; } A nested set, equivalent to { foo = { bar = 1; }; } rec { x = "bla"; 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!") 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 ])
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. The next two sections describe these two styles.
Declarative package management With declarative package management, you specify which packages you want on your system by setting the option . 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. You can get a list of the available packages as follows: $ nix-env -qaP '*' --description nixos.pkgs.firefox firefox-23.0 Mozilla Firefox - the browser, reloaded ... The first column in the output is the attribute name, such as nixos.pkgs.thunderbird. (The nixos prefix allows distinguishing between different channels that you might have.) To “uninstall” a package, simply remove it from and run nixos-rebuild switch.
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; 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 overrideDerivation. While the override mechanism above overrides the arguments of a package function, overrideDerivation allows changing the result of the function. 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.lib.overrideDerivation pkgs.emacs (attrs: { name = "emacs-25.0-pre"; src = /path/to/my/emacs/tree; })) ]; Here, overrideDerivation 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. The original attributes are accessible via attrs. 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 overriden instance, to prevent an infinite recursion.)
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 git://github.com/NixOS/nixpkgs.git $ 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 <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!
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.pkgs.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 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 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-env1 manpage or the Nix manual.
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.extraUsers.alice = { createHome = true; home = "/home/alice"; description = "Alice Foobar"; extraGroups = [ "wheel" ]; isSystemUser = false; useDefaultShell = true; openssh.authorizedKeys.keys = [ "ssh-dss AAAAB3Nza... alice@foobar" ]; }; Note that alice is a member of the wheel group, which allows her to use sudo to execute commands as root. 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. 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.extraGroups.students.gid = 1000; As with users, the group ID (gid) is optional and will be assigned automatically if it’s missing. Currently declarative user management is not perfect: nixos-rebuild does not know how to realise certain configuration changes. This includes removing a user or group, and removing group membership from a user. 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 The flag 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 deletes the user’s home directory. Accounts can be modified using usermod. Unix groups can be managed using groupadd, groupmod and groupdel.
File systems You can define file systems using the 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 , 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 (), 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 to ensure that the kernel module is available.
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/sda2: $ cryptsetup luksFormat /dev/sda2 WARNING! ======== This will overwrite data on /dev/sda2 irrevocably. Are you sure? (Type uppercase yes): YES Enter LUKS passphrase: *** Verify passphrase: *** $ cryptsetup luksOpen /dev/sda2 crypted Enter passphrase for /dev/sda2: *** $ 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 = [ { device = "/dev/sda2"; name = "crypted"; } ]; fileSystems."/".device = "/dev/mapper/crypted";
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.kde4.enable = true; services.xserver.desktopManager.xfce.enable = true; services.xserver.windowManager.xmonad.enable = true; services.xserver.windowManager.twm.enable = true; services.xserver.windowManager.icewm.enable = true; NixOS’s default display manager (the program that provides a graphical login prompt and manages the X server) is SLiM. You can select KDE’s kdm instead: services.xserver.displayManager.kdm.enable = true; 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
NVIDIA graphics cards 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" ]; You may need to reboot after enabling this driver to prevent a clash with other kernel modules. On 64-bit systems, if you want full acceleration for 32-bit programs such as Wine, you should also set the following: services.xserver.driSupport32Bit = true;
Touchpads Support for Synaptics touchpads (found in many laptops such as the Dell Latitude series) can be enabled as follows: services.xserver.synaptics.enable = true; The driver has many options (see ). For instance, the following enables two-finger scrolling: services.xserver.synaptics.twoFingerScroll = true;
Networking
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.extraUsers.alice.openssh.authorizedKeys.keys = [ "ssh-dss AAAAB3NzaC1kc3MAAACBAPIkGWVEt4..." ];
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 = { ipAddress = "192.168.1.2"; prefixLength = 24; }; (The network prefix can also be specified using the option subnetMask, e.g. "255.255.255.0", but this is deprecated.) 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" ]; 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 = "cartman"; The default host name is nixos. Set it to the empty string ("") to allow the DHCP server to provide the host name.
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;
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 can be enabled as follows: networking.firewall.enable = true; 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 (). UDP ports can be opened through . Also of interest is networking.firewall.allowPing = true; to allow the machine to respond to ping requests. (ICMPv6 pings are always allowed.)
Wireless networks NixOS will start wpa_supplicant for you if you enable this setting: networking.wireless.enable = true; NixOS currently does not generate wpa_supplicant's configuration file, /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 the wpa_passphrase tool might be useful to 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
Ad-hoc configuration You can use 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 '';
Linux kernel You can override the Linux kernel and associated packages using the option . 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 in /run/booted-system/kernel-modules/config. If you want to change the kernel configuration, you can use the feature (see ). 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 , 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.extraKernelModules = [ "cifs" ]; This causes the specified modules and their dependencies to be added to the initial ramdark. Kernel runtime parameters can be set through , 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.