dev: NixOS 25.11 매뉴얼 로컬 사본 추가

nixpkgs nixos-25.11 브랜치의 nixos/doc/manual/ 디렉토리를 sparse clone으로
가져와 ~/obsidian/dev/nixos-manual/에 복사. _index.md에 구조/갱신 방법 정리.

오프라인 참조 + AI 에이전트 컨텍스트용. sandbox-tokyo 같은 NixOS 노드 운영 시
빠른 참조로 사용.
This commit is contained in:
kappa
2026-04-08 16:15:46 +09:00
parent 862ca9bae8
commit 370c7da4a9
145 changed files with 24441 additions and 0 deletions

View File

@@ -0,0 +1,4 @@
[Moved to ./contributing-to-this-manual.chapter.md](./contributing-to-this-manual.chapter.md).
Link:
https://nixos.org/manual/nixos/unstable/#chap-contributing

View File

@@ -0,0 +1,65 @@
---
title: NixOS Manual (25.11 Xantusia)
updated: 2026-04-08
tags: [nixos, manual, reference, dev]
source: https://github.com/NixOS/nixpkgs/tree/nixos-25.11/nixos/doc/manual
upstream-version: nixos-25.11
---
# NixOS Manual (로컬 사본)
NixOS 25.11 stable("Xantusia") 매뉴얼의 CommonMark 소스. nixpkgs `nixos-25.11` 브랜치의 `nixos/doc/manual/` 디렉토리를 그대로 복사한 것.
- **온라인 렌더링**: https://nixos.org/manual/nixos/stable/
- **상위**: https://github.com/NixOS/nixpkgs/tree/nixos-25.11/nixos/doc/manual
- **가져온 날짜**: 2026-04-08
- **로컬 위치**: `~/obsidian/dev/nixos-manual/`
## 구조
| 디렉토리 / 파일 | 내용 |
|---|---|
| `manual.md` | 매뉴얼 루트(목차) |
| `preface.md` | 머리말 |
| `installation/` | 설치(하드웨어, 부트로더, 프로비저닝) |
| `configuration/` | 시스템 설정(모듈, 옵션, 사용자, 네트워킹, 부트, X11, Wayland 등) |
| `administration/` | 운영(서비스 관리, 컨테이너, 업그레이드, 트러블슈팅) |
| `development/` | 개발(모듈 작성, 옵션 정의, 테스트, 패키지 추가, 빌드 시스템) |
| `release-notes/` | 릴리스 노트 (각 NixOS 버전별 변경) |
| `nixos-options.md` | 옵션 카탈로그 안내 |
| `contributing-to-this-manual.chapter.md` | 매뉴얼 자체 기여 가이드 |
| `redirects.json` | 매뉴얼 URL 리다이렉트 매핑 |
| `default.nix`, `common.nix`, `shell.nix`, `README.md` | 매뉴얼 빌드 인프라 (참고용, NixOS 사용에는 직접 필요 없음) |
## 빠른 진입
- 처음 NixOS를 보는 사람: `manual.md``installation/``configuration/`
- 운영 중인 노드 다루는 사람: `administration/` + `release-notes/rl-2511.section.md`
- 모듈 만들고 싶은 사람: `development/writing-nixos-modules.section.md`
- 옵션 검색은 온라인이 더 빠름: https://search.nixos.org/options?channel=25.11
## 갱신 방법
새 stable 출시 시 (예: 26.05) 같은 방식으로 sparse clone 후 덮어쓰기:
```bash
cd /tmp && rm -rf nixpkgs-manual-fetch
git clone --depth=1 --filter=blob:none --sparse \
--branch nixos-26.05 https://github.com/NixOS/nixpkgs.git nixpkgs-manual-fetch
cd nixpkgs-manual-fetch && git sparse-checkout set nixos/doc/manual
rm -rf ~/obsidian/dev/nixos-manual/{administration,configuration,development,installation,release-notes,*.md,*.nix,*.json}
cp -R /tmp/nixpkgs-manual-fetch/nixos/doc/manual/. ~/obsidian/dev/nixos-manual/
# _index.md(이 파일)는 보존
```
## 주의
- 파일은 **CommonMark + MyST 확장**이라 일반 markdown 렌더러는 일부 directive(`{.note}`, `:::`, `{=include}`)를 제대로 보여주지 않을 수 있음. Obsidian 기본 뷰에서는 코드블럭처럼 보일 수 있음.
- 옵션 카탈로그(`nixos-options.md`)는 빌드 시 자동 생성되는 placeholder. 실제 옵션 검색은 https://search.nixos.org/options 사용.
- 빌드 인프라 파일(`default.nix`, `common.nix`, `shell.nix`)은 manual을 PDF/HTML로 빌드할 때만 필요.
- 향후 [[infra-hosts|sandbox-tokyo]] 같은 NixOS 노드 운영 시 빠른 참조용.
## 관련 문서
- [[infra-hosts]] — 인프라 호스트 (sandbox-tokyo NixOS 노드 포함)
- [[sandbox-tokyo-nixos]] — sandbox-tokyo의 NixOS 전환 기록

View File

@@ -0,0 +1,41 @@
# Boot Problems {#sec-boot-problems}
If NixOS fails to boot, there are a number of kernel command line parameters that may help you to identify or fix the issue. You can add these parameters in the GRUB boot menu by pressing “e” to modify the selected boot entry and editing the line starting with `linux`. The following are some useful kernel command line parameters that are recognised by the NixOS boot scripts or by systemd:
`boot.shell_on_fail`
: Allows the user to start a root shell if something goes wrong in stage 1 of the boot process (the initial ramdisk). This is disabled by default because there is no authentication for the root shell.
`boot.debug1`
: Start an interactive shell in stage 1 before anything useful has been done. That is, no modules have been loaded and no file systems have been mounted, except for `/proc` and `/sys`.
`boot.debug1devices`
: Like `boot.debug1`, but runs stage1 until kernel modules are loaded and device nodes are created. This may help with e.g. making the keyboard work.
`boot.debug1mounts`
: Like `boot.debug1` or `boot.debug1devices`, but runs stage1 until all filesystems that are mounted during initrd are mounted (see [neededForBoot](#opt-fileSystems._name_.neededForBoot)). As a motivating example, this could be useful if you've forgotten to set [neededForBoot](#opt-fileSystems._name_.neededForBoot) on a file system.
`boot.trace`
: Print every shell command executed by the stage 1 and 2 boot scripts.
`single`
: Boot into rescue mode (a.k.a. single user mode). This will cause systemd to start nothing but the unit `rescue.target`, which runs `sulogin` to prompt for the root password and start a root login shell. Exiting the shell causes the system to continue with the normal boot process.
`systemd.log_level=debug` `systemd.log_target=console`
: Make systemd very verbose and send log messages to the console instead of the journal. For more parameters recognised by systemd, see systemd(1).
In addition, these arguments are recognised by the live image only:
`live.nixos.passwd=password`
: Set the password for the `nixos` live user. This can be used for SSH access if there are issues using the terminal.
Notice that for `boot.shell_on_fail`, `boot.debug1`, `boot.debug1devices`, and `boot.debug1mounts`, if you did **not** select "start the new shell as pid 1", and you `exit` from the new shell, boot will proceed normally from the point where it failed, as if you'd chosen "ignore the error and continue".
If no login prompts or X11 login screens appear (e.g. due to hanging dependencies), you can press Alt+ArrowUp. If youre lucky, this will start rescue mode (described above). (Also note that since most units have a 90-second timeout before systemd gives up on them, the `agetty` login prompts should appear eventually unless something is very wrong.)

View File

@@ -0,0 +1,64 @@
# Cleaning the Nix Store {#sec-nix-gc}
Nix has a purely functional model, meaning that packages are never
upgraded in place. Instead new versions of packages end up in a
different location in the Nix store (`/nix/store`). You should
periodically run Nix's *garbage collector* to remove old, unreferenced
packages. This is easy:
```ShellSession
$ nix-collect-garbage
```
Alternatively, you can use a systemd unit that does the same in the
background:
```ShellSession
# systemctl start nix-gc.service
```
You can tell NixOS in `configuration.nix` to run this unit automatically
at certain points in time, for instance, every night at 03:15:
```nix
{
nix.gc.automatic = true;
nix.gc.dates = "03:15";
}
```
The commands above do not remove garbage collector roots, such as old
system configurations. Thus they do not remove the ability to roll back
to previous configurations. The following command deletes old roots,
removing the ability to roll back to them:
```ShellSession
$ nix-collect-garbage -d
```
You can also do this for specific profiles, e.g.
```ShellSession
$ nix-env -p /nix/var/nix/profiles/per-user/eelco/profile --delete-generations old
```
Note that NixOS system configurations are stored in the profile
`/nix/var/nix/profiles/system`.
Another way to reclaim disk space (often as much as 40% of the size of
the Nix store) is to run Nix's store optimiser, which seeks out
identical files in the store and replaces them with hard links to a
single copy.
```ShellSession
$ nix-store --optimise
```
Since this command needs to read the entire Nix store, it can take quite
a while to finish.
## NixOS Boot Entries {#sect-nixos-gc-boot-entries}
If your `/boot` partition runs out of space, after clearing old profiles
you must rebuild your system with `nixos-rebuild boot` or `nixos-rebuild
switch` to update the `/boot` partition and clear space.

View File

@@ -0,0 +1,46 @@
# Container Networking {#sec-container-networking}
When you create a container using `nixos-container create`, it gets it
own private IPv4 address in the range `10.233.0.0/16`. You can get the
container's IPv4 address as follows:
```ShellSession
# nixos-container show-ip foo
10.233.4.2
$ ping -c1 10.233.4.2
64 bytes from 10.233.4.2: icmp_seq=1 ttl=64 time=0.106 ms
```
Networking is implemented using a pair of virtual Ethernet devices. The
network interface in the container is called `eth0`, while the matching
interface in the host is called `ve-container-name` (e.g., `ve-foo`).
The container has its own network namespace and the `CAP_NET_ADMIN`
capability, so it can perform arbitrary network configuration such as
setting up firewall rules, without affecting or having access to the
host's network.
By default, containers cannot talk to the outside network. If you want
that, you should set up Network Address Translation (NAT) rules on the
host to rewrite container traffic to use your external IP address. This
can be accomplished using the following configuration on the host:
```nix
{
networking.nat.enable = true;
networking.nat.internalInterfaces = [ "ve-+" ];
networking.nat.externalInterface = "eth0";
}
```
where `eth0` should be replaced with the desired external interface.
Note that `ve-+` is a wildcard that matches all container interfaces.
If you are using Network Manager, you need to explicitly prevent it from
managing container interfaces:
```nix
{ networking.networkmanager.unmanaged = [ "interface-name:ve-*" ]; }
```
You may need to restart your system for the changes to take effect.

View File

@@ -0,0 +1,28 @@
# Container Management {#ch-containers}
NixOS allows you to easily run other NixOS instances as *containers*.
Containers are a light-weight approach to virtualisation that runs
software in the container at the same speed as in the host system. NixOS
containers share the Nix store of the host, making container creation
very efficient.
::: {.warning}
Currently, NixOS containers are not perfectly isolated from the host
system. This means that a user with root access to the container can do
things that affect the host. So you should not give container root
access to untrusted users.
:::
NixOS containers can be created in two ways: imperatively, using the
command `nixos-container`, and declaratively, by specifying them in your
`configuration.nix`. The declarative approach implies that containers
get upgraded along with your host system when you run `nixos-rebuild`,
which is often not what you want. By contrast, in the imperative
approach, containers are configured and updated independently from the
host system.
```{=include=} sections
imperative-containers.section.md
declarative-containers.section.md
container-networking.section.md
```

View File

@@ -0,0 +1,59 @@
# Control Groups {#sec-cgroups}
To keep track of the processes in a running system, systemd uses
*control groups* (cgroups). A control group is a set of processes used
to allocate resources such as CPU, memory or I/O bandwidth. There can be
multiple control group hierarchies, allowing each kind of resource to be
managed independently.
The command `systemd-cgls` lists all control groups in the `systemd`
hierarchy, which is what systemd uses to keep track of the processes
belonging to each service or user session:
```ShellSession
$ systemd-cgls
├─user
│ └─eelco
│ └─c1
│ ├─ 2567 -:0
│ ├─ 2682 kdeinit4: kdeinit4 Running...
│ ├─ ...
│ └─10851 sh -c less -R
└─system
├─httpd.service
│ ├─2444 httpd -f /nix/store/3pyacby5cpr55a03qwbnndizpciwq161-httpd.conf -DNO_DETACH
│ └─...
├─dhcpcd.service
│ └─2376 dhcpcd --config /nix/store/f8dif8dsi2yaa70n03xir8r653776ka6-dhcpcd.conf
└─ ...
```
Similarly, `systemd-cgls cpu` shows the cgroups in the CPU hierarchy,
which allows per-cgroup CPU scheduling priorities. By default, every
systemd service gets its own CPU cgroup, while all user sessions are in
the top-level CPU cgroup. This ensures, for instance, that a thousand
run-away processes in the `httpd.service` cgroup cannot starve the CPU
for one process in the `postgresql.service` cgroup. (By contrast, it
they were in the same cgroup, then the PostgreSQL process would get
1/1001 of the cgroup's CPU time.) You can limit a service's CPU share in
`configuration.nix`:
```nix
{ systemd.services.httpd.serviceConfig.CPUShares = 512; }
```
By default, every cgroup has 1024 CPU shares, so this will halve the CPU
allocation of the `httpd.service` cgroup.
There also is a `memory` hierarchy that controls memory allocation
limits; by default, all processes are in the top-level cgroup, so any
service or session can exhaust all available memory. Per-cgroup memory
limits can be specified in `configuration.nix`; for instance, to limit
`httpd.service` to 512 MiB of RAM (excluding swap):
```nix
{ systemd.services.httpd.serviceConfig.MemoryLimit = "512M"; }
```
The command `systemd-cgtop` shows a continuously updated list of all
cgroups with their CPU and memory usage.

View File

@@ -0,0 +1,53 @@
# Declarative Container Specification {#sec-declarative-containers}
You can also specify containers and their configuration in the host's
`configuration.nix`. For example, the following specifies that there
shall be a container named `database` running PostgreSQL:
```nix
{
containers.database = {
config =
{ config, pkgs, ... }:
{
services.postgresql.enable = true;
services.postgresql.package = pkgs.postgresql_14;
};
};
}
```
If you run `nixos-rebuild switch`, the container will be built. If the
container was already running, it will be updated in place, without
rebooting. The container can be configured to start automatically by
setting `containers.database.autoStart = true` in its configuration.
By default, declarative containers share the network namespace of the
host, meaning that they can listen on (privileged) ports. However, they
cannot change the network configuration. You can give a container its
own network as follows:
```nix
{
containers.database = {
privateNetwork = true;
hostAddress = "192.168.100.10";
localAddress = "192.168.100.11";
};
}
```
This gives the container a private virtual Ethernet interface with IP
address `192.168.100.11`, which is hooked up to a virtual Ethernet
interface on the host with IP address `192.168.100.10`. (See the next
section for details on container networking.)
To disable the container, just remove it from `configuration.nix` and
run `nixos-rebuild
switch`. Note that this will not delete the root directory of the
container in `/var/lib/nixos-containers`. Containers can be destroyed using
the imperative method: `nixos-container destroy foo`.
Declarative containers can be started and stopped using the
corresponding systemd service, e.g.
`systemctl start container@database`.

View File

@@ -0,0 +1,115 @@
# Imperative Container Management {#sec-imperative-containers}
We'll cover imperative container management using `nixos-container`
first. Be aware that container management is currently only possible as
`root`, and that you need to enable [](#opt-boot.enableContainers) explicitly.
You create a container with identifier `foo` as follows:
```ShellSession
# nixos-container create foo
```
This creates the container's root directory in `/var/lib/nixos-containers/foo`
and a small configuration file in `/etc/nixos-containers/foo.conf`. It also
builds the container's initial system configuration and stores it in
`/nix/var/nix/profiles/per-container/foo/system`. You can modify the
initial configuration of the container on the command line. For
instance, to create a container that has `sshd` running, with the given
public key for `root`:
```ShellSession
# nixos-container create foo --config '
services.openssh.enable = true;
users.users.root.openssh.authorizedKeys.keys = ["ssh-dss AAAAB3N…"];
'
```
By default the next free address in the `10.233.0.0/16` subnet will be
chosen as container IP. This behavior can be altered by setting
`--host-address` and `--local-address`:
```ShellSession
# nixos-container create test --config-file test-container.nix \
--local-address 10.235.1.2 --host-address 10.235.1.1
```
Creating a container does not start it. To start the container, run:
```ShellSession
# nixos-container start foo
```
This command will return as soon as the container has booted and has
reached `multi-user.target`. On the host, the container runs within a
systemd unit called `container@container-name.service`. Thus, if
something went wrong, you can get status info using `systemctl`:
```ShellSession
# systemctl status container@foo
```
If the container has started successfully, you can log in as root using
the `root-login` operation:
```ShellSession
# nixos-container root-login foo
[root@foo:~]#
```
Note that only root on the host can do this (since there is no
authentication). You can also get a regular login prompt using the
`login` operation, which is available to all users on the host:
```ShellSession
# nixos-container login foo
foo login: alice
Password: ***
```
With `nixos-container run`, you can execute arbitrary commands in the
container:
```ShellSession
# nixos-container run foo -- uname -a
Linux foo 3.4.82 #1-NixOS SMP Thu Mar 20 14:44:05 UTC 2014 x86_64 GNU/Linux
```
There are several ways to change the configuration of the container.
First, on the host, you can edit
`/var/lib/nixos-containers/foo/etc/nixos/configuration.nix`, and run
```ShellSession
# nixos-container update foo
```
This will build and activate the new configuration. You can also specify
a new configuration on the command line:
```ShellSession
# nixos-container update foo --config '
services.httpd.enable = true;
services.httpd.adminAddr = "foo@example.org";
networking.firewall.allowedTCPPorts = [ 80 ];
'
# curl http://$(nixos-container show-ip foo)/
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">…
```
However, note that this will overwrite the container's
`/etc/nixos/configuration.nix`.
Alternatively, you can change the configuration from within the
container itself by running `nixos-rebuild switch` inside the container.
Note that the container by default does not have a copy of the NixOS
channel, so you should run `nix-channel --update` first.
Containers can be stopped and started using `nixos-container
stop` and `nixos-container start`, respectively, or by using
`systemctl` on the container's service unit. To destroy a container,
including its file system, do
```ShellSession
# nixos-container destroy foo
```

View File

@@ -0,0 +1,38 @@
# Logging {#sec-logging}
System-wide logging is provided by systemd's *journal*, which subsumes
traditional logging daemons such as syslogd and klogd. Log entries are
kept in binary files in `/var/log/journal/`. The command `journalctl`
allows you to see the contents of the journal. For example,
```ShellSession
$ journalctl -b
```
shows all journal entries since the last reboot. (The output of
`journalctl` is piped into `less` by default.) You can use various
options and match operators to restrict output to messages of interest.
For instance, to get all messages from PostgreSQL:
```ShellSession
$ journalctl -u postgresql.service
-- Logs begin at Mon, 2013-01-07 13:28:01 CET, end at Tue, 2013-01-08 01:09:57 CET. --
...
Jan 07 15:44:14 hagbard postgres[2681]: [2-1] LOG: database system is shut down
-- Reboot --
Jan 07 15:45:10 hagbard postgres[2532]: [1-1] LOG: database system was shut down at 2013-01-07 15:44:14 CET
Jan 07 15:45:13 hagbard postgres[2500]: [1-1] LOG: database system is ready to accept connections
```
Or to get all messages since the last reboot that have at least a
"critical" severity level:
```ShellSession
$ journalctl -b -p crit
Dec 17 21:08:06 mandark sudo[3673]: pam_unix(sudo:auth): auth could not identify password for [alice]
Dec 29 01:30:22 mandark kernel[6131]: [1053513.909444] CPU6: Core temperature above threshold, cpu clock throttled (total events = 1)
```
The system journal is readable by root and by users in the `wheel` and
`systemd-journal` groups. All users have a private journal that can be
read using `journalctl`.

View File

@@ -0,0 +1,11 @@
# Maintenance Mode {#sec-maintenance-mode}
You can enter rescue mode by running:
```ShellSession
# systemctl rescue
```
This will eventually give you a single-user root shell. Systemd will
stop (almost) all system services. To get out of maintenance mode, just
exit from the rescue shell.

View File

@@ -0,0 +1,21 @@
# Network Problems {#sec-nix-network-issues}
Nix uses a so-called *binary cache* to optimise building a package from
source into downloading it as a pre-built binary. That is, whenever a
command like `nixos-rebuild` needs a path in the Nix store, Nix will try
to download that path from the Internet rather than build it from
source. The default binary cache is `https://cache.nixos.org/`. If this
cache is unreachable, Nix operations may take a long time due to HTTP
connection timeouts. You can disable the use of the binary cache by
adding `--option use-binary-caches false`, e.g.
```ShellSession
# nixos-rebuild switch --option use-binary-caches false
```
If you have an alternative binary cache at your disposal, you can use it
instead:
```ShellSession
# nixos-rebuild switch --option binary-caches http://my-cache.example.org/
```

View File

@@ -0,0 +1,28 @@
# NixOS {#sec-nixos-state}
## `/nix` {#sec-state-nix}
NixOS needs the entirety of `/nix` to be persistent, as it includes:
- `/nix/store`, which contains all the system's executables, libraries, and supporting data;
- `/nix/var/nix`, which contains:
- the Nix daemon's database;
- roots whose transitive closure is preserved when garbage-collecting the Nix store;
- system-wide and per-user profiles.
## `/boot` {#sec-state-boot}
`/boot` should also be persistent, as it contains:
- the kernel and initrd which the bootloader loads,
- the bootloader's configuration, including the kernel's command-line which
determines the store path to use as system environment.
## Users and groups {#sec-state-users}
- `/var/lib/nixos` should persist: it holds state needed to generate stable
uids and gids for declaratively-managed users and groups, etc.
- `users.mutableUsers` should be false, *or* the following files under `/etc`
should all persist:
- {manpage}`passwd(5)` and {manpage}`group(5)`,
- {manpage}`shadow(5)` and {manpage}`gshadow(5)`,
- {manpage}`subuid(5)` and {manpage}`subgid(5)`.

View File

@@ -0,0 +1,30 @@
# Rebooting and Shutting Down {#sec-rebooting}
The system can be shut down (and automatically powered off) by doing:
```ShellSession
# shutdown
```
This is equivalent to running `systemctl poweroff`.
To reboot the system, run
```ShellSession
# reboot
```
which is equivalent to `systemctl reboot`. Alternatively, you can
quickly reboot the system using `kexec`, which bypasses the BIOS by
directly loading the new kernel into memory:
```ShellSession
# systemctl kexec
```
The machine can be suspended to RAM (if supported) using `systemctl suspend`,
and suspended to disk using `systemctl hibernate`.
These commands can be run by any user who is logged in locally, i.e. on
a virtual console or in X11; otherwise, the user is asked for
authentication.

View File

@@ -0,0 +1,38 @@
# Rolling Back Configuration Changes {#sec-rollback}
After running `nixos-rebuild` to switch to a new configuration, you may
find that the new configuration doesn't work very well. In that case,
there are several ways to return to a previous configuration.
First, the GRUB boot manager allows you to boot into any previous
configuration that hasn't been garbage-collected. These configurations
can be found under the GRUB submenu "NixOS - All configurations". This
is especially useful if the new configuration fails to boot. After the
system has booted, you can make the selected configuration the default
for subsequent boots:
```ShellSession
# /run/current-system/bin/switch-to-configuration boot
```
Second, you can switch to the previous configuration in a running
system:
```ShellSession
# nixos-rebuild switch --rollback
```
This is equivalent to running:
```ShellSession
# /nix/var/nix/profiles/system-N-link/bin/switch-to-configuration switch
```
where `N` is the number of the NixOS system configuration. To get a
list of the available configurations, do:
```ShellSession
$ ls -l /nix/var/nix/profiles/system-*-link
...
lrwxrwxrwx 1 root root 78 Aug 12 13:54 /nix/var/nix/profiles/system-268-link -> /nix/store/202b...-nixos-13.07pre4932_5a676e4-4be1055
```

View File

@@ -0,0 +1,15 @@
# Administration {#ch-running}
This chapter describes various aspects of managing a running NixOS system, such as how to use the {command}`systemd` service manager.
```{=include=} chapters
service-mgmt.chapter.md
rebooting.chapter.md
user-sessions.chapter.md
control-groups.chapter.md
logging.chapter.md
system-state.chapter.md
cleaning-store.chapter.md
containers.chapter.md
troubleshooting.chapter.md
```

View File

@@ -0,0 +1,173 @@
# Service Management {#sec-systemctl}
In NixOS, all system services are started and monitored using the
systemd program. systemd is the "init" process of the system (i.e. PID
1), the parent of all other processes. It manages a set of so-called
"units", which can be things like system services (programs), but also
mount points, swap files, devices, targets (groups of units) and more.
Units can have complex dependencies; for instance, one unit can require
that another unit must be successfully started before the first unit can
be started. When the system boots, it starts a unit named
`default.target`; the dependencies of this unit cause all system
services to be started, file systems to be mounted, swap files to be
activated, and so on.
## Interacting with a running systemd {#sect-nixos-systemd-general}
The command `systemctl` is the main way to interact with `systemd`. The
following paragraphs demonstrate ways to interact with any OS running
systemd as init system. NixOS is of no exception. The [next section
](#sect-nixos-systemd-nixos) explains NixOS specific things worth
knowing.
Without any arguments, `systemctl` the status of active units:
```ShellSession
$ systemctl
-.mount loaded active mounted /
swapfile.swap loaded active active /swapfile
sshd.service loaded active running SSH Daemon
graphical.target loaded active active Graphical Interface
...
```
You can ask for detailed status information about a unit, for instance,
the PostgreSQL database service:
```ShellSession
$ systemctl status postgresql.service
postgresql.service - PostgreSQL Server
Loaded: loaded (/nix/store/pn3q73mvh75gsrl8w7fdlfk3fq5qm5mw-unit/postgresql.service)
Active: active (running) since Mon, 2013-01-07 15:55:57 CET; 9h ago
Main PID: 2390 (postgres)
CGroup: name=systemd:/system/postgresql.service
├─2390 postgres
├─2418 postgres: writer process
├─2419 postgres: wal writer process
├─2420 postgres: autovacuum launcher process
├─2421 postgres: stats collector process
└─2498 postgres: zabbix zabbix [local] idle
Jan 07 15:55:55 hagbard postgres[2394]: [1-1] LOG: database system was shut down at 2013-01-07 15:55:05 CET
Jan 07 15:55:57 hagbard postgres[2390]: [1-1] LOG: database system is ready to accept connections
Jan 07 15:55:57 hagbard postgres[2420]: [1-1] LOG: autovacuum launcher started
Jan 07 15:55:57 hagbard systemd[1]: Started PostgreSQL Server.
```
Note that this shows the status of the unit (active and running), all
the processes belonging to the service, as well as the most recent log
messages from the service.
Units can be stopped, started or restarted:
```ShellSession
# systemctl stop postgresql.service
# systemctl start postgresql.service
# systemctl restart postgresql.service
```
These operations are synchronous: they wait until the service has
finished starting or stopping (or has failed). Starting a unit will
cause the dependencies of that unit to be started as well (if
necessary).
## systemd in NixOS {#sect-nixos-systemd-nixos}
Packages in Nixpkgs sometimes provide systemd units with them, usually
in e.g `#pkg-out#/lib/systemd/`. Putting such a package in
`environment.systemPackages` doesn't make the service available to
users or the system.
In order to enable a systemd *system* service with provided upstream
package, use (e.g):
```nix
{ systemd.packages = [ pkgs.packagekit ]; }
```
Usually NixOS modules written by the community do the above, plus take
care of other details. If a module was written for a service you are
interested in, you'd probably need only to use
`services.#name#.enable = true;`. These services are defined in
Nixpkgs' [ `nixos/modules/` directory
](https://github.com/NixOS/nixpkgs/tree/master/nixos/modules). In case
the service is simple enough, the above method should work, and start
the service on boot.
*User* systemd services on the other hand, should be treated
differently. Given a package that has a systemd unit file at
`#pkg-out#/lib/systemd/user/`, using [](#opt-systemd.packages) will
make you able to start the service via `systemctl --user start`, but it
won't start automatically on login. However, You can imperatively
enable it by adding the package's attribute to
[](#opt-systemd.packages) and then do this (e.g):
```ShellSession
$ mkdir -p ~/.config/systemd/user/default.target.wants
$ ln -s /run/current-system/sw/lib/systemd/user/syncthing.service ~/.config/systemd/user/default.target.wants/
$ systemctl --user daemon-reload
$ systemctl --user enable syncthing.service
```
If you are interested in a timer file, use `timers.target.wants` instead
of `default.target.wants` in the 1st and 2nd command.
Using `systemctl --user enable syncthing.service` instead of the above,
will work, but it'll use the absolute path of `syncthing.service` for
the symlink, and this path is in `/nix/store/.../lib/systemd/user/`.
Hence [garbage collection](#sec-nix-gc) will remove that file and you
will wind up with a broken symlink in your systemd configuration, which
in turn will not make the service / timer start on login.
### Defining custom services {#sect-nixos-systemd-custom-services}
You can define services by adding them to `systemd.services`:
```nix
{
systemd.services.myservice = {
after = [ "network-online.target" ];
requires = [ "network-online.target" ];
before = [ "multi-user.target" ];
wantedBy = [ "multi-user.target" ];
serviceConfig = {
ExecStart = "...";
};
};
}
```
If you want to specify a multi-line script for `ExecStart`,
you may want to use `pkgs.writeShellScript`.
### Template units {#sect-nixos-systemd-template-units}
systemd supports templated units where a base unit can be started multiple
times with a different parameter. The syntax to accomplish this is
`service-name@instance-name.service`. Units get the instance name passed to
them (see `systemd.unit(5)`). NixOS has support for these kinds of units and
for template-specific overrides. A service needs to be defined twice, once
for the base unit and once for the instance. All instances must include
`overrideStrategy = "asDropin"` for the change detection to work. This
example illustrates this:
```nix
{
systemd.services = {
"base-unit@".serviceConfig = {
ExecStart = "...";
User = "...";
};
"base-unit@instance-a" = {
overrideStrategy = "asDropin"; # needed for templates to work
wantedBy = [ "multi-user.target" ]; # causes NixOS to manage the instance
};
"base-unit@instance-b" = {
overrideStrategy = "asDropin"; # needed for templates to work
wantedBy = [ "multi-user.target" ]; # causes NixOS to manage the instance
serviceConfig.User = "root"; # also override something for this specific instance
};
};
}
```

View File

@@ -0,0 +1,28 @@
# Nix Store Corruption {#sec-nix-store-corruption}
After a system crash, it's possible for files in the Nix store to become
corrupted. (For instance, the Ext4 file system has the tendency to
replace un-synced files with zero bytes.) NixOS tries hard to prevent
this from happening: it performs a `sync` before switching to a new
configuration, and Nix's database is fully transactional. If corruption
still occurs, you may be able to fix it automatically.
If the corruption is in a path in the closure of the NixOS system
configuration, you can fix it by doing
```ShellSession
# nixos-rebuild switch --repair
```
This will cause Nix to check every path in the closure, and if its
cryptographic hash differs from the hash recorded in Nix's database, the
path is rebuilt or redownloaded.
You can also scan the entire Nix store for corrupt paths:
```ShellSession
# nix-store --verify --check-contents --repair
```
Any corrupt paths will be redownloaded if they're available in a binary
cache; otherwise, they cannot be repaired.

View File

@@ -0,0 +1,17 @@
# Necessary system state {#ch-system-state}
Normally — on systems with a persistent `rootfs` — system services can persist state to
the filesystem without administrator intervention.
However, it is possible and not-uncommon to create [impermanent systems], whose
`rootfs` is either a `tmpfs` or reset during boot. While NixOS itself supports
this kind of configuration, special care needs to be taken.
[impermanent systems]: https://wiki.nixos.org/wiki/Impermanence
```{=include=} sections
nixos-state.section.md
systemd-state.section.md
zfs-state.section.md
```

View File

@@ -0,0 +1,52 @@
# systemd {#sec-systemd-state}
## `machine-id(5)` {#sec-machine-id}
`systemd` uses per-machine identifier — {manpage}`machine-id(5)` — which must be
unique and persistent; otherwise, the system journal may fail to list earlier
boots, etc.
`systemd` generates a random `machine-id(5)` during boot if it does not already exist,
and persists it in `/etc/machine-id`. As such, it suffices to make that file persistent.
Alternatively, it is possible to generate a random `machine-id(5)`; while the
specification allows for *any* hex-encoded 128b value, systemd itself uses
[UUIDv4], *i.e.* random UUIDs, and it is thus preferable to do so as well, in
case some software assumes `machine-id(5)` to be a UUIDv4. Those can be
generated with `uuidgen -r | tr -d -` (`tr` being used to remove the dashes).
Such a `machine-id(5)` can be set by writing it to `/etc/machine-id` or through
the kernel's command-line, though NixOS' systemd maintainers [discourage] the
latter approach.
[UUIDv4]: https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_4_(random)
[discourage]: https://github.com/NixOS/nixpkgs/pull/268995
## `/var/lib/systemd` {#sec-var-systemd}
Moreover, `systemd` expects its state directory — `/var/lib/systemd` — to persist, for:
- {manpage}`systemd-random-seed(8)`, which loads a 256b “seed” into the kernel's RNG
at boot time, and saves a fresh one during shutdown;
- {manpage}`systemd.timer(5)` with `Persistent=yes`, which are then run after boot if
the timer would have triggered during the time the system was shut down;
- {manpage}`systemd-coredump(8)` to store core dumps there by default;
(see {manpage}`coredump.conf(5)`)
- {manpage}`systemd-timesyncd(8)`;
- {manpage}`systemd-backlight(8)` and {manpage}`systemd-rfkill(8)` persist hardware-related
state;
- possibly other things, this list is not meant to be exhaustive.
In any case, making `/var/lib/systemd` persistent is recommended.
## `/var/log/journal/{machine-id}` {#sec-var-journal}
Lastly, {manpage}`systemd-journald(8)` writes the system's journal in binary
form to `/var/log/journal/{machine-id}`; if (locally) persisting the entire log
is desired, it is recommended to make all of `/var/log/journal` persistent.
If not, one can set `Storage=volatile` in {manpage}`journald.conf(5)`
([`services.journald.storage = "volatile";`](#opt-services.journald.storage)),
which disables journal persistence and causes it to be written to
`/run/log/journal`.

View File

@@ -0,0 +1,12 @@
# Troubleshooting {#ch-troubleshooting}
This chapter describes solutions to common problems you might encounter
when you manage your NixOS system.
```{=include=} sections
boot-problems.section.md
maintenance-mode.section.md
rollback.section.md
store-corruption.section.md
network-problems.section.md
```

View File

@@ -0,0 +1,43 @@
# User Sessions {#sec-user-sessions}
Systemd keeps track of all users who are logged into the system (e.g. on
a virtual console or remotely via SSH). The command `loginctl` allows
querying and manipulating user sessions. For instance, to list all user
sessions:
```ShellSession
$ loginctl
SESSION UID USER SEAT
c1 500 eelco seat0
c3 0 root seat0
c4 500 alice
```
This shows that two users are logged in locally, while another is logged
in remotely. ("Seats" are essentially the combinations of displays and
input devices attached to the system; usually, there is only one seat.)
To get information about a session:
```ShellSession
$ loginctl session-status c3
c3 - root (0)
Since: Tue, 2013-01-08 01:17:56 CET; 4min 42s ago
Leader: 2536 (login)
Seat: seat0; vc3
TTY: /dev/tty3
Service: login; type tty; class user
State: online
CGroup: name=systemd:/user/root/c3
├─ 2536 /nix/store/10mn4xip9n7y9bxqwnsx7xwx2v2g34xn-shadow-4.1.5.1/bin/login --
├─10339 -bash
└─10355 w3m nixos.org
```
This shows that the user is logged in on virtual console 3. It also
lists the processes belonging to this session. Since systemd keeps track
of this, you can terminate a session in a way that ensures that all the
session's processes are gone:
```ShellSession
# loginctl terminate-session c3
```

View File

@@ -0,0 +1,16 @@
# ZFS {#sec-zfs-state}
When using ZFS, `/etc/zfs/zpool.cache` should be persistent (or a symlink to a persistent
location) as it is the default value for the `cachefile` [property](man:zpoolprops(7)).
This cachefile is used on system startup to discover ZFS pools, so ZFS pools
holding the `rootfs` and/or early-boot datasets such as `/nix` can be set to
`cachefile=none`.
In principle, if there are no other pools attached to the system, `zpool.cache`
does not need to be persisted; it is however *strongly recommended* to persist
it, in case additional pools are added later on, temporarily or permanently:
While mishandling the cachefile does not lead to data loss by itself, it may
cause zpools not to be imported during boot, and services may then write to a
location where a dataset was expected to be mounted.

View File

@@ -0,0 +1,4 @@
{
outputPath = "share/doc/nixos";
indexPath = "index.html";
}

View File

@@ -0,0 +1,94 @@
# Abstractions {#sec-module-abstractions}
If you find yourself repeating yourself over and over, its time to abstract. Take, for instance, this Apache HTTP Server configuration:
```nix
{
services.httpd.virtualHosts = {
"blog.example.org" = {
documentRoot = "/webroot/blog.example.org";
adminAddr = "alice@example.org";
forceSSL = true;
enableACME = true;
};
"wiki.example.org" = {
documentRoot = "/webroot/wiki.example.org";
adminAddr = "alice@example.org";
forceSSL = true;
enableACME = 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`:
```nix
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.org"; });
};
}
```
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:
```nix
{
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:
```nix
{
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.

View File

@@ -0,0 +1,14 @@
# Ad-Hoc Configuration {#ad-hoc-network-config}
You can use [](#opt-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:
```nix
{
networking.localCommands = ''
ip -6 addr add 2001:610:685:1::1/64 dev eth0
'';
}
```

View File

@@ -0,0 +1,51 @@
# Ad-Hoc Package Management {#sec-ad-hoc-packages}
With the command `nix-env`, you can install and uninstall packages from
the command line. For instance, to install Mozilla Thunderbird:
```ShellSession
$ 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:
```ShellSession
$ 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:
```ShellSession
$ nix-env -u '*'
```
A package can be uninstalled using the `-e` flag:
```ShellSession
$ nix-env -e thunderbird
```
Finally, you can roll back an undesirable `nix-env` action:
```ShellSession
$ nix-env --rollback
```
`nix-env` has many more flags. For details, see the nix-env(1) manpage or
the Nix manual.

View File

@@ -0,0 +1,119 @@
# Adding Custom Packages {#sec-custom-packages}
It's possible that a package you need is not available in NixOS. In that
case, you can do two things. Either you can package it with Nix, or you can try
to use prebuilt packages from upstream. Due to the peculiarities of NixOS, it
is important to note that building software from source is often easier than
using pre-built executables.
## Building with Nix {#sec-custom-packages-nix}
This can be done either in-tree or out-of-tree. For an in-tree build, 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](https://nixos.org/nixpkgs/manual). In short, you clone Nixpkgs:
```ShellSession
$ 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 [](#opt-environment.systemPackages), e.g.
```nix
{ environment.systemPackages = [ pkgs.my-package ]; }
```
and you run `nixos-rebuild`, specifying your own Nixpkgs tree:
```ShellSession
# 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](https://www.gnu.org/software/hello/) package directly in
`configuration.nix`:
```nix
{
environment.systemPackages =
let
my-hello =
with pkgs;
stdenv.mkDerivation rec {
name = "hello-2.8";
src = fetchurl {
url = "mirror://gnu/hello/${name}.tar.gz";
hash = "sha256-5rd/gffPfa761Kn1tl3myunD8TuM+66oy1O7XqVGDXM=";
};
};
in
[ my-hello ];
}
```
Of course, you can also move the definition of `my-hello` into a
separate Nix expression, e.g.
```nix
{ environment.systemPackages = [ (import ./my-hello.nix) ]; }
```
where `my-hello.nix` contains:
```nix
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";
hash = "sha256-5rd/gffPfa761Kn1tl3myunD8TuM+66oy1O7XqVGDXM=";
};
}
```
This allows testing the package easily:
```ShellSession
$ nix-build my-hello.nix
$ ./result/bin/hello
Hello, world!
```
## Using pre-built executables {#sec-custom-packages-prebuilt}
Most pre-built executables will not work on NixOS. There are two notable
exceptions: flatpaks and AppImages. For flatpaks see the [dedicated
section](#module-services-flatpak). AppImages can run "as-is" on NixOS.
First you need to enable AppImage support: add to `/etc/nixos/configuration.nix`
```nix
{
programs.appimage.enable = true;
programs.appimage.binfmt = true;
}
```
Then you can run the AppImage "as-is" or with `appimage-run foo.appimage`.
If there are shared libraries missing add them with
```nix
{
programs.appimage.package = pkgs.appimage-run.override {
extraPkgs = pkgs: [
# missing libraries here, e.g.: `pkgs.libepoxy`
];
};
}
```
To make other pre-built executables work on NixOS, you need to package them
with Nix and special helpers like `autoPatchelfHook` or `buildFHSEnv`. See
the [Nixpkgs manual](https://nixos.org/nixpkgs/manual) for details. This
is complex and often doing a source build is easier.

View File

@@ -0,0 +1,194 @@
# NixOS Configuration File {#sec-configuration-file}
The NixOS configuration file generally looks like this:
```nix
{ 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, in chapter [](#sec-writing-modules)) 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,
```nix
{ 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,
[](#opt-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:
```nix
{ 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:
```plain
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:
```plain
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.
```nix
{
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.
```nix
{
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](https://nixos.org/nix/manual/#ssec-values).
Booleans
: These can be `true` or `false`, e.g.
```nix
{
networking.firewall.enable = true;
networking.firewall.allowPing = false;
}
```
Integers
: For example,
```nix
{
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
```nix
{
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:
```nix
{
boot.kernelModules = [ "fuse" "kvm-intel" "coretemp" ];
}
```
List elements can be any other type, e.g. sets:
```nix
{
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:
```nix
{
environment.systemPackages =
[ pkgs.thunderbird
pkgs.emacs
];
services.postgresql.package = pkgs.postgresql_14;
}
```
The latter option definition changes the default PostgreSQL package
used by NixOS's PostgreSQL service to 14.x. For more information on
packages, including how to add new ones, see
[](#sec-custom-packages).

View File

@@ -0,0 +1,18 @@
# Configuration Syntax {#sec-configuration-syntax}
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](https://nixos.org/nix/manual/#chap-writing-nix-expressions), but
here we give a short overview of the most important constructs useful in
NixOS configuration files.
```{=include=} sections
config-file.section.md
abstractions.section.md
modularity.section.md
```

View File

@@ -0,0 +1,28 @@
# Configuration {#ch-configuration}
This chapter describes how to configure various aspects of a NixOS machine through the configuration file {file}`/etc/nixos/configuration.nix`. As described in [](#sec-changing-config), changes to this file only take effect after you run {command}`nixos-rebuild`.
```{=include=} chapters
config-syntax.chapter.md
package-mgmt.chapter.md
user-mgmt.chapter.md
file-systems.chapter.md
x-windows.chapter.md
wayland.chapter.md
gpu-accel.chapter.md
xfce.chapter.md
networking.chapter.md
linux-kernel.chapter.md
subversion.chapter.md
```
```{=include=} chapters
@MODULE_CHAPTERS@
```
```{=include=} chapters
profiles.chapter.md
mattermost.chapter.md
kubernetes.chapter.md
```
<!-- Apache; libvirtd virtualisation -->

View File

@@ -0,0 +1,121 @@
# Customising Packages {#sec-customising-packages}
The Nixpkgs configuration for a NixOS system is set by the {option}`nixpkgs.config` option.
::::{.example}
# Globally allow unfree packages
```nix
{
nixpkgs.config = {
allowUnfree = true;
};
}
```
:::{.note}
This only allows unfree software in the given NixOS configuration.
For users invoking Nix commands such as [`nix-build`](https://nixos.org/manual/nix/stable/command-ref/nix-build), Nixpkgs is configured independently.
See the [Nixpkgs manual section on global configuration](https://nixos.org/manual/nixpkgs/unstable/#chap-packageconfig) for details.
:::
::::
<!-- TODO(@fricklerhandwerk)
all of the following should go to the Nixpkgs manual, it has nothing to do with NixOS
-->
Some packages in Nixpkgs have options to enable or disable optional functionality, or change other aspects of the package.
::: {.warning}
Unfortunately, Nixpkgs currently lacks a way to query available package configuration options.
:::
::: {.note}
For example, many packages come with extensions one might add.
Examples include:
- [`passExtensions.pass-otp`](https://search.nixos.org/packages?query=passExtensions.pass-otp)
- [`python312Packages.requests`](https://search.nixos.org/packages?query=python312Packages.requests)
You can use them like this:
```nix
{
environment.systemPackages = with pkgs; [
sl
(pass.withExtensions (
subpkgs: with subpkgs; [
pass-audit
pass-otp
pass-genphrase
]
))
(python3.withPackages (subpkgs: with subpkgs; [ requests ]))
cowsay
];
}
```
:::
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:
```nix
{ 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,
[](#opt-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:
```nix
{
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:
```nix
{
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.)

View File

@@ -0,0 +1,46 @@
# Declarative Package Management {#sec-declarative-package-mgmt}
With declarative package management, you specify which packages you want
on your system by setting the option
[](#opt-environment.systemPackages). For instance, adding the
following line to `configuration.nix` enables the Mozilla Thunderbird
email application:
```nix
{ 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
[](#opt-environment.systemPackages) might not be sufficient. You are
advised to check the [list of options](#ch-options) whether a NixOS
module for the package does not exist.
:::
You can get a list of the available packages as follows:
```ShellSession
$ 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, remove it from
[](#opt-environment.systemPackages) and run `nixos-rebuild switch`.
```{=include=} sections
customizing-packages.section.md
adding-custom-packages.section.md
```

View File

@@ -0,0 +1,45 @@
# File Systems {#ch-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`:
```nix
{
fileSystems."/data" = {
device = "/dev/disk/by-label/data";
fsType = "ext4";
};
}
```
This will create an entry in `/etc/fstab`, which will generate a
corresponding [systemd.mount](https://www.freedesktop.org/software/systemd/man/systemd.mount.html)
unit via [systemd-fstab-generator](https://www.freedesktop.org/software/systemd/man/systemd-fstab-generator.html).
The filesystem will be mounted automatically unless `"noauto"` is
present in [options](#opt-fileSystems._name_.options). `"noauto"`
filesystems can be mounted explicitly using `systemctl` e.g.
`systemctl start data.mount`. 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" ];`.
:::
```{=include=} sections
luks-file-systems.section.md
sshfs-file-systems.section.md
overlayfs.section.md
```

View File

@@ -0,0 +1,45 @@
# Firewall {#sec-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:
```nix
{ networking.firewall.enable = false; }
```
If the firewall is enabled, you can open specific TCP ports to the
outside world:
```nix
{
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
[](#opt-networking.firewall.allowedUDPPorts).
To open ranges of TCP ports:
```nix
{
networking.firewall.allowedTCPPortRanges = [
{
from = 4000;
to = 4007;
}
{
from = 8000;
to = 8010;
}
];
}
```
Similarly, UDP port ranges can be opened through
[](#opt-networking.firewall.allowedUDPPortRanges).

View File

@@ -0,0 +1,197 @@
# GPU acceleration {#sec-gpu-accel}
NixOS provides various APIs that benefit from GPU hardware acceleration,
such as VA-API and VDPAU for video playback; OpenGL and Vulkan for 3D
graphics; and OpenCL for general-purpose computing. This chapter
describes how to set up GPU hardware acceleration (as far as this is not
done automatically) and how to verify that hardware acceleration is
indeed used.
Most of the aforementioned APIs are agnostic with regards to which
display server is used. Consequently, these instructions should apply
both to the X Window System and Wayland compositors.
## OpenCL {#sec-gpu-accel-opencl}
[OpenCL](https://en.wikipedia.org/wiki/OpenCL) is a general compute API.
It is used by various applications such as Blender and Darktable to
accelerate certain operations.
OpenCL applications load drivers through the *Installable Client Driver*
(ICD) mechanism. In this mechanism, an ICD file specifies the path to
the OpenCL driver for a particular GPU family. In NixOS, there are two
ways to make ICD files visible to the ICD loader. The first is through
the `OCL_ICD_VENDORS` environment variable. This variable can contain a
directory which is scanned by the ICL loader for ICD files. For example:
```ShellSession
$ export \
OCL_ICD_VENDORS=`nix-build '<nixpkgs>' --no-out-link -A rocmPackages.clr.icd`/etc/OpenCL/vendors/
```
The second mechanism is to add the OpenCL driver package to
[](#opt-hardware.graphics.extraPackages).
This links the ICD file under `/run/opengl-driver`, where it will be visible
to the ICD loader.
The proper installation of OpenCL drivers can be verified through the
`clinfo` command of the clinfo package. This command will report the
number of hardware devices that is found and give detailed information
for each device:
```ShellSession
$ clinfo | head -n3
Number of platforms 1
Platform Name AMD Accelerated Parallel Processing
Platform Vendor Advanced Micro Devices, Inc.
```
### AMD {#sec-gpu-accel-opencl-amd}
Modern AMD [Graphics Core
Next](https://en.wikipedia.org/wiki/Graphics_Core_Next) (GCN) GPUs are
supported through the rocmPackages.clr.icd package. Adding this package to
[](#opt-hardware.graphics.extraPackages)
enables OpenCL support:
```nix
{ hardware.graphics.extraPackages = [ rocmPackages.clr.icd ]; }
```
### Intel {#sec-gpu-accel-opencl-intel}
[Intel Gen12 and later GPUs](https://en.wikipedia.org/wiki/List_of_Intel_graphics_processing_units#Gen12)
are supported by the Intel NEO OpenCL runtime that is provided by the `intel-compute-runtime` package.
The previous generations (8,9 and 11), have been moved to the `intel-compute-runtime-legacy1` package.
The proprietary Intel OpenCL runtime, in the `intel-ocl` package, is an alternative for Gen7 GPUs.
Both `intel-compute-runtime` packages, as well as the `intel-ocl` package can be added to
[](#opt-hardware.graphics.extraPackages)
to enable OpenCL support. For example, for Gen12 and later GPUs, the following
configuration can be used:
```nix
{ hardware.graphics.extraPackages = [ intel-compute-runtime ]; }
```
## Vulkan {#sec-gpu-accel-vulkan}
[Vulkan](https://en.wikipedia.org/wiki/Vulkan_(API)) is a graphics and
compute API for GPUs. It is used directly by games or indirectly though
compatibility layers like
[DXVK](https://github.com/doitsujin/dxvk/wiki).
By default, if [](#opt-hardware.graphics.enable)
is enabled, Mesa is installed and provides Vulkan for supported hardware.
Similar to OpenCL, Vulkan drivers are loaded through the *Installable
Client Driver* (ICD) mechanism. ICD files for Vulkan are JSON files that
specify the path to the driver library and the supported Vulkan version.
All successfully loaded drivers are exposed to the application as
different GPUs. In NixOS, there are two ways to make ICD files visible
to Vulkan applications: an environment variable and a module option.
The way to do this is to add the Vulkan driver package to
[](#opt-hardware.graphics.extraPackages).
This links the ICD file under `/run/opengl-driver`, where it will be
visible to the ICD loader.
The proper installation of Vulkan drivers can be verified through the
`vulkaninfo` command of the vulkan-tools package. This command will
report the hardware devices and drivers found, in this example output
amdvlk and radv:
```ShellSession
$ vulkaninfo | grep GPU
GPU id : 0 (Unknown AMD GPU)
GPU id : 1 (AMD RADV NAVI10 (LLVM 9.0.1))
...
GPU0:
deviceType = PHYSICAL_DEVICE_TYPE_DISCRETE_GPU
deviceName = Unknown AMD GPU
GPU1:
deviceType = PHYSICAL_DEVICE_TYPE_DISCRETE_GPU
```
A simple graphical application that uses Vulkan is `vkcube` from the
vulkan-tools package.
### AMD {#sec-gpu-accel-vulkan-amd}
Modern AMD [Graphics Core
Next](https://en.wikipedia.org/wiki/Graphics_Core_Next) (GCN) GPUs are
supported through the RADV driver, which is part of mesa.
## VA-API {#sec-gpu-accel-va-api}
[VA-API (Video Acceleration API)](https://www.intel.com/content/www/us/en/developer/articles/technical/linuxmedia-vaapi.html)
is an open-source library and API specification, which provides access to
graphics hardware acceleration capabilities for video processing.
VA-API drivers are loaded by `libva`. The version in nixpkgs is built to search
the opengl driver path, so drivers can be installed in
[](#opt-hardware.graphics.extraPackages).
VA-API can be tested using:
```ShellSession
$ nix-shell -p libva-utils --run vainfo
```
### Intel {#sec-gpu-accel-va-api-intel}
Modern Intel GPUs use the iHD driver, which can be installed with:
```nix
{ hardware.graphics.extraPackages = [ intel-media-driver ]; }
```
Older Intel GPUs use the i965 driver, which can be installed with:
```nix
{ hardware.graphics.extraPackages = [ intel-vaapi-driver ]; }
```
## Common issues {#sec-gpu-accel-common-issues}
### User permissions {#sec-gpu-accel-common-issues-permissions}
Except where noted explicitly, it should not be necessary to adjust user
permissions to use these acceleration APIs. In the default
configuration, GPU devices have world-read/write permissions
(`/dev/dri/renderD*`) or are tagged as `uaccess` (`/dev/dri/card*`). The
access control lists of devices with the `uaccess` tag will be updated
automatically when a user logs in through `systemd-logind`. For example,
if the user *alice* is logged in, the access control list should look as
follows:
```ShellSession
$ getfacl /dev/dri/card0
# file: dev/dri/card0
# owner: root
# group: video
user::rw-
user:alice:rw-
group::rw-
mask::rw-
other::---
```
If you disabled (this functionality of) `systemd-logind`, you may need
to add the user to the `video` group and log in again.
### Mixing different versions of nixpkgs {#sec-gpu-accel-common-issues-mixing-nixpkgs}
The *Installable Client Driver* (ICD) mechanism used by OpenCL and
Vulkan loads runtimes into its address space using `dlopen`. Mixing an
ICD loader mechanism and runtimes from different version of nixpkgs may
not work. For example, if the ICD loader uses an older version of glibc
than the runtime, the runtime may not be loadable due to missing
symbols. Unfortunately, the loader will generally be quiet about such
issues.
If you suspect that you are running into library version mismatches
between an ICL loader and a runtime, you could run an application with
the `LD_DEBUG` variable set to get more diagnostic information. For
example, OpenCL can be tested with `LD_DEBUG=files clinfo`, which should
report missing symbols.

View File

@@ -0,0 +1,41 @@
# IPv4 Configuration {#sec-ipv4}
By default, NixOS uses DHCP (specifically, `dhcpcd`) to automatically
configure network interfaces. However, you can configure an interface
manually as follows:
```nix
{
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:
```nix
{
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 [](#opt-networking.hostName):
```nix
{ 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.

View File

@@ -0,0 +1,48 @@
# IPv6 Configuration {#sec-ipv6}
IPv6 is enabled by default. Stateless address autoconfiguration is used
to automatically assign IPv6 addresses to all interfaces, and Privacy
Extensions (RFC 4941) are enabled by default. You can adjust the default
for this by setting [](#opt-networking.tempAddresses). This option
may be overridden on a per-interface basis by
[](#opt-networking.interfaces._name_.tempAddress). You can disable
IPv6 support globally by setting:
```nix
{ networking.enableIPv6 = false; }
```
You can disable IPv6 on a single interface using a normal sysctl (in
this example, we use interface `eth0`):
```nix
{ 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:
```nix
{
networking.interfaces.eth0.ipv6.addresses = [
{
address = "fe00:aa:bb:cc::2";
prefixLength = 64;
}
];
}
```
For configuring a gateway, optionally with explicitly specified
interface:
```nix
{
networking.defaultGateway6 = {
address = "fe00::1";
interface = "enp0s3";
};
}
```
See [](#sec-ipv4) for similar examples and additional information.

View File

@@ -0,0 +1,103 @@
# Kubernetes {#sec-kubernetes}
The NixOS Kubernetes module is a collective term for a handful of
individual submodules implementing the Kubernetes cluster components.
There are generally two ways of enabling Kubernetes on NixOS. One way is
to enable and configure cluster components appropriately by hand:
```nix
{
services.kubernetes = {
apiserver.enable = true;
controllerManager.enable = true;
scheduler.enable = true;
addonManager.enable = true;
proxy.enable = true;
flannel.enable = true;
};
}
```
Another way is to assign cluster roles ("master" and/or "node") to
the host. This enables apiserver, controllerManager, scheduler,
addonManager, kube-proxy and etcd:
```nix
{ services.kubernetes.roles = [ "master" ]; }
```
While this will enable the kubelet and kube-proxy only:
```nix
{ services.kubernetes.roles = [ "node" ]; }
```
Assigning both the master and node roles is usable if you want a single
node Kubernetes cluster for dev or testing purposes:
```nix
{
services.kubernetes.roles = [
"master"
"node"
];
}
```
Note: Assigning either role will also default both
[](#opt-services.kubernetes.flannel.enable)
and [](#opt-services.kubernetes.easyCerts)
to true. This sets up flannel as CNI and activates automatic PKI bootstrapping.
::: {.note}
It is mandatory to configure:
[](#opt-services.kubernetes.masterAddress).
The masterAddress must be resolvable and routable by all cluster nodes.
In single node clusters, this can be set to `localhost`.
:::
Role-based access control (RBAC) authorization mode is enabled by
default. This means that anonymous requests to the apiserver secure port
will expectedly cause a permission denied error. All cluster components
must therefore be configured with x509 certificates for two-way tls
communication. The x509 certificate subject section determines the roles
and permissions granted by the apiserver to perform clusterwide or
namespaced operations. See also: [ Using RBAC
Authorization](https://kubernetes.io/docs/reference/access-authn-authz/rbac/).
The NixOS kubernetes module provides an option for automatic certificate
bootstrapping and configuration,
[](#opt-services.kubernetes.easyCerts).
The PKI bootstrapping process involves setting up a certificate authority (CA)
daemon (cfssl) on the kubernetes master node. cfssl generates a CA-cert
for the cluster, and uses the CA-cert for signing subordinate certs issued
to each of the cluster components. Subsequently, the certmgr daemon monitors
active certificates and renews them when needed. For single node Kubernetes
clusters, setting [](#opt-services.kubernetes.easyCerts)
= true is sufficient and no further action is required. For joining extra node
machines to an existing cluster on the other hand, establishing initial
trust is mandatory.
To add new nodes to the cluster: On any (non-master) cluster node where
[](#opt-services.kubernetes.easyCerts)
is enabled, the helper script `nixos-kubernetes-node-join` is available on PATH.
Given a token on stdin, it will copy the token to the kubernetes secrets directory
and restart the certmgr service. As requested certificates are issued, the
script will restart kubernetes cluster components as needed for them to
pick up new keypairs.
::: {.note}
Multi-master (HA) clusters are not supported by the easyCerts module.
:::
In order to interact with an RBAC-enabled cluster as an administrator,
one needs to have cluster-admin privileges. By default, when easyCerts
is enabled, a cluster-admin kubeconfig file is generated and linked into
`/etc/kubernetes/cluster-admin.kubeconfig` as determined by
[](#opt-services.kubernetes.pki.etcClusterAdminKubeconfig).
`export KUBECONFIG=/etc/kubernetes/cluster-admin.kubeconfig` will make
kubectl use this kubeconfig to access and authenticate the cluster. The
cluster-admin kubeconfig references an auto-generated keypair owned by
root. Thus, only root on the kubernetes master may obtain cluster-admin
rights by means of this file.

View File

@@ -0,0 +1,139 @@
# Linux Kernel {#sec-kernel-config}
You can override the Linux kernel and associated packages using the
option `boot.kernelPackages`. For instance, this selects the Linux 3.10
kernel:
```nix
{ boot.kernelPackages = pkgs.linuxKernel.packages.linux_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.
While `pkgs.linuxKernel.packages` contains all available kernel packages,
you may want to use one of the unversioned `pkgs.linuxPackages_*` aliases
such as `pkgs.linuxPackages_latest`, that are kept up to date with new
versions.
Please note that the current convention in NixOS is to only keep actively
maintained kernel versions on both unstable and the currently supported stable
release(s) of NixOS. This means that a non-longterm kernel will be removed after it's
abandoned by the kernel developers, even on stable NixOS versions. If you
pin your kernel onto a non-longterm version, expect your evaluation to fail as
soon as the version is out of maintenance.
A kernel will be removed from nixpkgs when the first batch of stable kernels
_after_ the final release is published. E.g. when 6.15.11 is the final release
of the 6.15 series and is released together with 6.16.3 and 6.12.43, it will be
removed on the release of 6.16.4 and 6.12.44. Custom kernel variants such
as linux-hardened are also affected by this.
Longterm versions of kernels will be removed before the next stable NixOS that will
exceed the maintenance period of the kernel version.
The default Linux kernel configuration should be fine for most users.
You can see the configuration of your current kernel with the following
command:
```ShellSession
zcat /proc/config.gz
```
If you want to change the kernel configuration, you can use the
`packageOverrides` feature (see [](#sec-customising-packages)). For
instance, to enable support for the kernel debugger KGDB:
```nix
{
nixpkgs.config.packageOverrides =
pkgs:
pkgs.lib.recursiveUpdate pkgs {
linuxKernel.kernels.linux_5_10 = pkgs.linuxKernel.kernels.linux_5_10.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
[](#opt-boot.kernelModules), e.g.
```nix
{
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 [](#opt-boot.initrd.kernelModules):
```nix
{ 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
[](#opt-boot.kernel.sysctl), e.g.
```nix
{ 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`.
## Building a custom kernel {#sec-linux-config-customizing}
Please refer to the Nixpkgs manual for the various ways of [building a custom kernel](https://nixos.org/nixpkgs/manual#sec-linux-kernel).
To use your custom kernel package in your NixOS configuration, set
```nix
{ boot.kernelPackages = pkgs.linuxPackagesFor yourCustomKernel; }
```
## Rust {#sec-linux-rust}
The Linux kernel does not have Rust language support enabled by
default. For kernel versions 6.7 or newer, experimental Rust support
can be enabled. In a NixOS configuration, set:
```nix
{
boot.kernelPatches = [
{
name = "Rust Support";
patch = null;
features = {
rust = true;
};
}
];
}
```
## Developing kernel modules {#sec-linux-config-developing-modules}
This section was moved to the [Nixpkgs manual](https://nixos.org/nixpkgs/manual#sec-linux-kernel-developing-modules).
## ZFS {#sec-linux-zfs}
It's a common issue that the latest stable version of ZFS doesn't support the latest
available Linux kernel. It is recommended to use the latest available LTS that's compatible
with ZFS. Usually this is the default kernel provided by nixpkgs (i.e. `pkgs.linuxPackages`).

View File

@@ -0,0 +1,122 @@
# LUKS-Encrypted File Systems {#sec-luks-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`:
```ShellSession
# 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
```
The LUKS volume should be automatically picked up by
`nixos-generate-config`, but you might want to verify that your
`hardware-configuration.nix` looks correct. To manually ensure that the
system is automatically mounted at boot time as `/`, add the following
to `configuration.nix`:
```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:
```nix
{ boot.loader.grub.enableCryptodisk = true; }
```
## FIDO2 {#sec-luks-file-systems-fido2}
NixOS also supports unlocking your LUKS-Encrypted file system using a FIDO2
compatible token.
### Without systemd in initrd {#sec-luks-file-systems-fido2-legacy}
In the following example, we will create a new
FIDO2 credential and add it as a new key to our existing device
`/dev/sda2`:
```ShellSession
# 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`:
```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](https://trezor.io/).
```nix
{ boot.initrd.luks.devices."/dev/sda2".fido2.passwordLess = true; }
```
### systemd Stage 1 {#sec-luks-file-systems-fido2-systemd}
If systemd stage 1 is enabled, it handles unlocking of LUKS-encrypted volumes
during boot. The following example enables systemd stage1 and adds support for
unlocking the existing LUKS2 volume `root` using any enrolled FIDO2 compatible
tokens.
```nix
{
boot.initrd = {
luks.devices.root = {
crypttabExtraOpts = [ "fido2-device=auto" ];
device = "/dev/sda2";
};
systemd.enable = true;
};
}
```
All tokens that should be used for unlocking the LUKS2-encrypted volume must
first be enrolled using [systemd-cryptenroll](https://www.freedesktop.org/software/systemd/man/systemd-cryptenroll.html).
In the following example, a new key slot for the first discovered token is
added to the LUKS volume.
```ShellSession
# systemd-cryptenroll --fido2-device=auto /dev/sda2
```
Existing key slots are left intact, unless `--wipe-slot=` is specified. It is
recommended to add a recovery key that should be stored in a secure physical
location and can be entered wherever a password would be entered.
```ShellSession
# systemd-cryptenroll --recovery-key /dev/sda2
```

View File

@@ -0,0 +1,132 @@
# Mattermost {#sec-mattermost}
The NixOS Mattermost module lets you build [Mattermost](https://mattermost.com)
instances for collaboration over chat, optionally with custom builds of plugins
specific to your instance.
To enable Mattermost using Postgres, use a config like this:
```nix
{
services.mattermost = {
enable = true;
# You can change this if you are reverse proxying.
host = "0.0.0.0";
port = 8065;
# Allow modifications to the config from Mattermost.
mutableConfig = true;
# Override modifications to the config with your NixOS config.
preferNixConfig = true;
socket = {
# Enable control with the `mmctl` socket.
enable = true;
# Exporting the control socket will add `mmctl` to your PATH, and export
# MMCTL_LOCAL_SOCKET_PATH systemwide. Otherwise, you can get the socket
# path out of `config.mattermost.socket.path` and set it manually.
export = true;
};
# For example, to disable auto-installation of prepackaged plugins.
settings.PluginSettings.AutomaticPrepackagedPlugins = false;
};
}
```
As of NixOS 25.05, Mattermost uses peer authentication with Postgres or
MySQL by default. If you previously used password auth on localhost,
this will automatically be configured if your `stateVersion` is set to at least
`25.05`.
## Using the Mattermost derivation {#sec-mattermost-derivation}
The nixpkgs `mattermost` derivation runs the entire test suite during the
`checkPhase`. This test suite is run with a live MySQL and Postgres database
instance in the sandbox. If you are building Mattermost, this can take a while,
especially if it is building on a resource-constrained system.
The following passthrus are designed to assist with enabling or disabling
the `checkPhase`:
- `mattermost.withTests`
- `mattermost.withoutTests`
The default (`mattermost`) is an alias for `mattermost.withTests`.
## Using Mattermost plugins {#sec-mattermost-plugins}
You can configure Mattermost plugins by either using prebuilt binaries or by
building your own. We test building and using plugins in the NixOS test suite.
Mattermost plugins are tarballs containing a system-specific statically linked
Go binary and webapp resources.
Here is an example with a prebuilt plugin tarball:
```nix
{
services.mattermost = {
plugins = with pkgs; [
# todo
# 0.7.1
# https://github.com/mattermost/mattermost-plugin-todo/releases/tag/v0.7.1
(fetchurl {
# Note: Don't unpack the tarball; the NixOS module will repack it for you.
url = "https://github.com/mattermost-community/mattermost-plugin-todo/releases/download/v0.7.1/com.mattermost.plugin-todo-0.7.1.tar.gz";
hash = "sha256-P+Z66vqE7FRmc2kTZw9FyU5YdLLbVlcJf11QCbfeJ84=";
})
];
};
}
```
Once the plugin is installed and the config rebuilt, you can enable this plugin
in the System Console.
## Building Mattermost plugins {#sec-mattermost-plugins-build}
The `mattermost` derivation includes the `buildPlugin` passthru for building
plugins that use the "standard" Mattermost plugin build template at
[mattermost-plugin-demo](https://github.com/mattermost/mattermost-plugin-demo).
Since this is a "de facto" standard for building Mattermost plugins that makes
assumptions about the build environment, the `buildPlugin` helper tries to fit
these assumptions the best it can.
Here is how to build the above Todo plugin. Note that we rely on
package-lock.json being assembled correctly, so must use a version where it is!
If there is no lockfile or the lockfile is incorrect, Nix cannot fetch NPM build
and runtime dependencies for a sandbox build.
```nix
{
services.mattermost = {
plugins = with pkgs; [
(mattermost.buildPlugin {
pname = "mattermost-plugin-todo";
version = "0.8-pre";
src = fetchFromGitHub {
owner = "mattermost-community";
repo = "mattermost-plugin-todo";
# 0.7.1 didn't work, seems to use an older set of node dependencies.
rev = "f25dc91ea401c9f0dcd4abcebaff10eb8b9836e5";
hash = "sha256-OM+m4rTqVtolvL5tUE8RKfclqzoe0Y38jLU60Pz7+HI=";
};
vendorHash = "sha256-5KpechSp3z/Nq713PXYruyNxveo6CwrCSKf2JaErbgg=";
npmDepsHash = "sha256-o2UOEkwb8Vx2lDWayNYgng0GXvmS6lp/ExfOq3peyMY=";
extraGoModuleAttrs = {
npmFlags = [ "--legacy-peer-deps" ];
};
})
];
};
}
```
See `pkgs/by-name/ma/mattermost/build-plugin.nix` for all the options.
As in the previous example, once the plugin is installed and the config rebuilt,
you can enable this plugin in the System Console.

View File

@@ -0,0 +1,142 @@
# Modularity {#sec-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.:
```nix
{ 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:
```nix
{ config, pkgs, ... }:
{
services.xserver.enable = true;
services.displayManager.sddm.enable = true;
services.desktopManager.plasma6.enable = true;
environment.systemPackages = [ pkgs.vim ];
}
```
Note that both `configuration.nix` and `kde.nix` define the option
[](#opt-environment.systemPackages). When multiple modules define an
option, NixOS will try to *merge* the definitions. In the case of
[](#opt-environment.systemPackages) the lists of packages will 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`:
```nix
{ 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 [](#opt-services.httpd.adminAddr),
`nixos-rebuild` will give an error:
```plain
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:
```nix
{ 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. (If 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
[](#opt-environment.systemPackages) only if
[](#opt-services.xserver.enable) is set to `true` somewhere else:
```nix
{ 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:
```ShellSession
$ 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:
```ShellSession
$ 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.
```nix
{ config, pkgs, ... }:
let
netConfig = hostName: {
networking.hostName = hostName;
networking.useDHCP = false;
};
in
{
imports = [ (netConfig "nixos.localdomain") ];
}
```

View File

@@ -0,0 +1,46 @@
# NetworkManager {#sec-networkmanager}
To facilitate network configuration, some desktop environments use
NetworkManager. You can enable NetworkManager by setting:
```nix
{ 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:
```nix
{ 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
[](#opt-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:
```nix
{
networking.networkmanager.unmanaged = [
"*"
"except:type:wwan"
"except:type:gsm"
];
}
```
Refer to the option description for the exact syntax and references to
external documentation.
:::

View File

@@ -0,0 +1,16 @@
# Networking {#sec-networking}
This section describes how to configure networking components
on your NixOS machine.
```{=include=} sections
network-manager.section.md
ssh.section.md
ipv4-config.section.md
ipv6-config.section.md
firewall.section.md
wireless.section.md
ad-hoc-network-config.section.md
renaming-interfaces.section.md
```
<!-- TODO: OpenVPN, NAT -->

View File

@@ -0,0 +1,29 @@
# Overlayfs {#sec-overlayfs}
NixOS offers a convenient abstraction to create both read-only as well writable
overlays.
```nix
{
fileSystems = {
"/writable-overlay" = {
overlay = {
lowerdir = [ writableOverlayLowerdir ];
upperdir = "/.rw-writable-overlay/upper";
workdir = "/.rw-writable-overlay/work";
};
# Mount the writable overlay in the initrd.
neededForBoot = true;
};
"/readonly-overlay".overlay.lowerdir = [
writableOverlayLowerdir
writableOverlayLowerdir2
];
};
}
```
If `upperdir` and `workdir` are not null, they will be created before the
overlay is mounted.
To mount an overlay as read-only, you need to provide at least two `lowerdir`s.

View File

@@ -0,0 +1,18 @@
# Package Management {#sec-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.
```{=include=} sections
declarative-packages.section.md
ad-hoc-packages.section.md
```

View File

@@ -0,0 +1,33 @@
# Profiles {#ch-profiles}
In some cases, it may be desirable to take advantage of commonly-used,
predefined configurations provided by nixpkgs, but different from those
that come as default. This is a role fulfilled by NixOS's Profiles,
which come as files living in `<nixpkgs/nixos/modules/profiles>`. That
is to say, expected usage is to add them to the imports list of your
`/etc/configuration.nix` as such:
```nix
{ imports = [ <nixpkgs/nixos/modules/profiles/profile-name.nix> ]; }
```
Even if some of these profiles seem only useful in the context of
install media, many are actually intended to be used in real installs.
What follows is a brief explanation of the purpose and use-case for each
profile. Detailing each option configured by each one is out of scope.
```{=include=} sections
profiles/all-hardware.section.md
profiles/base.section.md
profiles/clone-config.section.md
profiles/demo.section.md
profiles/docker-container.section.md
profiles/graphical.section.md
profiles/hardened.section.md
profiles/headless.section.md
profiles/installation-device.section.md
profiles/perlless.section.md
profiles/minimal.section.md
profiles/qemu-guest.section.md
```

View File

@@ -0,0 +1,11 @@
# All Hardware {#sec-profile-all-hardware}
Enables all hardware supported by NixOS: i.e., all firmware is included, and
all devices from which one may boot are enabled in the initrd. Its primary
use is in the NixOS installation CDs.
The enabled kernel modules include support for SATA and PATA, SCSI
(partially), USB, Firewire (untested), Virtio (QEMU, KVM, etc.), VMware, and
Hyper-V. Additionally, [](#opt-hardware.enableAllFirmware) is
enabled, and the firmware for the ZyDAS ZD1211 chipset is specifically
installed.

View File

@@ -0,0 +1,7 @@
# Base {#sec-profile-base}
Defines the software packages included in the "minimal" installation CD. It
installs several utilities useful in a simple recovery or install media, such
as a text-mode web browser, and tools for manipulating block devices,
networking, hardware diagnostics, and filesystems (with their respective
kernel modules).

View File

@@ -0,0 +1,11 @@
# Clone Config {#sec-profile-clone-config}
This profile is used in installer images. It provides an editable
configuration.nix that imports all the modules that were also used when
creating the image in the first place. As a result it allows users to edit
and rebuild the live-system.
On images where the installation media also becomes an installation target,
copying over `configuration.nix` should be disabled by
setting `installer.cloneConfig` to `false`.
For example, this is done in `sd-image-aarch64-installer.nix`.

View File

@@ -0,0 +1,4 @@
# Demo {#sec-profile-demo}
This profile just enables a `demo` user, with password `demo`, uid `1000`, `wheel` group and
[autologin in the SDDM display manager](#opt-services.displayManager.autoLogin).

View File

@@ -0,0 +1,7 @@
# Docker Container {#sec-profile-docker-container}
This is the profile from which the Docker images are generated. It prepares a
working system by importing the [Minimal](#sec-profile-minimal) and
[Clone Config](#sec-profile-clone-config) profiles, and
setting appropriate configuration options that are useful inside a container
context, like [](#opt-boot.isContainer).

View File

@@ -0,0 +1,10 @@
# Graphical {#sec-profile-graphical}
Defines a NixOS configuration with the Plasma 6 desktop. It's used by the
graphical installation CD.
It sets [](#opt-services.xserver.enable),
[](#opt-services.displayManager.sddm.enable),
[](#opt-services.desktopManager.plasma6.enable),
and [](#opt-services.libinput.enable) to true. It also
includes glxinfo and firefox in the system packages list.

View File

@@ -0,0 +1,20 @@
# Hardened {#sec-profile-hardened}
A profile with most (vanilla) hardening options enabled by default,
potentially at the cost of stability, features and performance.
This includes a hardened kernel, and limiting the system information
available to processes through the `/sys` and
`/proc` filesystems. It also disables the User Namespaces
feature of the kernel, which stops Nix from being able to build anything
(this particular setting can be overridden via
[](#opt-security.allowUserNamespaces)). See the
[profile source](https://github.com/nixos/nixpkgs/tree/master/nixos/modules/profiles/hardened.nix)
for further detail on which settings are altered.
::: {.warning}
This profile enables options that are known to affect system
stability. If you experience any stability issues when using the
profile, try disabling it. If you report an issue and use this
profile, always mention that you do.
:::

View File

@@ -0,0 +1,8 @@
# Headless {#sec-profile-headless}
Common configuration for headless machines (e.g., Amazon EC2 instances).
Disables [vesa](#opt-boot.vesa), serial consoles,
[emergency mode](#opt-systemd.enableEmergencyMode),
[grub splash images](#opt-boot.loader.grub.splashImage)
and configures the kernel to reboot automatically on panic.

View File

@@ -0,0 +1,24 @@
# Installation Device {#sec-profile-installation-device}
Provides a basic configuration for installation devices like CDs.
This enables redistributable firmware, includes the
[Clone Config profile](#sec-profile-clone-config)
and a copy of the Nixpkgs channel, so `nixos-install`
works out of the box.
Documentation for [Nixpkgs](#opt-documentation.enable)
and [NixOS](#opt-documentation.nixos.enable) are
forcefully enabled (to override the
[Minimal profile](#sec-profile-minimal) preference); the
NixOS manual is shown automatically on TTY 8, udisks is disabled.
Autologin is enabled as `nixos` user, while passwordless
login as both `root` and `nixos` is possible.
Passwordless `sudo` is enabled too.
[NetworkManager](#opt-networking.networkmanager.enable) is
enabled and can be configured interactively with `nmtui`.
It is explained how to login, start the ssh server, and if available,
how to start the display manager.
Several settings are tweaked so that the installer has a better chance of
succeeding under low-memory environments.

View File

@@ -0,0 +1,6 @@
# Minimal {#sec-profile-minimal}
This profile defines a small NixOS configuration. It does not contain any
graphical stuff. It's a very short file that sets the supported locales
to only support the user-selected locale, and
[disables packages' documentation](#opt-documentation.enable).

View File

@@ -0,0 +1,5 @@
# Perlless {#sec-perlless}
Render your system completely perlless (i.e. without the perl interpreter). This
includes a mechanism so that your build fails if it contains a Nix store path
that references the string "perl".

View File

@@ -0,0 +1,7 @@
# QEMU Guest {#sec-profile-qemu-guest}
This profile contains common configuration for virtual machines running under
QEMU (using virtio).
It makes virtio modules available on the initrd and sets the system time from
the hardware clock to work around a bug in qemu-kvm.

View File

@@ -0,0 +1,55 @@
# Renaming network interfaces {#sec-rename-ifs}
NixOS uses the udev [predictable naming
scheme](https://systemd.io/PREDICTABLE_INTERFACE_NAMES/) to assign names
to network interfaces. This means that by default cards are not given
the traditional names like `eth0` or `eth1`, whose order can change
unpredictably across reboots. Instead, relying on physical locations and
firmware information, the scheme produces names like `ens1`, `enp2s0`,
etc.
These names are predictable but less memorable and not necessarily
stable: for example installing new hardware or changing firmware
settings can result in a [name
change](https://github.com/systemd/systemd/issues/3715#issue-165347602).
If this is undesirable, for example if you have a single ethernet card,
you can revert to the traditional scheme by setting
[](#opt-networking.usePredictableInterfaceNames)
to `false`.
## Assigning custom names {#sec-custom-ifnames}
In case there are multiple interfaces of the same type, it's better to
assign custom names based on the device hardware address. For example,
we assign the name `wan` to the interface with MAC address
`52:54:00:12:01:01` using a netword link unit:
```nix
{
systemd.network.links."10-wan" = {
matchConfig.PermanentMACAddress = "52:54:00:12:01:01";
linkConfig.Name = "wan";
};
}
```
Note that links are directly read by udev, *not networkd*, and will work
even if networkd is disabled.
Alternatively, we can use a plain old udev rule:
```nix
{
boot.initrd.services.udev.rules = ''
SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", \
ATTR{address}=="52:54:00:12:01:01", KERNEL=="eth*", NAME="wan"
'';
}
```
::: {.warning}
The rule must be installed in the initrd using
`boot.initrd.services.udev.rules`, not the usual `services.udev.extraRules`
option. This is to avoid race conditions with other programs controlling
the interface.
:::

View File

@@ -0,0 +1,20 @@
# Secure Shell Access {#sec-ssh}
Secure shell (SSH) access to your machine can be enabled by setting:
```nix
{ services.openssh.enable = true; }
```
By default, root logins using a password are disallowed. They can be
disabled entirely by setting
[](#opt-services.openssh.settings.PermitRootLogin) to `"no"`.
You can declaratively specify authorised public keys for a user
as follows:
```nix
{
users.users.alice.openssh.authorizedKeys.keys = [ "ssh-ed25519 AAAAB3NzaC1kc3MAAACBAPIkGWVEt4..." ];
}
```

View File

@@ -0,0 +1,103 @@
# SSHFS File Systems {#sec-sshfs-file-systems}
[SSHFS][sshfs] is a [FUSE][fuse] filesystem that allows easy access to directories on a remote machine using the SSH File Transfer Protocol (SFTP).
It means that if you have SSH access to a machine, no additional setup is needed to mount a directory.
[sshfs]: https://github.com/libfuse/sshfs
[fuse]: https://en.wikipedia.org/wiki/Filesystem_in_Userspace
## Interactive mounting {#sec-sshfs-interactive}
In NixOS, SSHFS is packaged as `sshfs`.
Once installed, mounting a directory interactively is simple as running:
```ShellSession
$ sshfs my-user@example.com:/my-dir /mnt/my-dir
```
Like any other FUSE file system, the directory is unmounted using:
```ShellSession
$ fusermount -u /mnt/my-dir
```
## Non-interactive mounting {#sec-sshfs-non-interactive}
Mounting non-interactively requires some precautions because `sshfs` will run at boot and under a different user (root).
For obvious reason, you can't input a password, so public key authentication using an unencrypted key is needed.
To create a new key without a passphrase you can do:
```ShellSession
$ ssh-keygen -t ed25519 -P '' -f example-key
Generating public/private ed25519 key pair.
Your identification has been saved in example-key
Your public key has been saved in example-key.pub
The key fingerprint is:
SHA256:yjxl3UbTn31fLWeyLYTAKYJPRmzknjQZoyG8gSNEoIE my-user@workstation
```
To keep the key safe, change the ownership to `root:root` and make sure the permissions are `600`:
OpenSSH normally refuses to use the key if it's not well-protected.
The file system can be configured in NixOS via the usual [fileSystems](#opt-fileSystems) option.
Here's a typical setup:
```nix
{
fileSystems."/mnt/my-dir" = {
device = "my-user@example.com:/my-dir/";
fsType = "sshfs";
options = [
# Filesystem options
"allow_other" # for non-root access
"_netdev" # this is a network fs
"x-systemd.automount" # mount on demand
# SSH options
"reconnect" # handle connection drops
"ServerAliveInterval=15" # keep connections alive
"IdentityFile=/var/secrets/example-key"
];
};
}
```
More options from `ssh_config(5)` can be given as well, for example you can change the default SSH port or specify a jump proxy:
```nix
{
options = [
"ProxyJump=bastion@example.com"
"Port=22"
];
}
```
It's also possible to change the `ssh` command used by SSHFS to connect to the server.
For example:
```nix
{
options = [
(builtins.replaceStrings [ " " ] [ "\\040" ]
"ssh_command=${pkgs.openssh}/bin/ssh -v -L 8080:localhost:80"
)
];
}
```
::: {.note}
The escaping of spaces is needed because every option is written to the `/etc/fstab` file, which is a space-separated table.
:::
### Troubleshooting {#sec-sshfs-troubleshooting}
If you're having a hard time figuring out why mounting is failing, you can add the option `"debug"`.
This enables a verbose log in SSHFS that you can access via:
```ShellSession
$ journalctl -u $(systemd-escape -p /mnt/my-dir/).mount
Jun 22 11:41:18 workstation mount[87790]: SSHFS version 3.7.1
Jun 22 11:41:18 workstation mount[87793]: executing <ssh> <-x> <-a> <-oClearAllForwardings=yes> <-oServerAliveInterval=15> <-oIdentityFile=/var/secrets/wrong-key> <-2> <my-user@example.com> <-s> <sftp>
Jun 22 11:41:19 workstation mount[87793]: my-user@example.com: Permission denied (publickey).
Jun 22 11:41:19 workstation mount[87790]: read: Connection reset by peer
Jun 22 11:41:19 workstation systemd[1]: mnt-my\x2ddir.mount: Mount process exited, code=exited, status=1/FAILURE
Jun 22 11:41:19 workstation systemd[1]: mnt-my\x2ddir.mount: Failed with result 'exit-code'.
Jun 22 11:41:19 workstation systemd[1]: Failed to mount /mnt/my-dir.
Jun 22 11:41:19 workstation systemd[1]: mnt-my\x2ddir.mount: Consumed 54ms CPU time, received 2.3K IP traffic, sent 2.7K IP traffic.
```
::: {.note}
If the mount point contains special characters it needs to be escaped using `systemd-escape`.
This is due to the way systemd converts paths into unit names.
:::

View File

@@ -0,0 +1,116 @@
# Subversion {#module-services-subversion}
[Subversion](https://subversion.apache.org/) is a centralized
version-control system. It can use a [variety of
protocols](https://svnbook.red-bean.com/en/1.7/svn-book.html#svn.serverconfig.choosing)
for communication between client and server.
## Subversion inside Apache HTTP {#module-services-subversion-apache-httpd}
This section focuses on configuring a web-based server on top of the
Apache HTTP server, which uses
[WebDAV](http://www.webdav.org/)/[DeltaV](http://www.webdav.org/deltav/WWW10/deltav-intro.htm)
for communication.
For more information on the general setup, please refer to the [the
appropriate section of the Subversion
book](https://svnbook.red-bean.com/en/1.7/svn-book.html#svn.serverconfig.httpd).
To configure, include in `/etc/nixos/configuration.nix` code to activate
Apache HTTP, setting [](#opt-services.httpd.adminAddr)
appropriately:
```nix
{
services.httpd.enable = true;
services.httpd.adminAddr = "...";
networking.firewall.allowedTCPPorts = [
80
443
];
}
```
For a simple Subversion server with basic authentication, configure the
Subversion module for Apache as follows, setting `hostName` and
`documentRoot` appropriately, and `SVNParentPath` to the parent
directory of the repositories, `AuthzSVNAccessFile` to the location of
the `.authz` file describing access permission, and `AuthUserFile` to
the password file.
```nix
{
services.httpd.extraModules = [
# note that order is *super* important here
{
name = "dav_svn";
path = "${pkgs.apacheHttpdPackages.subversion}/modules/mod_dav_svn.so";
}
{
name = "authz_svn";
path = "${pkgs.apacheHttpdPackages.subversion}/modules/mod_authz_svn.so";
}
];
services.httpd.virtualHosts = {
"svn" = {
hostName = HOSTNAME;
documentRoot = DOCUMENTROOT;
locations."/svn".extraConfig = ''
DAV svn
SVNParentPath REPO_PARENT
AuthzSVNAccessFile ACCESS_FILE
AuthName "SVN Repositories"
AuthType Basic
AuthUserFile PASSWORD_FILE
Require valid-user
'';
};
};
}
```
The key `"svn"` is just a symbolic name identifying the virtual host.
The `"/svn"` in `locations."/svn".extraConfig` is the path underneath
which the repositories will be served.
[This page](https://wiki.archlinux.org/index.php/Subversion) explains
how to set up the Subversion configuration itself. This boils down to
the following:
Underneath `REPO_PARENT` repositories can be set up as follows:
```ShellSession
$ svn create REPO_NAME
```
Repository files need to be accessible by `wwwrun`:
```ShellSession
$ chown -R wwwrun:wwwrun REPO_PARENT
```
The password file `PASSWORD_FILE` can be created as follows:
```ShellSession
$ htpasswd -cs PASSWORD_FILE USER_NAME
```
Additional users can be set up similarly, omitting the `c` flag:
```ShellSession
$ htpasswd -s PASSWORD_FILE USER_NAME
```
The file describing access permissions `ACCESS_FILE` will look something
like the following:
```
[/]
* = r
[REPO_NAME:/]
USER_NAME = rw
```
The Subversion repositories will be accessible as
`http://HOSTNAME/svn/REPO_NAME`.

View File

@@ -0,0 +1,167 @@
# User Management {#sec-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:
```nix
{
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 [](#opt-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
[](#opt-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](#opt-users.users._name_.hashedPassword) option. A
hashed password can be generated using `mkpasswd`.
A user ID (uid) is assigned automatically. You can also specify a uid
manually by adding
```nix
{ uid = 1000; }
```
to the user specification.
Groups can be specified similarly. The following states that a group
named `students` shall exist:
```nix
{ 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`:
```ShellSession
# 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:
```ShellSession
# 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:
```ShellSession
# passwd alice
Enter new UNIX password: ***
Retype new UNIX password: ***
```
A user can be deleted using `userdel`:
```ShellSession
# 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`.
## Create users and groups with `systemd-sysusers` {#sec-systemd-sysusers}
::: {.note}
This is experimental.
Please consider using [Userborn](#sec-userborn) over systemd-sysusers as it's
more feature complete.
:::
Instead of using a custom perl script to create users and groups, you can use
systemd-sysusers:
```nix
{ systemd.sysusers.enable = true; }
```
The primary benefit of this is to remove a dependency on perl.
## Manage users and groups with `userborn` {#sec-userborn}
::: {.note}
This is experimental.
:::
Like systemd-sysusers, Userborn doesn't depend on Perl but offers some more
advantages over systemd-sysusers:
1. It can create "normal" users (with a GID >= 1000).
2. It can update some information about users. Most notably it can update their
passwords.
3. It will warn when users use an insecure or unsupported password hashing
scheme.
Userborn is the recommended way to manage users if you don't want to rely on
the Perl script. It aims to eventually replace the Perl script by default.
You can enable Userborn via:
```nix
{ services.userborn.enable = true; }
```
You can configure Userborn to store the password files
(`/etc/{group,passwd,shadow}`) outside of `/etc` and symlink them from this
location to `/etc`:
```nix
{ services.userborn.passwordFilesLocation = "/persistent/etc"; }
```
This is useful when you store `/etc` on a `tmpfs` or if `/etc` is immutable
(e.g. when using `system.etc.overlay.mutable = false;`). In the latter case the
original files are by default stored in `/var/lib/nixos`.
Userborn implements immutable users by re-mounting the password files
read-only. This means that unlike when using the Perl script, trying to add a
new user (e.g. via `useradd`) will fail right away.
## Restrict usage time {#sec-restrict-usage-time}
[Timekpr-nExT](https://mjasnik.gitlab.io/timekpr-next/) is a screen time managing application that helps optimizing time spent at computer for your subordinates, children or even for yourself.
You can enable it via:
```nix
{ services.timekpr.enable = true; }
```
This will install the `timekpr` package and start the `timekpr` service.
You can then use the `timekpra` application to configure time limits for users.

View File

@@ -0,0 +1,24 @@
# Wayland {#sec-wayland}
While X11 (see [](#sec-x11)) is still the primary display technology
on NixOS, Wayland support is steadily improving. Where X11 separates the
X Server and the window manager, on Wayland those are combined: a
Wayland Compositor is like an X11 window manager, but also embeds the
Wayland 'Server' functionality. This means it is sufficient to install
a Wayland Compositor such as sway without separately enabling a Wayland
server:
```nix
{ programs.sway.enable = true; }
```
This installs the sway compositor along with some essential utilities.
Now you can start sway from the TTY console.
If you are using a wlroots-based compositor, like sway, and want to be
able to share your screen, make sure to configure Pipewire using
[](#opt-services.pipewire.enable)
and related options.
For more helpful tips and tricks, see the
[wiki page about Sway](https://wiki.nixos.org/wiki/Sway).

View File

@@ -0,0 +1,74 @@
# Wireless Networks {#sec-wireless}
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:
```nix
{ networking.wireless.enable = true; }
```
NixOS lets you specify networks for wpa_supplicant declaratively:
```nix
{
networking.wireless.networks = {
# SSID with no spaces or special characters
echelon = {
psk = "abcdefgh";
};
# SSID with spaces and/or special characters
"echelon's AP" = {
psk = "ijklmnop";
};
# Hidden SSID
echelon = {
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`:
```ShellSession
$ wpa_passphrase ESSID PSK
network={
ssid="echelon"
#psk="abcdefgh"
psk=dca6d6ed41f4ab5a984c9f55f6f66d4efdc720ebf66959810f4329bb391c5435
}
```
```nix
{
networking.wireless.networks = {
echelon = {
pskRaw = "dca6d6ed41f4ab5a984c9f55f6f66d4efdc720ebf66959810f4329bb391c5435";
};
};
}
```
or you can use it to directly generate the `wpa_supplicant.conf`:
```ShellSession
# wpa_passphrase ESSID PSK > /etc/wpa_supplicant.conf
```
After you have edited the `wpa_supplicant.conf`, you need to restart the
wpa_supplicant service.
```ShellSession
# systemctl restart wpa_supplicant.service
```

View File

@@ -0,0 +1,396 @@
# X Window System {#sec-x11}
The X Window System (X11) provides the basis of NixOS' graphical user
interface. It can be enabled as follows:
```nix
{ 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.
```nix
{ 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:
```nix
{
services.desktopManager.plasma6.enable = true;
services.xserver.desktopManager.xfce.enable = true;
services.desktopManager.gnome.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;
services.xserver.windowManager.herbstluftwm.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:
```nix
{
services.displayManager.sddm.enable = true;
services.displayManager.gdm.enable = true;
}
```
You can set the keyboard layout (and optionally the layout variant):
```nix
{
services.xserver.xkb.layout = "de";
services.xserver.xkb.variant = "neo";
}
```
The X server is started automatically at boot time. If you don't want
this to happen, you can set:
```nix
{ services.xserver.autorun = false; }
```
The X server can then be started manually:
```ShellSession
# 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:
```nix
{ hardware.graphics.enable32Bit = true; }
```
## Auto-login {#sec-x11-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:
```nix
{ services.displayManager.defaultSession = "none+i3"; }
```
Every display manager in NixOS supports auto-login, here is an example
using lightdm for a user `alice`:
```nix
{
services.xserver.displayManager.lightdm.enable = true;
services.displayManager.autoLogin.enable = true;
services.displayManager.autoLogin.user = "alice";
}
```
## Running X without a display manager {#sec-x11-startx}
It is possible to avoid a display manager entirely and starting the X server
manually from a virtual terminal. Add to your configuration:
```nix
{
services.xserver.displayManager.startx = {
enable = true;
generateScript = true;
};
}
```
then you can start the X server with the `startx` command.
The second option will generate a base `xinitrc` script that will run your
window manager and set up the systemd user session.
You can extend the script using the
[extraCommands](#opt-services.xserver.displayManager.startx.extraCommands)
option, for example:
```nix
{
services.xserver.displayManager.startx = {
generateScript = true;
extraCommands = ''
xrdb -load .Xresources
xsetroot -solid '#666661'
xsetroot -cursor_name left_ptr
'';
};
}
```
or, alternatively, you can write your own from scratch in `~/.xinitrc`.
In this case, remember you're responsible for starting the window manager, for
example:
```shell
sxhkd &
bspwm &
```
and if you have enabled some systemd user service, you will probably want to
also add these lines too:
```shell
# import required env variables from the current shell
systemctl --user import-environment DISPLAY XDG_SESSION_ID
# start all graphical user services
systemctl --user start nixos-fake-graphical-session.target
# start the user dbus daemon
dbus-daemon --session --address="unix:path=/run/user/$(id -u)/bus" &
```
## Intel Graphics drivers {#sec-x11--graphics-cards-intel}
The default and recommended driver for Intel Graphics in X.org is `modesetting`
(included in the xorg-server package itself).
This is a generic driver which uses the kernel [mode
setting](https://en.wikipedia.org/wiki/Mode_setting) (KMS) mechanism, it
supports Glamor (2D graphics acceleration via OpenGL) and is actively
maintained, it may perform worse in some cases (like in old chipsets).
There is a second driver, `intel` (provided by the xf86-video-intel package),
specific to older Intel iGPUs from generation 2 to 9. It is not recommended by
most distributions: it lacks several modern features (for example, it doesn't
support Glamor) and the package hasn't been officially updated since 2015.
Third generation and older iGPUs (15-20+ years old) are not supported by the
`modesetting` driver (X will crash upon startup). Thus, the `intel` driver is
required for these chipsets.
Otherwise, the results vary depending on the hardware, so you may have to try
both drivers. Use the option
[](#opt-services.xserver.videoDrivers)
to set one. The recommended configuration for modern systems is:
```nix
{ services.xserver.videoDrivers = [ "modesetting" ]; }
```
::: {.note}
The `modesetting` driver doesn't currently provide a `TearFree` option (this
will become available in an upcoming X.org release), So, without using a
compositor (for example, see [](#opt-services.picom.enable)) you will
experience screen tearing.
:::
If you experience screen tearing no matter what, this configuration was
reported to resolve the issue:
```nix
{
services.xserver.videoDrivers = [ "intel" ];
services.xserver.deviceSection = ''
Option "DRI" "2"
Option "TearFree" "true"
'';
}
```
Note that this will likely downgrade the performance compared to
`modesetting` or `intel` with DRI 3 (default).
## Proprietary NVIDIA drivers {#sec-x11-graphics-cards-nvidia}
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:
```nix
{ services.xserver.videoDrivers = [ "nvidia" ]; }
```
If you have an older card, you may have to use one of the legacy drivers:
```nix
{
hardware.nvidia.package = config.boot.kernelPackages.nvidiaPackages.legacy_470;
hardware.nvidia.package = config.boot.kernelPackages.nvidiaPackages.legacy_390;
hardware.nvidia.package = config.boot.kernelPackages.nvidiaPackages.legacy_340;
}
```
You may need to reboot after enabling this driver to prevent a clash
with other kernel modules.
## Touchpads {#sec-x11-touchpads}
Support for Synaptics touchpads (found in many laptops such as the Dell
Latitude series) can be enabled as follows:
```nix
{ services.libinput.enable = true; }
```
The driver has many options (see [](#ch-options)).
For instance, the following disables tap-to-click behavior:
```nix
{ services.libinput.touchpad.tapping = false; }
```
Note: the use of `services.xserver.synaptics` is deprecated since NixOS
17.09.
## GTK/Qt themes {#sec-x11-gtk-and-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
GTK ones, you can use the following configuration:
```nix
{
qt.enable = true;
qt.platformTheme = "gtk2";
qt.style = "gtk2";
}
```
## Custom XKB layouts {#custom-xkb-layouts}
It is possible to install custom [ XKB
](https://en.wikipedia.org/wiki/X_keyboard_extension) keyboard layouts
using the option `services.xserver.xkb.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.
Create a file called `us-greek` with the following content (under a
directory called `symbols`; it's an XKB peculiarity that will help with
testing):
```
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 ] };
};
```
A minimal layout specification must include the following:
```nix
{
services.xserver.xkb.extraLayouts.us-greek = {
description = "US layout with alt-gr greek";
languages = [ "eng" ];
symbolsFile = /yourpath/symbols/us-greek;
};
}
```
::: {.note}
The name (after `extraLayouts.`) should match the one given to the
`xkb_symbols` block.
:::
Applying this customization requires rebuilding several packages, and a
broken XKB file can lead to the X session crashing at login. Therefore,
you're strongly advised to **test your layout before applying it**:
```ShellSession
$ nix-shell -p xorg.xkbcomp
$ setxkbmap -I/yourpath us-greek -print | xkbcomp -I/yourpath - $DISPLAY
```
You can inspect the predefined XKB files for examples:
```ShellSession
$ echo "$(nix-build --no-out-link '<nixpkgs>' -A xorg.xkeyboardconfig)/etc/X11/xkb/"
```
Once the configuration is applied, and you did a logout/login cycle, the
layout should be ready to use. You can try it by e.g. running
`setxkbmap us-greek` and then type `<alt>+a` (it may not get applied in
your terminal straight away). To change the default, the usual
`services.xserver.xkb.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
```nix
{
services.xserver.xkb.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:
```nix
{
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
```ShellSession
$ xinit -- -xkbdir /etc/X11/xkb
```
To learn how to write layouts take a look at the XKB [documentation
](https://www.x.org/releases/current/doc/xorg-docs/input/XKB-Enhancing.html#Defining_New_Layouts).
More example layouts can also be found [here
](https://wiki.archlinux.org/index.php/X_KeyBoard_extension#Basic_examples).

View File

@@ -0,0 +1,61 @@
# Xfce Desktop Environment {#sec-xfce}
To enable the Xfce Desktop Environment, set
```nix
{
services.xserver.desktopManager.xfce.enable = true;
services.displayManager.defaultSession = "xfce";
}
```
Optionally, *picom* can be enabled for nice graphical effects, some
example settings:
```nix
{
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
[](#opt-environment.systemPackages) from `pkgs.xfce`.
## Thunar {#sec-xfce-thunar-plugins}
Thunar (the Xfce file manager) is automatically enabled when Xfce is
enabled. To enable Thunar without enabling Xfce, use the configuration
option [](#opt-programs.thunar.enable) instead of adding
`pkgs.xfce.thunar` to [](#opt-environment.systemPackages).
If you'd like to add extra plugins to Thunar, add them to
[](#opt-programs.thunar.plugins). You shouldn't just add them to
[](#opt-environment.systemPackages).
## Troubleshooting {#sec-xfce-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`).
```plain
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.
```ShellSession
$ xfconf-query -c xfce4-session -p /compat/LaunchGNOME -s true
```
It is necessary to log out and log in again for this to take effect.

View File

@@ -0,0 +1,140 @@
# Contributing to this manual {#chap-contributing}
The sources of the NixOS manual are in the [nixos/doc/manual](https://github.com/NixOS/nixpkgs/tree/master/nixos/doc/manual) subdirectory of the [Nixpkgs](https://github.com/NixOS/nixpkgs) repository.
This manual uses the [Nixpkgs manual syntax](https://nixos.org/manual/nixpkgs/unstable/#sec-contributing-markup).
You can quickly check your edits with the following:
```ShellSession
$ cd /path/to/nixpkgs
$ $EDITOR doc/nixos/manual/... # edit the manual
$ nix-build nixos/release.nix -A manual.x86_64-linux
```
If the build succeeds, the manual will be in `./result/share/doc/nixos/index.html`.
There's also [a convenient development daemon](https://nixos.org/manual/nixpkgs/unstable/#sec-contributing-devmode).
The above instructions don't deal with the appendix of available `configuration.nix` options, and the manual pages related to NixOS. These are built, and written in a different location and in a different format, as explained in the next sections.
## Development environment {#sec-contributing-development-env}
In order to reduce repetition, consider using tools from the provided development environment:
Load it from the NixOS documentation directory with
```ShellSession
$ cd /path/to/nixpkgs/nixos/doc/manual
$ nix-shell
```
To load the development utilities automatically when entering that directory, [set up `nix-direnv`](https://nix.dev/guides/recipes/direnv).
Make sure that your local files aren't added to Git history by adding the following lines to `.git/info/exclude` at the root of the Nixpkgs repository:
```
/**/.envrc
/**/.direnv
```
### `devmode` {#sec-contributing-devmode}
Use [`devmode`](https://github.com/NixOS/nixpkgs/blob/master/pkgs/by-name/de/devmode/README.md) for a live preview when editing the manual.
## Testing redirects {#sec-contributing-redirects}
Once you have a successful build, you can open the relevant HTML (path mentioned above) in a browser along with the anchor, and observe the redirection.
Note that if you already loaded the page and *then* input the anchor, you will need to perform a reload. This is because browsers do not re-run client JS code when only the anchor has changed.
## Contributing to the `configuration.nix` options documentation {#sec-contributing-options}
The documentation for all the different `configuration.nix` options is automatically generated by reading the `description`s of all the NixOS options defined at `nixos/modules/`. If you want to improve such `description`, find it in the `nixos/modules/` directory, and edit it and open a pull request.
To see how your changes render on the web, run again:
```ShellSession
$ nix-build nixos/release.nix -A manual.x86_64-linux
```
And you'll see the changes to the appendix in the path `result/share/doc/nixos/options.html`.
You can also build only the `configuration.nix(5)` manual page, via:
```ShellSession
$ cd /path/to/nixpkgs
$ nix-build nixos/release.nix -A nixos-configuration-reference-manpage.x86_64-linux
```
And observe the result via:
```ShellSession
$ man --local-file result/share/man/man5/configuration.nix.5
```
If you're on a different architecture that's supported by NixOS (check file `nixos/release.nix` on Nixpkgs' repository) then replace `x86_64-linux` with the architecture. `nix-build` will complain otherwise, but should also tell you which architecture you have + the supported ones.
## Contributing to `nixos-*` tools' manpages {#sec-contributing-nixos-tools}
The manual pages for the tools available in the installation image can be found in Nixpkgs by running (e.g for `nixos-rebuild`):
```ShellSession
$ git ls | grep nixos-rebuild.8
```
Man pages are written in [`mdoc(7)` format](https://mandoc.bsd.lv/man/mdoc.7.html) and should be portable between mandoc and groff for rendering (except for minor differences, notably different spacing rules.)
For a preview, run `man --local-file path/to/file.8`.
Being written in `mdoc`, these manpages use semantic markup. This following subsections provides a guideline on where to apply which semantic elements.
### Command lines and arguments {#ssec-contributing-nixos-tools-cli-and-args}
In any manpage, commands, flags and arguments to the *current* executable should be marked according to their semantics. Commands, flags and arguments passed to *other* executables should not be marked like this and should instead be considered as code examples and marked with `Ql`.
- Use `Fl` to mark flag arguments, `Ar` for their arguments.
- Repeating arguments should be marked by adding an ellipsis (spelled with periods, `...`).
- Use `Cm` to mark literal string arguments, e.g. the `boot` command argument passed to `nixos-rebuild`.
- Optional flags or arguments should be marked with `Op`. This includes optional repeating arguments.
- Required flags or arguments should not be marked.
- Mutually exclusive groups of arguments should be enclosed in curly brackets, preferably created with `Bro`/`Brc` blocks.
When an argument is used in an example it should be marked up with `Ar` again to differentiate it from a constant. For example, a command with a `--host name` option that calls ssh to retrieve the host's local time would signify this thusly:
```
This will run
.Ic ssh Ar name Ic time
to retrieve the remote time.
```
### Paths, NixOS options, environment variables {#ssec-contributing-nixos-tools-options-and-environment}
Constant paths should be marked with `Pa`, NixOS options with `Va`, and environment variables with `Ev`.
Generated paths, e.g. `result/bin/run-hostname-vm` (where `hostname` is a variable or arguments) should be marked as `Ql` inline literals with their variable components marked appropriately.
- When `hostname` refers to an argument, it becomes `.Ql result/bin/run- Ns Ar hostname Ns -vm`
- When `hostname` refers to a variable, it becomes `.Ql result/bin/run- Ns Va hostname Ns -vm`
### Code examples and other commands {#ssec-contributing-nixos-tools-code-examples}
In free text names and complete invocations of other commands (e.g. `ssh` or `tar -xvf src.tar`) should be marked with `Ic`, fragments of command lines should be marked with `Ql`.
Larger code blocks or those that cannot be shown inline should use indented literal display block markup for their contents, i.e.
```
.Bd -literal -offset indent
...
.Ed
```
Contents of code blocks may be marked up further, e.g. if they refer to arguments that will be substituted into them:
```
.Bd -literal -offset indent
{
config.networking.hostname = "\c
.Ar hostname Ns \c
";
}
.Ed
```

View File

@@ -0,0 +1,295 @@
{
pkgs,
options,
config,
version,
revision,
extraSources ? [ ],
baseOptionsJSON ? null,
warningsAreErrors ? true,
prefix ? ../../..,
checkRedirects ? true,
}:
let
inherit (pkgs) buildPackages runCommand docbook_xsl_ns;
inherit (pkgs.lib)
evalModules
hasPrefix
removePrefix
flip
foldr
types
mkOption
escapeShellArg
concatMapStringsSep
sourceFilesBySuffices
modules
;
common = import ./common.nix;
manpageUrls = pkgs.path + "/doc/manpage-urls.json";
# We need to strip references to /nix/store/* from options,
# including any `extraSources` if some modules came from elsewhere,
# or else the build will fail.
#
# E.g. if some `options` came from modules in ${pkgs.customModules}/nix,
# you'd need to include `extraSources = [ pkgs.customModules ]`
prefixesToStrip = map (p: "${toString p}/") ([ prefix ] ++ extraSources);
stripAnyPrefixes = flip (foldr removePrefix) prefixesToStrip;
optionsDoc = buildPackages.nixosOptionsDoc {
inherit
options
revision
baseOptionsJSON
warningsAreErrors
;
transformOptions =
opt:
opt
// {
# Clean up declaration sites to not refer to the NixOS source tree.
declarations = map stripAnyPrefixes opt.declarations;
};
};
nixos-lib = import ../../lib { };
testOptionsDoc =
let
eval = nixos-lib.evalTest {
# Avoid evaluating a NixOS config prototype.
config.node.type = types.deferredModule;
options._module.args = mkOption { internal = true; };
};
in
buildPackages.nixosOptionsDoc {
inherit (eval) options;
inherit revision;
transformOptions =
opt:
opt
// {
# Clean up declaration sites to not refer to the NixOS source tree.
declarations = map (
decl:
if hasPrefix (toString ../../..) (toString decl) then
let
subpath = removePrefix "/" (removePrefix (toString ../../..) (toString decl));
in
{
url = "https://github.com/NixOS/nixpkgs/blob/master/${subpath}";
name = subpath;
}
else
decl
) opt.declarations;
};
documentType = "none";
variablelistId = "test-options-list";
optionIdPrefix = "test-opt-";
};
testDriverMachineDocstrings =
pkgs.callPackage ../../../nixos/lib/test-driver/nixos-test-driver-docstrings.nix
{ };
prepareManualFromMD = ''
cp -r --no-preserve=all $inputs/* .
cp -r ${../../../doc/release-notes} ./release-notes-nixpkgs
substituteInPlace ./manual.md \
--replace-fail '@NIXOS_VERSION@' "${version}"
substituteInPlace ./configuration/configuration.md \
--replace-fail \
'@MODULE_CHAPTERS@' \
${escapeShellArg (concatMapStringsSep "\n" (p: "${p.value}") config.meta.doc)}
substituteInPlace ./nixos-options.md \
--replace-fail \
'@NIXOS_OPTIONS_JSON@' \
${optionsDoc.optionsJSON}/${common.outputPath}/options.json
substituteInPlace ./development/writing-nixos-tests.section.md \
--replace-fail \
'@NIXOS_TEST_OPTIONS_JSON@' \
${testOptionsDoc.optionsJSON}/${common.outputPath}/options.json
sed -e '/@PYTHON_MACHINE_METHODS@/ {' -e 'r ${testDriverMachineDocstrings}/machine-methods.md' -e 'd' -e '}' \
-i ./development/writing-nixos-tests.section.md
substituteInPlace ./development/modular-services.md \
--replace-fail \
'@PORTABLE_SERVICE_OPTIONS@' \
${portableServiceOptions.optionsJSON}/${common.outputPath}/options.json
substituteInPlace ./development/modular-services.md \
--replace-fail \
'@SYSTEMD_SERVICE_OPTIONS@' \
${systemdServiceOptions.optionsJSON}/${common.outputPath}/options.json
'';
portableServiceOptions = buildPackages.nixosOptionsDoc {
inherit
(evalModules {
modules = [
(modules.importApply ../../modules/system/service/portable/service.nix {
pkgs = throw "nixos docs / portableServiceOptions: Do not reference pkgs in docs";
})
];
})
options
;
inherit revision warningsAreErrors;
transformOptions =
opt:
opt
// {
# Clean up declaration sites to not refer to the NixOS source tree.
declarations = map stripAnyPrefixes opt.declarations;
};
};
systemdServiceOptions = buildPackages.nixosOptionsDoc {
inherit (evalModules { modules = [ ../../modules/system/service/systemd/service.nix ]; }) options;
# TODO: filter out options that are not systemd-specific, maybe also change option prefix to just `service-opt-`?
inherit revision warningsAreErrors;
transformOptions =
opt:
opt
// {
# Clean up declaration sites to not refer to the NixOS source tree.
declarations = map stripAnyPrefixes opt.declarations;
};
};
in
rec {
inherit (optionsDoc) optionsJSON optionsNix optionsDocBook;
# Generate the NixOS manual.
manualHTML =
runCommand "nixos-manual-html"
{
nativeBuildInputs = [ buildPackages.nixos-render-docs ];
inputs = sourceFilesBySuffices ./. [ ".md" ];
meta.description = "The NixOS manual in HTML format";
allowedReferences = [ "out" ];
}
''
# Generate the HTML manual.
dst=$out/${common.outputPath}
mkdir -p $dst
cp ${../../../doc/style.css} $dst/style.css
cp ${../../../doc/anchor.min.js} $dst/anchor.min.js
cp ${../../../doc/anchor-use.js} $dst/anchor-use.js
cp -r ${pkgs.documentation-highlighter} $dst/highlightjs
${prepareManualFromMD}
nixos-render-docs -j $NIX_BUILD_CORES manual html \
--manpage-urls ${manpageUrls} \
${if checkRedirects then "--redirects ${./redirects.json}" else ""} \
--revision ${escapeShellArg revision} \
--generator "nixos-render-docs ${pkgs.lib.version}" \
--stylesheet style.css \
--stylesheet highlightjs/mono-blue.css \
--script ./highlightjs/highlight.pack.js \
--script ./highlightjs/loader.js \
--script ./anchor.min.js \
--script ./anchor-use.js \
--toc-depth 1 \
--chunk-toc-depth 1 \
./manual.md \
$dst/${common.indexPath}
cp ${pkgs.roboto.src}/web/Roboto\[ital\,wdth\,wght\].ttf "$dst/Roboto.ttf"
mkdir -p $out/nix-support
echo "nix-build out $out" >> $out/nix-support/hydra-build-products
echo "doc manual $dst" >> $out/nix-support/hydra-build-products
''; # */
# Alias for backward compatibility. TODO(@oxij): remove eventually.
manual = manualHTML;
# Index page of the NixOS manual.
manualHTMLIndex = "${manualHTML}/${common.outputPath}/${common.indexPath}";
manualEpub =
runCommand "nixos-manual-epub"
{
nativeBuildInputs = [
buildPackages.libxml2.bin
buildPackages.libxslt.bin
buildPackages.zip
];
doc = ''
<book xmlns="http://docbook.org/ns/docbook"
xmlns:xlink="http://www.w3.org/1999/xlink"
version="5.0"
xml:id="book-nixos-manual">
<info>
<title>NixOS Manual</title>
<subtitle>Version ${pkgs.lib.version}</subtitle>
</info>
<chapter>
<title>Temporarily unavailable</title>
<para>
The NixOS manual is currently not available in EPUB format,
please use the <link xlink:href="https://nixos.org/nixos/manual">HTML manual</link>
instead.
</para>
<para>
If you've used the EPUB manual in the past and it has been useful to you, please
<link xlink:href="https://github.com/NixOS/nixpkgs/issues/237234">let us know</link>.
</para>
</chapter>
</book>
'';
passAsFile = [ "doc" ];
}
''
# Generate the epub manual.
dst=$out/${common.outputPath}
xsltproc \
--param chapter.autolabel 0 \
--nonet --xinclude --output $dst/epub/ \
${docbook_xsl_ns}/xml/xsl/docbook/epub/docbook.xsl \
$docPath
echo "application/epub+zip" > mimetype
manual="$dst/nixos-manual.epub"
zip -0Xq "$manual" mimetype
cd $dst/epub && zip -Xr9D "$manual" *
rm -rf $dst/epub
mkdir -p $out/nix-support
echo "doc-epub manual $manual" >> $out/nix-support/hydra-build-products
'';
# Generate the `man configuration.nix` package
nixos-configuration-reference-manpage =
runCommand "nixos-configuration-reference-manpage"
{
nativeBuildInputs = [
buildPackages.installShellFiles
buildPackages.nixos-render-docs
];
allowedReferences = [ "out" ];
}
''
# Generate manpages.
mkdir -p $out/share/man/man5
nixos-render-docs -j $NIX_BUILD_CORES options manpage \
--revision ${escapeShellArg revision} \
${optionsJSON}/${common.outputPath}/options.json \
$out/share/man/man5/configuration.nix.5
compressManPages $out
'';
}

View File

@@ -0,0 +1,74 @@
# Activation script {#sec-activation-script}
The activation script is a bash script called to activate the new
configuration which resides in a NixOS system in `$out/activate`. Since its
contents depend on your system configuration, the contents may differ.
This chapter explains how the script works in general and some common NixOS
snippets. Please be aware that the script is executed on every boot and system
switch, so tasks that can be performed in other places should be performed
there (for example letting a directory of a service be created by systemd using
mechanisms like `StateDirectory`, `CacheDirectory`, ... or if that's not
possible using `preStart` of the service).
Activation scripts are defined as snippets using
[](#opt-system.activationScripts). They can either be a simple multiline string
or an attribute set that can depend on other snippets. The builder for the
activation script will take these dependencies into account and order the
snippets accordingly. As a simple example:
```nix
{
system.activationScripts.my-activation-script = {
deps = [ "etc" ];
# supportsDryActivation = true;
text = ''
echo "Hallo i bims"
'';
};
}
```
This example creates an activation script snippet that is run after the `etc`
snippet. The special variable `supportsDryActivation` can be set so the snippet
is also run when `nixos-rebuild dry-activate` is run. To differentiate between
real and dry activation, the `$NIXOS_ACTION` environment variable can be
read which is set to `dry-activate` when a dry activation is done.
An activation script can write to special files instructing
`switch-to-configuration` to restart/reload units. The script will take these
requests into account and will incorporate the unit configuration as described
above. This means that the activation script will "fake" a modified unit file
and `switch-to-configuration` will act accordingly. By doing so, configuration
like [systemd.services.\<name\>.restartIfChanged](#opt-systemd.services) is
respected. Since the activation script is run **after** services are already
stopped, [systemd.services.\<name\>.stopIfChanged](#opt-systemd.services)
cannot be taken into account anymore and the unit is always restarted instead
of being stopped and started afterwards.
The files that can be written to are `/run/nixos/activation-restart-list` and
`/run/nixos/activation-reload-list` with their respective counterparts for
dry activation being `/run/nixos/dry-activation-restart-list` and
`/run/nixos/dry-activation-reload-list`. Those files can contain
newline-separated lists of unit names where duplicates are being ignored. These
files are not create automatically and activation scripts must take the
possibility into account that they have to create them first.
## NixOS snippets {#sec-activation-script-nixos-snippets}
There are some snippets NixOS enables by default because disabling them would
most likely break your system. This section lists a few of them and what they
do:
- `binsh` creates `/bin/sh` which points to the runtime shell
- `etc` sets up the contents of `/etc`, this includes systemd units and
excludes `/etc/passwd`, `/etc/group`, and `/etc/shadow` (which are managed by
the `users` snippet)
- `hostname` sets the system's hostname in the kernel (not in `/etc`)
- `modprobe` sets the path to the `modprobe` binary for module auto-loading
- `nix` prepares the nix store and adds a default initial channel
- `specialfs` is responsible for mounting filesystems like `/proc` and `sys`
- `users` creates and removes users and groups by managing `/etc/passwd`,
`/etc/group` and `/etc/shadow`. This also creates home directories
- `usrbinenv` creates `/usr/bin/env`
- `var` creates some directories in `/var` that are not service-specific
- `wrappers` creates setuid wrappers like `sudo`

View File

@@ -0,0 +1,45 @@
# Warnings and Assertions {#sec-assertions}
When configuration problems are detectable in a module, it is a good idea to write an assertion or warning. Doing so provides clear feedback to the user and prevents errors after the build.
Although Nix has the `abort` and `builtins.trace` [functions](https://nixos.org/nix/manual/#ssec-builtins) to perform such tasks, they are not ideally suited for NixOS modules. Instead of these functions, you can declare your warnings and assertions using the NixOS module system.
## Warnings {#sec-assertions-warnings}
This is an example of using `warnings`.
```nix
{ config, lib, ... }:
{
config = lib.mkIf config.services.foo.enable {
warnings =
if config.services.foo.bar then
[
''
You have enabled the bar feature of the foo service.
This is known to cause some specific problems in certain situations.
''
]
else
[ ];
};
}
```
## Assertions {#sec-assertions-assetions}
This example, extracted from the [`syslogd` module](https://github.com/NixOS/nixpkgs/blob/release-17.09/nixos/modules/services/logging/syslogd.nix) shows how to use `assertions`. Since there can only be one active syslog daemon at a time, an assertion is useful to prevent such a broken system from being built.
```nix
{ config, lib, ... }:
{
config = lib.mkIf config.services.syslogd.enable {
assertions = [
{
assertion = !config.services.rsyslogd.enable;
message = "rsyslogd conflicts with syslogd";
}
];
};
}
```

View File

@@ -0,0 +1,38 @@
# Bootspec {#sec-bootspec}
Bootspec is a feature introduced in [RFC-0125](https://github.com/NixOS/rfcs/pull/125) in order to standardize bootloader support and advanced boot workflows such as SecureBoot and potentially more.
The reference implementation can be found [here](https://github.com/NixOS/nixpkgs/pull/172237).
The creation of bootspec documents is enabled by default.
## Schema {#sec-bootspec-schema}
The bootspec schema is versioned and validated against [a CUE schema file](https://cuelang.org/) which should considered as the source of truth for your applications.
You will find the current version [here](../../../modules/system/activation/bootspec.cue).
## Extensions mechanism {#sec-bootspec-extensions}
Bootspec cannot account for all usecases.
For this purpose, Bootspec offers a generic extension facility [`boot.bootspec.extensions`](options.html#opt-boot.bootspec.extensions) which can be used to inject any data needed for your usecases.
An example for SecureBoot is to get the Nix store path to `/etc/os-release` in order to bake it into a unified kernel image:
```nix
{ config, lib, ... }:
{
boot.bootspec.extensions = {
"org.secureboot.osRelease" = config.environment.etc."os-release".source;
};
}
```
To reduce incompatibility and prevent names from clashing between applications, it is **highly recommended** to use a unique namespace for your extensions.
## External bootloaders {#sec-bootspec-external-bootloaders}
It is possible to enable your own bootloader through [`boot.loader.external.installHook`](options.html#opt-boot.loader.external.installHook) which can wrap an existing bootloader.
Currently, there is no good story to compose existing bootloaders to enrich their features, e.g. SecureBoot, etc.
It will be necessary to reimplement or reuse existing parts.

View File

@@ -0,0 +1,74 @@
# Building Specific Parts of NixOS {#sec-building-parts}
With the command `nix-build`, you can build specific parts of your NixOS
configuration. This is done as follows:
```ShellSession
$ cd /path/to/nixpkgs/nixos
$ nix-build -A config.option
```
where `option` is a NixOS option with type "derivation" (i.e. something
that can be built). Attributes of interest include:
`system.build.toplevel`
: The top-level option that builds the entire NixOS system. Everything
else in your configuration is indirectly pulled in by this option.
This is what `nixos-rebuild` builds and what `/run/current-system`
points to afterwards.
A shortcut to build this is:
```ShellSession
$ nix-build -A system
```
`system.build.manual.manualHTML`
: The NixOS manual.
`system.build.etc`
: A tree of symlinks that form the static parts of `/etc`.
`system.build.initialRamdisk` , `system.build.kernel`
: The initial ramdisk and kernel of the system. This allows a quick
way to test whether the kernel and the initial ramdisk boot
correctly, by using QEMU's `-kernel` and `-initrd` options:
```ShellSession
$ nix-build -A config.system.build.initialRamdisk -o initrd
$ nix-build -A config.system.build.kernel -o kernel
$ qemu-system-x86_64 -kernel ./kernel/bzImage -initrd ./initrd/initrd -hda /dev/null
```
`system.build.nixos-rebuild` , `system.build.nixos-install` , `system.build.nixos-generate-config`
: These build the corresponding NixOS commands.
`systemd.units.unit-name.unit`
: This builds the unit with the specified name. Note that since unit
names contain dots (e.g. `httpd.service`), you need to put them
between quotes, like this:
```ShellSession
$ nix-build -A 'config.systemd.units."httpd.service".unit'
```
You can also test individual units, without rebuilding the whole
system, by putting them in `/run/systemd/system`:
```ShellSession
$ cp $(nix-build -A 'config.systemd.units."httpd.service".unit')/httpd.service \
/run/systemd/system/tmp-httpd.service
# systemctl daemon-reload
# systemctl start tmp-httpd.service
```
Note that the unit must not have the same name as any unit in
`/etc/systemd/system` since those take precedence over
`/run/systemd/system`. That's why the unit is installed as
`tmp-httpd.service` here.

View File

@@ -0,0 +1,45 @@
# Developing the NixOS Test Driver {#chap-developing-the-test-driver}
The NixOS test framework is a project of its own.
It consists of roughly the following components:
- `nixos/lib/test-driver`: The Python framework that sets up the test and runs the [`testScript`](#test-opt-testScript)
- `nixos/lib/testing`: The Nix code responsible for the wiring, written using the (NixOS) Module System.
These components are exposed publicly through:
- `nixos/lib/default.nix`: The public interface that exposes the `nixos/lib/testing` entrypoint.
- `flake.nix`: Exposes the `lib.nixos`, including the public test interface.
Beyond the test driver itself, its integration into NixOS and Nixpkgs is important.
- `pkgs/top-level/all-packages.nix`: Defines the `nixosTests` attribute, used
by the package `tests` attributes and OfBorg.
- `nixos/release.nix`: Defines the `tests` attribute built by Hydra, independently, but analogous to `nixosTests`
- `nixos/release-combined.nix`: Defines which tests are channel blockers.
Finally, we have legacy entrypoints that users should move away from, but are cared for on a best effort basis.
These include `pkgs.nixosTest`, `testing-python.nix` and `make-test-python.nix`.
## Testing changes to the test framework {#sec-test-the-test-framework}
We currently have limited unit tests for the framework itself. You may run these with `nix-build -A nixosTests.nixos-test-driver`.
When making significant changes to the test framework, we run the tests on Hydra, to avoid disrupting the larger NixOS project.
For this, we use the `python-test-refactoring` branch in the `NixOS/nixpkgs` repository, and its [corresponding Hydra jobset](https://hydra.nixos.org/jobset/nixos/python-test-refactoring).
This branch is used as a pointer, and not as a feature branch.
1. Rebase the PR onto a recent, good evaluation of `nixos-unstable`
2. Create a baseline evaluation by force-pushing this revision of `nixos-unstable` to `python-test-refactoring`.
3. Note the evaluation number (we'll call it `<previous>`)
4. Push the PR to `python-test-refactoring` and evaluate the PR on Hydra
5. Create a comparison URL by navigating to the latest build of the PR and adding to the URL `?compare=<previous>`. This is not necessary for the evaluation that comes right after the baseline.
Review the removed tests and newly failed tests using the constructed URL; otherwise you will accidentally compare iterations of the PR instead of changes to the PR base.
As we currently have some flaky tests, newly failing tests are expected, but should be reviewed to make sure that
- The number of failures did not increase significantly.
- All failures that do occur can reasonably be assumed to fail for a different reason than the changes.

View File

@@ -0,0 +1,16 @@
# Development {#ch-development}
This chapter describes how you can modify and extend NixOS.
```{=include=} chapters
sources.chapter.md
writing-modules.chapter.md
building-parts.chapter.md
bootspec.chapter.md
what-happens-during-a-system-switch.chapter.md
writing-documentation.chapter.md
nixos-tests.chapter.md
developing-the-test-driver.chapter.md
testing-installer.chapter.md
modular-services.md
```

View File

@@ -0,0 +1,36 @@
# `/etc` via overlay filesystem {#sec-etc-overlay}
::: {.note}
This is experimental and requires a kernel version >= 6.6 because it uses
new overlay features and relies on the new mount API.
:::
Instead of using a custom perl script to activate `/etc`, you activate it via an
overlay filesystem:
```nix
{ system.etc.overlay.enable = true; }
```
Using an overlay has two benefits:
1. it removes a dependency on perl
2. it makes activation faster (up to a few seconds)
By default, the `/etc` overlay is mounted writable (i.e. there is a writable
upper layer). However, you can also mount `/etc` immutably (i.e. read-only) by
setting:
```nix
{ system.etc.overlay.mutable = false; }
```
The overlay is atomically replaced during system switch. However, files that
have been modified will NOT be overwritten. This is the biggest change compared
to the perl-based system.
If you manually make changes to `/etc` on your system and then switch to a new
configuration where `system.etc.overlay.mutable = false;`, you will not be able
to see the previously made changes in `/etc` anymore. However the changes are
not completely gone, they are still in the upperdir of the previous overlay in
`/.rw-etc/upper`.

View File

@@ -0,0 +1,79 @@
# Freeform modules {#sec-freeform-modules}
Freeform modules allow you to define values for option paths that have
not been declared explicitly. This can be used to add attribute-specific
types to what would otherwise have to be `attrsOf` options in order to
accept all attribute names.
This feature can be enabled by using the attribute `freeformType` to
define a freeform type. By doing this, all assignments without an
associated option will be merged using the freeform type and combined
into the resulting `config` set. Since this feature nullifies name
checking for entire option trees, it is only recommended for use in
submodules.
::: {#ex-freeform-module .example}
### Freeform submodule
The following shows a submodule assigning a freeform type that allows
arbitrary attributes with `str` values below `settings`, but also
declares an option for the `settings.port` attribute to have it
type-checked and assign a default value. See
[Example: Declaring a type-checked `settings` attribute](#ex-settings-typed-attrs)
for a more complete example.
```nix
{ lib, config, ... }:
{
options.settings = lib.mkOption {
type = lib.types.submodule {
freeformType = with lib.types; attrsOf str;
# We want this attribute to be checked for the correct type
options.port = lib.mkOption {
type = lib.types.port;
# Declaring the option also allows defining a default value
default = 8080;
};
};
};
}
```
And the following shows what such a module then allows
```nix
{
# Not a declared option, but the freeform type allows this
settings.logLevel = "debug";
# Not allowed because the freeform type only allows strings
# settings.enable = true;
# Allowed because there is a port option declared
settings.port = 80;
# Not allowed because the port option doesn't allow strings
# settings.port = "443";
}
```
:::
::: {.note}
Freeform attributes cannot depend on other attributes of the same set
without infinite recursion:
```nix
{
# This throws infinite recursion encountered
settings.logLevel = lib.mkIf (config.settings.port == 80) "debug";
}
```
To prevent this, declare options for all attributes that need to depend
on others. For above example this means to declare `logLevel` to be an
option.
:::

View File

@@ -0,0 +1,23 @@
# Importing Modules {#sec-importing-modules}
Sometimes NixOS modules need to be used in configuration but exist
outside of Nixpkgs. These modules can be imported:
```nix
{
config,
lib,
pkgs,
...
}:
{
imports = [
# Use a locally-available module definition in
# ./example-module/default.nix
./example-module
];
services.exampleModule.enable = true;
}
```

View File

@@ -0,0 +1,6 @@
# Linking NixOS tests to packages {#sec-linking-nixos-tests-to-packages}
You can link NixOS module tests to the packages that they exercised,
so that the tests can be run automatically during code review when the package gets changed.
This is
[described in the nixpkgs manual](https://nixos.org/manual/nixpkgs/stable/#ssec-nixos-tests-linking).

View File

@@ -0,0 +1,73 @@
# Meta Attributes {#sec-meta-attributes}
Like Nix packages, NixOS modules can declare meta-attributes to provide
extra information. Module meta attributes are defined in the `meta.nix`
special module.
`meta` is a top level attribute like `options` and `config`. Available
meta-attributes are `maintainers`, `doc`, and `buildDocsInSandbox`.
Each of the meta-attributes must be defined at most once per module
file.
```nix
{
config,
lib,
pkgs,
...
}:
{
options = {
# ...
};
config = {
# ...
};
meta = {
maintainers = with lib.maintainers; [ ];
doc = ./default.md;
buildDocsInSandbox = true;
};
}
```
- `maintainers` contains a list of the module maintainers.
- `doc` points to a valid [Nixpkgs-flavored CommonMark](
https://nixos.org/manual/nixpkgs/unstable/#sec-contributing-markup
) file containing the module
documentation. Its contents is automatically added to
[](#ch-configuration). Changes to a module documentation have to
be checked to not break building the NixOS manual:
```ShellSession
$ nix-build nixos/release.nix -A manual.x86_64-linux
```
- `buildDocsInSandbox` indicates whether the option documentation for the
module can be built in a derivation sandbox. This option is currently only
honored for modules shipped by nixpkgs. User modules and modules taken from
`extraModules` are always built outside of the sandbox, as has
been the case in previous releases.
Building NixOS option documentation in a sandbox allows caching of the built
documentation, which greatly decreases the amount of time needed to evaluate
a system configuration that has NixOS documentation enabled. The sandbox also
restricts which attributes may be referenced by documentation attributes
(such as option descriptions) to the `options` and `lib` module arguments and
the `pkgs.formats` attribute of the `pkgs` argument, `config` and the rest of
`pkgs` are disallowed and will cause doc build failures when used. This
restriction is necessary because we cannot reproduce the full nixpkgs
instantiation with configuration and overlays from a system configuration
inside the sandbox. The `options` argument only includes options of modules
that are also built inside the sandbox, referencing an option of a module
that isn't built in the sandbox is also forbidden.
The default is `true` and should usually not be changed; set it to `false`
only if the module requires access to `pkgs` in its documentation (e.g.
because it loads information from a linked package to build an option type)
or if its documentation depends on other modules that also aren't sandboxed
(e.g. by using types defined in the other module).

View File

@@ -0,0 +1,111 @@
# Modular Services {#modular-services}
Status: in development. This functionality is new in NixOS 25.11, and significant changes should be expected. We'd love to hear your feedback in <https://github.com/NixOS/nixpkgs/pull/372170>
Traditionally, NixOS services were defined using sets of options *in* modules, not *as* modules. This made them non-modular, resulting in problems with composability, reuse, and portability.
A configuration management framework is an application of `evalModules` with the `class` and `specialArgs` input attribute set to particular values.
NixOS is such a configuration management framework, and so are [Home Manager](https://github.com/nix-community/home-manager) and [`nix-darwin`](https://github.com/lnl7/nix-darwin).
The service management component of a configuration management framework is the set of module options that connects Nix expressions with the underlying service (or process) manager.
For NixOS this is the module wrapping [`systemd`](https://systemd.io/), on `nix-darwin` this is the module wrapping [`launchd`](https://en.wikipedia.org/wiki/Launchd).
A *modular service* is a [module] that defines values for a core set of options declared in the service management component of a configuration management framework, including which program to run.
Since it's a module, it can be composed with other modules via `imports` to extend its functionality.
NixOS provides two options into which such modules can be plugged:
- `system.services.<name>`
- an option for user services (TBD)
Crucially, these options have the type [`attrsOf`] [`submodule`].
The name of the service is the attribute name corresponding to `attrsOf`.
<!-- ^ This is how composition is *always* provided, instead of a difficult thing (but this is reference docs, not a changelog) -->
The `submodule` is pre-loaded with two modules:
- a generic module that is intended to be portable
- a module with systemd-specific options, whose values or defaults derive from the generic module's option values.
So note that the default value of `system.services.<name>` is not a complete service. It requires that the user provide a value, and this is typically done by importing a module. For example:
<!-- Not using typical example syntax, because reading this is *not* optional, and should it should not be folded closed. -->
```nix
{
system.services.my-service-instance = {
imports = [ pkgs.some-application.services.some-service-module ];
foo.settings = {
# ...
};
};
}
```
## Portability {#modular-service-portability}
It is possible to write service modules that are portable. This is done by either avoiding the `systemd` option tree, or by defining process-manager-specific definitions in an optional way:
```nix
{
config,
options,
lib,
...
}:
{
_class = "service";
config = {
process.argv = [ (lib.getExe config.foo.program) ];
}
// lib.optionalAttrs (options ? systemd) {
# ... systemd-specific definitions ...
};
}
```
This way, the module can be loaded into a configuration manager that does not use systemd, and the `systemd` definitions will be ignored.
Similarly, other configuration managers can declare their own options for services to customize.
## Composition and Ownership {#modular-service-composition}
Compared to traditional services, modular services are inherently more composable, by virtue of being modules and receiving a user-provided name when imported.
However, composition can not end there, because services need to be able to interact with each other.
This can be achieved in two ways:
1. Users can link services together by providing the necessary NixOS configuration.
2. Services can be compositions of other services.
These aren't mutually exclusive. In fact, it is a good practice when developing services to first write them as individual services, and then compose them into a higher-level composition. Each of these services is a valid modular service, including their composition.
## Migration {#modular-service-migration}
Many services could be migrated to the modular service system, but even when the modular service system is mature, it is not necessary to migrate all services.
For instance, many system-wide services are a mandatory part of a desktop system, and it doesn't make sense to have multiple instances of them.
Moving their logic into separate Nix files may still be beneficial for the efficient evaluation of configurations that don't use those services, but that is a rather minor benefit, unless modular services potentially become the standard way to define services.
<!-- TODO example of a single-instance service -->
## Writing and Reviewing a Modular Service {#modular-service-review}
A typical service module consists of the following:
For more details, refer to the contributor documentation in [`nixos/README-modular-services.md`](https://github.com/NixOS/nixpkgs/blob/master/nixos/README-modular-services.md).
## Portable Service Options {#modular-service-options-portable}
```{=include=} options
id-prefix: service-opt-
list-id: service-options
source: @PORTABLE_SERVICE_OPTIONS@
```
## Systemd-specific Service Options {#modular-service-options-systemd}
```{=include=} options
id-prefix: systemd-service-opt-
list-id: systemd-service-options
source: @SYSTEMD_SERVICE_OPTIONS@
```
[module]: https://nixos.org/manual/nixpkgs/stable/index.html#module-system
<!-- TODO: more anchors -->
[`attrsOf`]: #sec-option-types-composed
[`submodule`]: #sec-option-types-submodule

View File

@@ -0,0 +1,14 @@
# NixOS Tests {#sec-nixos-tests}
When you add some feature to NixOS, you should write a test for it.
NixOS tests are kept in the directory `nixos/tests`, and are executed
(using Nix) by a testing framework that automatically starts one or more
virtual machines containing the NixOS system(s) required for the test.
```{=include=} sections
writing-nixos-tests.section.md
running-nixos-tests.section.md
running-nixos-tests-interactively.section.md
linking-nixos-tests-to-packages.section.md
testing-hardware-features.section.md
```

View File

@@ -0,0 +1,22 @@
# Non Switchable Systems {#sec-non-switchable-system}
In certain systems, most notably image based appliances, updates are handled
outside the system. This means that you do not need to rebuild your
configuration on the system itself anymore.
If you want to build such a system, you can use the `image-based-appliance`
profile:
```nix
{ modulesPath, ... }:
{
imports = [ "${modulesPath}/profiles/image-based-appliance.nix" ];
}
```
The most notable deviation of this profile from a standard NixOS configuration
is that after building it, you cannot switch *to* the configuration anymore.
The profile sets `config.system.switch.enable = false;`, which excludes
`switch-to-configuration`, the central script called by `nixos-rebuild`, from
your system. Removing this script makes the image lighter and slightly more
secure.

View File

@@ -0,0 +1,269 @@
# Option Declarations {#sec-option-declarations}
An option declaration specifies the name, type and description of a
NixOS configuration option. It is invalid to define an option that
hasn't been declared in any module. An option declaration generally
looks like this:
```nix
{
options = {
name = mkOption {
type = type specification;
default = default value;
example = example value;
description = "Description for use in the NixOS manual.";
};
};
}
```
The attribute names within the `name` attribute path must be camel
cased in general but should, as an exception, match the [ package
attribute name](https://nixos.org/nixpkgs/manual/#sec-package-naming)
when referencing a Nixpkgs package. For example, the option
`services.nix-serve.bindAddress` references the `nix-serve` Nixpkgs
package.
The function `mkOption` accepts the following arguments.
`type`
: The type of the option (see [](#sec-option-types)). This
argument is mandatory for nixpkgs modules. Setting this is highly
recommended for the sake of documentation and type checking. In case it is
not set, a fallback type with unspecified behavior is used.
`default`
: The default value used if no value is defined by any module. A
default is not required; but if a default is not given, then users
of the module will have to define the value of the option, otherwise
an error will be thrown.
`defaultText`
: A textual representation of the default value to be rendered verbatim in
the manual. Useful if the default value is a complex expression or depends
on other values or packages.
Use `lib.literalExpression` for a Nix expression, `lib.literalMD` for
a plain English description in [Nixpkgs-flavored Markdown](
https://nixos.org/nixpkgs/manual/#sec-contributing-markup) format.
`example`
: An example value that will be shown in the NixOS manual.
You can use `lib.literalExpression` and `lib.literalMD` in the same way
as in `defaultText`.
`description`
: A textual description of the option in [Nixpkgs-flavored Markdown](
https://nixos.org/nixpkgs/manual/#sec-contributing-markup) format that will be
included in the NixOS manual.
## Utility functions for common option patterns {#sec-option-declarations-util}
### `mkEnableOption` {#sec-option-declarations-util-mkEnableOption}
Creates an Option attribute set for a boolean value option i.e an
option to be toggled on or off.
This function takes a single string argument, the name of the thing to be toggled.
The option's description is "Whether to enable \<name\>.".
For example:
::: {#ex-options-declarations-util-mkEnableOption-magic .example}
### `mkEnableOption` usage
```nix
lib.mkEnableOption "magic"
# is like
lib.mkOption
{
type = lib.types.bool;
default = false;
example = true;
description = "Whether to enable magic.";
}
```
:::
### `mkPackageOption` {#sec-option-declarations-util-mkPackageOption}
Usage:
```nix
mkPackageOption pkgs "name" {
default = [
"path"
"in"
"pkgs"
];
example = "literal example";
}
```
Creates an Option attribute set for an option that specifies the package a module should use for some purpose.
**Note**: You should make package options for your modules, where applicable. While one can always overwrite a specific package throughout nixpkgs by using [nixpkgs overlays](https://nixos.org/manual/nixpkgs/stable/#chap-overlays), they slow down nixpkgs evaluation significantly and are harder to debug when issues arise.
The package is specified in the third argument under `default` as a list of strings
representing its attribute path in nixpkgs (or another package set).
Because of this, you need to pass nixpkgs itself (or a subset) as the first argument.
The second argument may be either a string or a list of strings.
It provides the display name of the package in the description of the generated option
(using only the last element if the passed value is a list)
and serves as the fallback value for the `default` argument.
To include extra information in the description, pass `extraDescription` to
append arbitrary text to the generated description.
You can also pass an `example` value, either a literal string or an attribute path.
The default argument can be omitted if the provided name is
an attribute of pkgs (if name is a string) or a
valid attribute path in pkgs (if name is a list).
If you wish to explicitly provide no default, pass `null` as `default`.
[]{#ex-options-declarations-util-mkPackageOption}
Examples:
::: {#ex-options-declarations-util-mkPackageOption-hello .example}
### Simple `mkPackageOption` usage
```nix
lib.mkPackageOption pkgs "hello" { }
# is like
lib.mkOption
{
type = lib.types.package;
default = pkgs.hello;
defaultText = lib.literalExpression "pkgs.hello";
description = "The hello package to use.";
}
```
:::
::: {#ex-options-declarations-util-mkPackageOption-ghc .example}
### `mkPackageOption` with explicit default and example
```nix
lib.mkPackageOption pkgs "GHC"
{
default = [ "ghc" ];
example = "pkgs.haskellPackages.ghc.withPackages (hkgs: [ hkgs.primes ])";
}
# is like
lib.mkOption
{
type = lib.types.package;
default = pkgs.ghc;
defaultText = lib.literalExpression "pkgs.ghc";
example = lib.literalExpression "pkgs.haskellPackages.ghc.withPackages (hkgs: [ hkgs.primes ])";
description = "The GHC package to use.";
}
```
:::
::: {#ex-options-declarations-util-mkPackageOption-extraDescription .example}
### `mkPackageOption` with additional description text
```nix
mkPackageOption pkgs [ "python312Packages" "torch" ]
{
extraDescription = "This is an example and doesn't actually do anything.";
}
# is like
lib.mkOption
{
type = lib.types.package;
default = pkgs.python312Packages.torch;
defaultText = lib.literalExpression "pkgs.python312Packages.torch";
description = "The pytorch package to use. This is an example and doesn't actually do anything.";
}
```
:::
## Extensible Option Types {#sec-option-declarations-eot}
Extensible option types is a feature that allows to extend certain types
declaration through multiple module files. This feature only work with a
restricted set of types, namely `enum` and `submodules` and any composed
forms of them.
Extensible option types can be used for `enum` options that affects
multiple modules, or as an alternative to related `enable` options.
As an example, we will take the case of display managers. There is a
central display manager module for generic display manager options and a
module file per display manager backend (sddm, gdm ...).
There are two approaches we could take with this module structure:
- Configuring the display managers independently by adding an enable
option to every display manager module backend. (NixOS)
- Configuring the display managers in the central module by adding
an option to select which display manager backend to use.
Both approaches have problems.
Making backends independent can quickly become hard to manage. For
display managers, there can only be one enabled at a time, but the
type system cannot enforce this restriction as there is no relation
between each backend's `enable` option. As a result, this restriction
has to be done explicitly by adding assertions in each display manager
backend module.
On the other hand, managing the display manager backends in the
central module will require changing the central module option every
time a new backend is added or removed.
By using extensible option types, it is possible to create a placeholder
option in the central module
([Example: Extensible type placeholder in the service module](#ex-option-declaration-eot-service)),
and to extend it in each backend module
([Example: Extending `services.xserver.displayManager.enable` in the `gdm` module](#ex-option-declaration-eot-backend-gdm),
[Example: Extending `services.xserver.displayManager.enable` in the `sddm` module](#ex-option-declaration-eot-backend-sddm)).
As a result, `displayManager.enable` option values can be added without
changing the main service module file and the type system automatically
enforces that there can only be a single display manager enabled.
::: {#ex-option-declaration-eot-service .example}
### Extensible type placeholder in the service module
```nix
{
services.xserver.displayManager.enable = mkOption {
description = "Display manager to use";
type = with types; nullOr (enum [ ]);
};
}
```
:::
::: {#ex-option-declaration-eot-backend-gdm .example}
### Extending `services.xserver.displayManager.enable` in the `gdm` module
```nix
{
services.xserver.displayManager.enable = mkOption { type = with types; nullOr (enum [ "gdm" ]); };
}
```
:::
::: {#ex-option-declaration-eot-backend-sddm .example}
### Extending `services.xserver.displayManager.enable` in the `sddm` module
```nix
{
services.xserver.displayManager.enable = mkOption { type = with types; nullOr (enum [ "sddm" ]); };
}
```
:::
The placeholder declaration is a standard `mkOption` declaration, but it
is important that extensible option declarations only use the `type`
argument.
Extensible option types work with any of the composed variants of `enum`
such as `with types; nullOr (enum [ "foo" "bar" ])` or `with types;
listOf (enum [ "foo" "bar" ])`.

View File

@@ -0,0 +1,204 @@
# Option Definitions {#sec-option-definitions}
Option definitions are generally straight-forward bindings of values to
option names, like
```nix
{
config = {
services.httpd.enable = true;
};
}
```
However, sometimes you need to wrap an option definition or set of
option definitions in a *property* to achieve certain effects:
## Delaying Conditionals {#sec-option-definitions-delaying-conditionals}
If a set of option definitions is conditional on the value of another
option, you may need to use `mkIf`. Consider, for instance:
```nix
{
config =
if config.services.httpd.enable then
{
environment.systemPackages = [
# ...
];
# ...
}
else
{ };
}
```
This definition will cause Nix to fail with an "infinite recursion"
error. Why? Because the value of `config.services.httpd.enable` depends
on the value being constructed here. After all, you could also write the
clearly circular and contradictory:
```nix
{
config =
if config.services.httpd.enable then
{
services.httpd.enable = false;
}
else
{
services.httpd.enable = true;
};
}
```
The solution is to write:
```nix
{
config = mkIf config.services.httpd.enable {
environment.systemPackages = [
# ...
];
# ...
};
}
```
The special function `mkIf` causes the evaluation of the conditional to
be "pushed down" into the individual definitions, as if you had written:
```nix
{
config = {
environment.systemPackages =
if config.services.httpd.enable then
[
# ...
]
else
[ ];
# ...
};
}
```
## Setting Priorities {#sec-option-definitions-setting-priorities}
A module can override the definitions of an option in other modules by
setting an *override priority*. All option definitions that do not have the lowest
priority value are discarded. By default, option definitions have
priority 100 and option defaults have priority 1500.
You can specify an explicit priority by using `mkOverride`, e.g.
```nix
{ services.openssh.enable = mkOverride 10 false; }
```
This definition causes all other definitions with priorities above 10 to
be discarded. The function `mkForce` is equal to `mkOverride 50`, and
`mkDefault` is equal to `mkOverride 1000`.
## Ordering Definitions {#sec-option-definitions-ordering}
It is also possible to influence the order in which the definitions for an option are
merged by setting an *order priority* with `mkOrder`. The default order priority is 1000.
The functions `mkBefore` and `mkAfter` are equal to `mkOrder 500` and `mkOrder 1500`, respectively.
As an example,
```nix
{ hardware.firmware = mkBefore [ myFirmware ]; }
```
This definition ensures that `myFirmware` comes before other unordered
definitions in the final list value of `hardware.firmware`.
Note that this is different from [override priorities](#sec-option-definitions-setting-priorities):
setting an order does not affect whether the definition is included or not.
## Merging Configurations {#sec-option-definitions-merging}
In conjunction with `mkIf`, it is sometimes useful for a module to
return multiple sets of option definitions, to be merged together as if
they were declared in separate modules. This can be done using
`mkMerge`:
```nix
{
config = mkMerge [
# Unconditional stuff.
{
environment.systemPackages = [
# ...
];
}
# Conditional stuff.
(mkIf config.services.bla.enable {
environment.systemPackages = [
# ...
];
})
];
}
```
## Free-floating definitions {#sec-option-definitions-definitions}
:::{.note}
The module system internally transforms module syntax into definitions. This always happens internally.
:::
It is possible to create first class definitions which are not transformed _again_ into definitions by the module system.
Usually the file location of a definition is implicit and equal to the file it came from.
However, when manipulating definitions, it may be useful for them to be completely self-contained (or "free-floating").
A free-floating definition is created with `mkDefinition { file = ...; value = ...; }`.
Preserving the file location creates better error messages, for example when copying definitions from one option to another.
Other properties like `mkOverride` `mkMerge` `mkAfter` can be used in the `value` attribute but not on the entire definition.
This is what would work
```nix
mkDefinition {
value = mkForce 42;
file = "somefile.nix";
}
```
While this would NOT work.
```nix
mkForce (mkDefinition {
value = 42;
file = "somefile.nix";
})
```
The following shows an example configuration that yields an error with the custom position information:
```nix
{
_file = "file.nix";
options.foo = mkOption { default = 13; };
config.foo = lib.mkDefinition {
file = "custom place";
# mkOptionDefault creates a conflict with the option foo's `default = 1` on purpose
# So we see the error message below contains the conflicting values and different positions
value = lib.mkOptionDefault 42;
};
}
```
evaluating the module yields the following error:
```
error: Cannot merge definitions of `foo'. Definition values:
- In `file.nix': 13
- In `custom place': 42
```
To set the file location for all definitions in a module, you may add the `_file` module syntax attribute, which has a similar effect to using `mkDefinition` on all definitions in the module, without the hassle.

View File

@@ -0,0 +1,795 @@
# Options Types {#sec-option-types}
Option types are a way to put constraints on the values a module option
can take. Types are also responsible of how values are merged in case of
multiple value definitions.
## Basic types {#sec-option-types-basic}
Basic types are the simplest available types in the module system. Basic
types include multiple string types that mainly differ in how definition
merging is handled.
`types.bool`
: A boolean, its values can be `true` or `false`.
All definitions must have the same value, after priorities. An error is thrown in case of a conflict.
`types.boolByOr`
: A boolean, its values can be `true` or `false`.
The result is `true` if _any_ of multiple definitions is `true`.
In other words, definitions are merged with the logical _OR_ operator.
`types.path`
: A filesystem path that starts with a slash. Even if derivations can be
considered as paths, the more specific `types.package` should be preferred.
`types.pathInStore`
: A path that is contained in the Nix store. This can be a top-level store
path like `pkgs.hello` or a descendant like `"${pkgs.hello}/bin/hello"`.
`types.externalPath`
: A path that is not contained in the Nix store. Typical use cases are:
secrets, password or any other external file.
::: {.warning}
This type only validates that the path is not *currently* in the Nix store.
It does NOT prevent the value from being copied to the store later when:
- Referenced in a derivation
- Used in certain path operations (e.g., `${path}` interpolation)
- Passed to functions that copy to the store
Users must still be careful about how they reference these paths.
:::
`types.pathWith` { *`inStore`* ? `null`, *`absolute`* ? `null` }
: A filesystem path. Either a string or something that can be coerced
to a string.
**Parameters**
`inStore` (`Boolean` or `null`, default `null`)
: Whether the path must be in the store (`true`), must not be in the store
(`false`), or it doesn't matter (`null`)
`absolute` (`Boolean` or `null`, default `null`)
: Whether the path must be absolute (`true`), must not be absolute
(`false`), or it doesn't matter (`null`)
**Behavior**
- `pathWith { inStore = true; }` is equivalent to `pathInStore`
- `pathWith { absolute = true; }` is equivalent to `path`
- `pathWith { inStore = false; absolute = true; }` requires an absolute
path that is not in the store. Useful for password files that shouldn't be
leaked into the store.
`types.package`
: A top-level store path. This can be an attribute set pointing
to a store path, like a derivation or a flake input.
`types.enum` *`l`*
: One element of the list *`l`*, e.g. `types.enum [ "left" "right" ]`.
Multiple definitions cannot be merged.
If you want to pair these values with more information, possibly of
distinct types, consider using a [sum type](#sec-option-types-sums).
`types.anything`
: A type that accepts any value and recursively merges attribute sets
together. This type is recommended when the option type is unknown.
::: {#ex-types-anything .example}
### `types.anything`
Two definitions of this type like
```nix
{
str = lib.mkDefault "foo";
pkg.hello = pkgs.hello;
fun.fun = x: x + 1;
}
```
```nix
{
str = lib.mkIf true "bar";
pkg.gcc = pkgs.gcc;
fun.fun = lib.mkForce (x: x + 2);
}
```
will get merged to
```nix
{
str = "bar";
pkg.gcc = pkgs.gcc;
pkg.hello = pkgs.hello;
fun.fun = x: x + 2;
}
```
:::
`types.raw`
: A type which doesn't do any checking, merging or nested evaluation. It
accepts a single arbitrary value that is not recursed into, making it
useful for values coming from outside the module system, such as package
sets or arbitrary data. Options of this type are still evaluated according
to priorities and conditionals, so `mkForce`, `mkIf` and co. still work on
the option value itself, but not for any value nested within it. This type
should only be used when checking, merging and nested evaluation are not
desirable.
`types.optionType`
: The type of an option's type. Its merging operation ensures that nested
options have the correct file location annotated, and that if possible,
multiple option definitions are correctly merged together. The main use
case is as the type of the `_module.freeformType` option.
`types.attrs`
: A free-form attribute set.
::: {.warning}
This type will be deprecated in the future because it doesn't
recurse into attribute sets, silently drops earlier attribute
definitions, and doesn't discharge `lib.mkDefault`, `lib.mkIf`
and co. For allowing arbitrary attribute sets, prefer
`types.attrsOf types.anything` instead which doesn't have these
problems.
:::
`types.pkgs`
: A type for the top level Nixpkgs package set.
### Numeric types {#sec-option-types-numeric}
`types.int`
: A signed integer.
`types.ints.{s8, s16, s32}`
: Signed integers with a fixed length (8, 16 or 32 bits). They go from
2^n/2 to
2^n/21 respectively (e.g. `128` to
`127` for 8 bits).
`types.ints.unsigned`
: An unsigned integer (that is >= 0).
`types.ints.{u8, u16, u32}`
: Unsigned integers with a fixed length (8, 16 or 32 bits). They go
from 0 to 2^n1 respectively (e.g. `0`
to `255` for 8 bits).
`types.ints.between` *`lowest highest`*
: An integer between *`lowest`* and *`highest`* (both inclusive).
`types.ints.positive`
: A positive integer (that is > 0).
`types.port`
: A port number. This type is an alias to
`types.ints.u16`.
`types.float`
: A floating point number.
::: {.warning}
Converting a floating point number to a string with `toString` or `toJSON`
may result in [precision loss](https://github.com/NixOS/nix/issues/5733).
:::
`types.number`
: Either a signed integer or a floating point number. No implicit conversion
is done between the two types, and multiple equal definitions will only be
merged if they have the same type.
`types.numbers.between` *`lowest highest`*
: An integer or floating point number between *`lowest`* and *`highest`* (both inclusive).
`types.numbers.nonnegative`
: A nonnegative integer or floating point number (that is >= 0).
`types.numbers.positive`
: A positive integer or floating point number (that is > 0).
### String types {#sec-option-types-string}
`types.str`
: A string. Multiple definitions cannot be merged.
`types.separatedString` *`sep`*
: A string. Multiple definitions are concatenated with *`sep`*, e.g.
`types.separatedString "|"`.
`types.lines`
: A string. Multiple definitions are concatenated with a new line
`"\n"`.
`types.commas`
: A string. Multiple definitions are concatenated with a comma `","`.
`types.envVar`
: A string. Multiple definitions are concatenated with a colon `":"`.
`types.strMatching`
: A string matching a specific regular expression. Multiple
definitions cannot be merged. The regular expression is processed
using `builtins.match`.
### Specialised types {#sec-option-types-specialised}
`types.luaInline`
: A string wrapped using `lib.mkLuaInline`. Allows embedding lua expressions
inline within generated lua. Multiple definitions cannot be merged.
## Submodule types {#sec-option-types-submodule}
Submodules are detailed in [Submodule](#section-option-types-submodule).
`types.submodule` *`o`*
: A set of sub options *`o`*. *`o`* can be an attribute set, a function
returning an attribute set, or a path to a file containing such a
value. Submodules are used in composed types to create modular
options. This is equivalent to
`types.submoduleWith { modules = toList o; shorthandOnlyDefinesConfig = true; }`.
`types.submoduleWith` { *`modules`*, *`specialArgs`* ? {}, *`shorthandOnlyDefinesConfig`* ? false }
: Like `types.submodule`, but more flexible and with better defaults.
It has parameters
- *`modules`* A list of modules to use by default for this
submodule type. This gets combined with all option definitions
to build the final list of modules that will be included.
::: {.note}
Only options defined with this argument are included in rendered
documentation.
:::
- *`specialArgs`* An attribute set of extra arguments to be passed
to the module functions. The option `_module.args` should be
used instead for most arguments since it allows overriding.
*`specialArgs`* should only be used for arguments that can't go
through the module fixed-point, because of infinite recursion or
other problems. An example is overriding the `lib` argument,
because `lib` itself is used to define `_module.args`, which
makes using `_module.args` to define it impossible.
- *`shorthandOnlyDefinesConfig`* Whether definitions of this type
should default to the `config` section of a module (see
[Example: Structure of NixOS Modules](#ex-module-syntax))
if it is an attribute set. Enabling this only has a benefit
when the submodule defines an option named `config` or `options`.
In such a case it would allow the option to be set with
`the-submodule.config = "value"` instead of requiring
`the-submodule.config.config = "value"`. This is because
only when modules *don't* set the `config` or `options`
keys, all keys are interpreted as option definitions in the
`config` section. Enabling this option implicitly puts all
attributes in the `config` section.
With this option enabled, defining a non-`config` section
requires using a function:
`the-submodule = { ... }: { options = { ... }; }`.
`types.deferredModule`
: Whereas `submodule` represents an option tree, `deferredModule` represents
a module value, such as a module file or a configuration.
It can be set multiple times.
Module authors can use its value in `imports`, in `submoduleWith`'s `modules`
or in `evalModules`' `modules` parameter, among other places.
Note that `imports` must be evaluated before the module fixpoint. Because
of this, deferred modules can only be imported into "other" fixpoints, such
as submodules.
One use case for this type is the type of a "default" module that allow the
user to affect all submodules in an `attrsOf submodule` at once. This is
more convenient and discoverable than expecting the module user to
type-merge with the `attrsOf submodule` option.
## Union types {#sec-option-types-unions}
A union of types is a type such that a value is valid when it is valid for at least one of those types.
If some values are instances of more than one of the types, it is not possible to distinguish which type they are meant to be instances of. If that's needed, consider using a [sum type](#sec-option-types-sums).
<!-- SYNC WITH oneOf BELOW -->
`types.either` *`t1 t2`*
: Type *`t1`* or type *`t2`*, e.g. `with types; either int str`.
Multiple definitions cannot be merged.
::: {.warning}
`either` and `oneOf` eagerly decide the active type based on the passed types' shallow check method. For composite types like `attrsOf` and `submodule`, which both match all attribute set definitions, the first type argument will be chosen for the returned option value, and this therefore also decides how nested values are checked and merged. For example, `either (attrsOf int) (submodule {...})` will always use `attrsOf int` for any attribute set value, even if it was intended as a submodule. This behavior is a trade-off that keeps the implementation simple and the evaluation order predictable, avoiding unexpected strictness problems such as infinite recursions. When proper type discrimination is needed, consider using a [sum type](#sec-option-types-sums) like `attrTag` instead.
:::
<!-- SYNC WITH either ABOVE -->
`types.oneOf` \[ *`t1 t2`* ... \]
: Type *`t1`* or type *`t2`* and so forth, e.g.
`with types; oneOf [ int str bool ]`. Multiple definitions cannot be
merged.
::: {.warning}
`either` and `oneOf` eagerly decide the active type based on the passed types' shallow check method. For composite types like `attrsOf` and `submodule`, which both match all attribute set definitions, the first matching type in the list will be chosen for the returned option value, and this therefore also decides how nested values are checked and merged. For example, `oneOf [ (attrsOf int) (submodule {...}) ]` will always use `attrsOf int` for any attribute set value, even if it was intended as a submodule. This behavior is a trade-off that keeps the implementation simple and the evaluation order predictable, avoiding unexpected strictness problems such as infinite recursions. When proper type discrimination is needed, consider using a [sum type](#sec-option-types-sums) like `attrTag` instead.
:::
`types.nullOr` *`t`*
: `null` or type *`t`*. Multiple definitions are merged according to
type *`t`*.
This is mostly equivalent to `either (enum [ null ]) t`, but `nullOr` provides a `null` fallback for attribute values with `mkIf false` definitions in `lazyAttrsOf (nullOr t)`, whereas `either` would throw an error when the attribute is accessed.
## Sum types {#sec-option-types-sums}
A sum type can be thought of, conceptually, as a *`types.enum`* where each valid item is paired with at least a type, through some value syntax.
Nix does not have a built-in syntax for this pairing of a label and a type or value, so sum types may be represented in multiple ways.
If the you're interested in can be distinguished without a label, you may simplify your value syntax with a [union type](#sec-option-types-unions) instead.
`types.attrTag` *`{ attr1 = option1; attr2 = option2; ... }`*
: An attribute set containing one attribute, whose name must be picked from
the attribute set (`attr1`, etc) and whose value consists of definitions that are valid for the corresponding option (`option1`, etc).
This type appears in the documentation as _attribute-tagged union_.
Example:
```nix
{ lib, ... }:
let inherit (lib) type mkOption;
in {
options.toyRouter.rules = mkOption {
description = ''
Rules for a fictional packet routing service.
'';
type = types.attrsOf (
types.attrTag {
bounce = mkOption {
description = "Send back a packet explaining why it wasn't forwarded.";
type = types.submodule {
options.errorMessage = mkOption { … };
};
};
forward = mkOption {
description = "Forward the packet.";
type = types.submodule {
options.destination = mkOption { … };
};
};
drop = types.mkOption {
description = "Drop the packet without sending anything back.";
type = types.submodule {};
};
});
};
config.toyRouter.rules = {
http = {
bounce = {
errorMessage = "Unencrypted HTTP is banned. You must always use https://.";
};
};
ssh = { drop = {}; };
};
}
```
## Composed types {#sec-option-types-composed}
Composed types are types that take a type as parameter. `listOf
int` and `either int str` are examples of composed types.
`types.listOf` *`t`*
: A list of *`t`* type, e.g. `types.listOf
int`. Multiple definitions are merged with list concatenation.
`types.attrsOf` *`t`*
: An attribute set of where all the values are of *`t`* type. Multiple
definitions result in the joined attribute set.
::: {.note}
This type is *strict* in its values, which in turn means attributes
cannot depend on other attributes. See `
types.lazyAttrsOf` for a lazy version.
:::
`types.lazyAttrsOf` *`t`*
: An attribute set of where all the values are of *`t`* type. Multiple
definitions result in the joined attribute set. This is the lazy
version of `types.attrsOf
`, allowing attributes to depend on each other.
::: {.warning}
This version does not fully support conditional definitions! With an
option `foo` of this type and a definition
`foo.attr = lib.mkIf false 10`, evaluating `foo ? attr` will return
`true` even though it should be false. Accessing the value will then
throw an error. For types *`t`* that have an `emptyValue` defined,
that value will be returned instead of throwing an error. So if the
type of `foo.attr` was `lazyAttrsOf (nullOr int)`, `null` would be
returned instead for the same `mkIf false` definition.
:::
`types.attrsWith` { *`elemType`*, *`lazy`* ? false, *`placeholder`* ? "name" }
: An attribute set of where all the values are of *`elemType`* type.
**Parameters**
`elemType` (Required)
: Specifies the type of the values contained in the attribute set.
`lazy`
: Determines whether the attribute set is lazily evaluated. See: `types.lazyAttrsOf`
`placeholder` (`String`, default: `name` )
: Placeholder string in documentation for the attribute names.
The default value `name` results in the placeholder `<name>`
**Behavior**
- `attrsWith { elemType = t; }` is equivalent to `attrsOf t`
- `attrsWith { lazy = true; elemType = t; }` is equivalent to `lazyAttrsOf t`
- `attrsWith { placeholder = "id"; elemType = t; }`
Displays the option as `foo.<id>` in the manual.
`types.uniq` *`t`*
: Ensures that type *`t`* cannot be merged. It is used to ensure option
definitions are provided only once.
`types.unique` `{ message = m }` *`t`*
: Ensures that type *`t`* cannot be merged. Prints the message *`m`*, after
the line `The option <option path> is defined multiple times.` and before
a list of definition locations.
`types.coercedTo` *`from f to`*
: Type *`to`* or type *`from`* which will be coerced to type *`to`* using
function *`f`* which takes an argument of type *`from`* and return a
value of type *`to`*. Can be used to preserve backwards compatibility
of an option if its type was changed.
## Submodule {#section-option-types-submodule}
`submodule` is a very powerful type that defines a set of sub-options
that are handled like a separate module.
It takes a parameter *`o`*, that should be a set, or a function returning
a set with an `options` key defining the sub-options. Submodule option
definitions are type-checked accordingly to the `options` declarations.
Of course, you can nest submodule option definitions for even higher
modularity.
The option set can be defined directly
([Example: Directly defined submodule](#ex-submodule-direct)) or as reference
([Example: Submodule defined as a reference](#ex-submodule-reference)).
Note that even if your submodules options all have a default value,
you will still need to provide a default value (e.g. an empty attribute set)
if you want to allow users to leave it undefined.
::: {#ex-submodule-direct .example}
### Directly defined submodule
```nix
{
options.mod = mkOption {
description = "submodule example";
type =
with types;
submodule {
options = {
foo = mkOption { type = int; };
bar = mkOption { type = str; };
};
};
};
}
```
:::
::: {#ex-submodule-reference .example}
### Submodule defined as a reference
```nix
let
modOptions = {
options = {
foo = mkOption { type = int; };
bar = mkOption { type = int; };
};
};
in
{
options.mod = mkOption {
description = "submodule example";
type = with types; submodule modOptions;
};
}
```
:::
The `submodule` type is especially interesting when used with composed
types like `attrsOf` or `listOf`. When composed with `listOf`
([Example: Declaration of a list of submodules](#ex-submodule-listof-declaration)), `submodule` allows
multiple definitions of the submodule option set
([Example: Definition of a list of submodules](#ex-submodule-listof-definition)).
::: {#ex-submodule-listof-declaration .example}
### Declaration of a list of submodules
```nix
{
options.mod = mkOption {
description = "submodule example";
type =
with types;
listOf (submodule {
options = {
foo = mkOption { type = int; };
bar = mkOption { type = str; };
};
});
};
}
```
:::
::: {#ex-submodule-listof-definition .example}
### Definition of a list of submodules
```nix
{
config.mod = [
{
foo = 1;
bar = "one";
}
{
foo = 2;
bar = "two";
}
];
}
```
:::
When composed with `attrsOf`
([Example: Declaration of attribute sets of submodules](#ex-submodule-attrsof-declaration)), `submodule` allows
multiple named definitions of the submodule option set
([Example: Definition of attribute sets of submodules](#ex-submodule-attrsof-definition)).
::: {#ex-submodule-attrsof-declaration .example}
### Declaration of attribute sets of submodules
```nix
{
options.mod = mkOption {
description = "submodule example";
type =
with types;
attrsOf (submodule {
options = {
foo = mkOption { type = int; };
bar = mkOption { type = str; };
};
});
};
}
```
:::
::: {#ex-submodule-attrsof-definition .example}
### Definition of attribute sets of submodules
```nix
{
config.mod.one = {
foo = 1;
bar = "one";
};
config.mod.two = {
foo = 2;
bar = "two";
};
}
```
:::
## Extending types {#sec-option-types-extending}
Types are mainly characterized by their `check` and `merge` functions.
`check`
: The function to type check the value. Takes a value as parameter and
return a boolean. It is possible to extend a type check with the
`addCheck` function ([Example: Adding a type check](#ex-extending-type-check-1)),
or to fully override the check function
([Example: Overriding a type check](#ex-extending-type-check-2)).
::: {#ex-extending-type-check-1 .example}
### Adding a type check
```nix
{
byte = mkOption {
description = "An integer between 0 and 255.";
type = types.addCheck types.int (x: x >= 0 && x <= 255);
};
}
```
:::
::: {#ex-extending-type-check-2 .example}
### Overriding a type check
```nix
{
nixThings = mkOption {
description = "words that start with 'nix'";
type = types.str // {
check = (x: lib.hasPrefix "nix" x);
};
};
}
```
:::
`merge`
: Function to merge the options values when multiple values are set.
The function takes two parameters, `loc` the option path as a list
of strings, and `defs` the list of defined values as a list. It is
possible to override a type merge function for custom needs.
## Custom types {#sec-option-types-custom}
Custom types can be created with the `mkOptionType` function. As type
creation includes some more complex topics such as submodule handling,
it is recommended to get familiar with `types.nix` code before creating
a new type.
The only required parameter is `name`.
`name`
: A string representation of the type function name.
`description`
: Description of the type used in documentation. Give information of
the type and any of its arguments.
`check`
: A function to type check the definition value. Takes the definition
value as a parameter and returns a boolean indicating the type check
result, `true` for success and `false` for failure.
`merge`
: A function to merge multiple definitions values. Takes two
parameters:
*`loc`*
: The option path as a list of strings, e.g. `["boot" "loader
"grub" "enable"]`.
*`defs`*
: The list of sets of defined `value` and `file` where the value
was defined, e.g. `[ {
file = "/foo.nix"; value = 1; } { file = "/bar.nix"; value = 2 }
]`. The `merge` function should return the merged value
or throw an error in case the values are impossible or not meant
to be merged.
`getSubOptions`
: For composed types that can take a submodule as type parameter, this
function generate sub-options documentation. It takes the current
option prefix as a list and return the set of sub-options. Usually
defined in a recursive manner by adding a term to the prefix, e.g.
`prefix:
elemType.getSubOptions (prefix ++
["prefix"])` where *`"prefix"`* is the newly added prefix.
`getSubModules`
: For composed types that can take a submodule as type parameter, this
function should return the type parameters submodules. If the type
parameter is called `elemType`, the function should just recursively
look into submodules by returning `elemType.getSubModules;`.
`substSubModules`
: For composed types that can take a submodule as type parameter, this
function can be used to substitute the parameter of a submodule
type. It takes a module as parameter and return the type with the
submodule options substituted. It is usually defined as a type
function call with a recursive call to `substSubModules`, e.g for a
type `composedType` that take an `elemtype` type parameter, this
function should be defined as `m:
composedType (elemType.substSubModules m)`.
`typeMerge`
: A function to merge multiple type declarations. Takes the type to
merge `functor` as parameter. A `null` return value means that type
cannot be merged.
*`f`*
: The type to merge `functor`.
Note: There is a generic `defaultTypeMerge` that work with most of
value and composed types.
`functor`
: An attribute set representing the type. It is used for type
operations and has the following keys:
`type`
: The type function.
`wrapped`
: Holds the type parameter for composed types.
`payload`
: Holds the value parameter for value types. The types that have a
`payload` are the `enum`, `separatedString` and `submodule`
types.
`binOp`
: A binary operation that can merge the payloads of two same
types. Defined as a function that take two payloads as
parameters and return the payloads merged.

View File

@@ -0,0 +1,80 @@
# Replace Modules {#sec-replace-modules}
Modules that are imported can also be disabled. The option declarations,
config implementation and the imports of a disabled module will be
ignored, allowing another to take its place. This can be used to
import a set of modules from another channel while keeping the rest of
the system on a stable release.
`disabledModules` is a top level attribute like `imports`, `options` and
`config`. It contains a list of modules that will be disabled. This can
either be:
- the full path to the module,
- or a string with the filename relative to the modules path (eg. \<nixpkgs/nixos/modules> for nixos),
- or an attribute set containing a specific `key` attribute.
The latter allows some modules to be disabled, despite them being distributed
via attributes instead of file paths. The `key` should be globally unique, so
it is recommended to include a file path in it, or rely on a framework to do it
for you.
This example will replace the existing postgresql module with the
version defined in the nixos-unstable channel while keeping the rest of
the modules and packages from the original nixos channel. This only
overrides the module definition, this won't use postgresql from
nixos-unstable unless explicitly configured to do so.
```nix
{
config,
lib,
pkgs,
...
}:
{
disabledModules = [ "services/databases/postgresql.nix" ];
imports = [
# Use postgresql service from nixos-unstable channel.
# sudo nix-channel --add https://channels.nixos.org/nixos-unstable nixos-unstable
<nixos-unstable/nixos/modules/services/databases/postgresql.nix>
];
services.postgresql.enable = true;
}
```
This example shows how to define a custom module as a replacement for an
existing module. Importing this module will disable the original module
without having to know its implementation details.
```nix
{
config,
lib,
pkgs,
...
}:
let
inherit (lib) mkIf mkOption types;
cfg = config.programs.man;
in
{
disabledModules = [ "services/programs/man.nix" ];
options = {
programs.man.enable = mkOption {
type = types.bool;
default = true;
description = "Whether to enable manual pages.";
};
};
config = mkIf cfg.enabled {
warnings = [ "disabled manpages for production deployments." ];
};
}
```

View File

@@ -0,0 +1,171 @@
# Running Tests interactively {#sec-running-nixos-tests-interactively}
The test itself can be run interactively. This is particularly useful
when developing or debugging a test:
```ShellSession
$ nix-build . -A nixosTests.login.driverInteractive
$ ./result/bin/nixos-test-driver
[...]
>>>
```
::: {.note}
By executing the test driver in this way,
the VMs executed may gain network & Internet access via their backdoor control interface,
typically recognized as `eth0`.
:::
You can then take any Python statement, e.g.
```py
>>> start_all()
>>> test_script()
>>> machine.succeed("touch /tmp/foo")
>>> print(machine.succeed("pwd")) # Show stdout of command
```
The function `test_script` executes the entire test script and drops you
back into the test driver command line upon its completion. This allows
you to inspect the state of the VMs after the test (e.g. to debug the
test script).
## Shell access in interactive mode {#sec-nixos-test-shell-access}
The function `<yourmachine>.shell_interact()` grants access to a shell running
inside a virtual machine. To use it, replace `<yourmachine>` with the name of a
virtual machine defined in the test, for example: `machine.shell_interact()`.
Keep in mind that this shell may not display everything correctly as it is
running within an interactive Python REPL, and logging output from the virtual
machine may overwrite input and output from the guest shell:
```py
>>> machine.shell_interact()
machine: Terminal is ready (there is no initial prompt):
$ hostname
machine
```
As an alternative, you can proxy the guest shell to a local TCP server by first
starting a TCP server in a terminal using the command:
```ShellSession
$ socat 'READLINE,PROMPT=$ ' tcp-listen:4444,reuseaddr
```
In the terminal where the test driver is running, connect to this server by
using:
```py
>>> machine.shell_interact("tcp:127.0.0.1:4444")
```
Once the connection is established, you can enter commands in the socat terminal
where socat is running.
## SSH Access for test machines {#sec-nixos-test-ssh-access}
An SSH-based backdoor to log into machines can be enabled with
```nix
{
name = "";
nodes.machines = {
# …
};
interactive.sshBackdoor.enable = true;
}
```
::: {.warning}
Make sure to only enable the backdoor for interactive tests
(i.e. by using `interactive.sshBackdoor.enable`)! This is the only
supported configuration.
Running a test in a sandbox with this will fail because `/dev/vhost-vsock` isn't available
in the sandbox.
:::
This creates a [vsock socket](https://man7.org/linux/man-pages/man7/vsock.7.html)
for each VM to log in with SSH. This configures root login with an empty password.
When the VMs get started interactively with the test-driver, it's possible to
connect to `machine` with
```
$ ssh vsock/3 -o User=root
```
The socket numbers correspond to the node number of the test VM, but start
at three instead of one because that's the lowest possible
vsock number. The exact SSH commands are also printed out when starting
`nixos-test-driver`.
On non-NixOS systems you'll probably need to enable
the SSH config from {manpage}`systemd-ssh-proxy(1)` yourself.
If starting VM fails with an error like
```
qemu-system-x86_64: -device vhost-vsock-pci,guest-cid=3: vhost-vsock: unable to set guest cid: Address already in use
```
it means that the vsock numbers for the VMs are already in use. This can happen
if another interactive test with SSH backdoor enabled is running on the machine.
In that case, you need to assign another range of vsock numbers. You can pick another
offset with
```nix
{
sshBackdoor = {
enable = true;
vsockOffset = 23542;
};
}
```
## Port forwarding to NixOS test VMs {#sec-nixos-test-port-forwarding}
If your test has only a single VM, you may use e.g.
```ShellSession
$ QEMU_NET_OPTS="hostfwd=tcp:127.0.0.1:2222-:22" ./result/bin/nixos-test-driver
```
to port-forward a port in the VM (here `22`) to the host machine (here port `2222`).
This naturally does not work when multiple machines are involved,
since a single port on the host cannot forward to multiple VMs.
If the test defines multiple machines, you may opt to _temporarily_ set
`virtualisation.forwardPorts` in the test definition for debugging.
Such port forwardings connect via the VM's virtual network interface.
Thus they cannot connect to ports that are only bound to the VM's
loopback interface (`127.0.0.1`), and the VM's NixOS firewall
must be configured to allow these connections.
## Reuse VM state {#sec-nixos-test-reuse-vm-state}
You can re-use the VM states coming from a previous run by setting the
`--keep-vm-state` flag.
```ShellSession
$ ./result/bin/nixos-test-driver --keep-vm-state
```
The machine state is stored in the `$TMPDIR/vm-state-machinename`
directory.
## Interactive-only test configuration {#sec-nixos-test-interactive-configuration}
The `.driverInteractive` attribute combines the regular test configuration with
definitions from the [`interactive` submodule](#test-opt-interactive). This gives you
a more usable, graphical, but slightly different configuration.
You can add your own interactive-only test configuration by adding extra
configuration to the [`interactive` submodule](#test-opt-interactive).
To interactively run only the regular configuration, build the `<test>.driver` attribute
instead, and call it with the flag `result/bin/nixos-test-driver --interactive`.

View File

@@ -0,0 +1,30 @@
# Running Tests {#sec-running-nixos-tests}
You can run tests using `nix-build`. For example, to run the test
[`login.nix`](https://github.com/NixOS/nixpkgs/blob/master/nixos/tests/login.nix),
you do:
```ShellSession
$ cd /my/git/clone/of/nixpkgs
$ nix-build -A nixosTests.login
```
After building/downloading all required dependencies, this will perform
a build that starts a QEMU/KVM virtual machine containing a NixOS
system. The virtual machine mounts the Nix store of the host; this makes
VM creation very fast, as no disk image needs to be created. Afterwards,
you can view a log of the test:
```ShellSession
$ nix-store --read-log result
```
## System Requirements {#sec-running-nixos-tests-requirements}
NixOS tests require virtualization support.
This means that the machine must have `kvm` in its [system features](https://nixos.org/manual/nix/stable/command-ref/conf-file.html?highlight=system-features#conf-system-features) list, or `apple-virt` in case of macOS.
These features are autodetected locally, but `apple-virt` is only autodetected since Nix 2.19.0.
Features of **remote builders** must additionally be configured manually on the client, e.g. on NixOS with [`nix.buildMachines.*.supportedFeatures`](https://search.nixos.org/options?show=nix.buildMachines.*.supportedFeatures&sort=alpha_asc&query=nix.buildMachines) or through general [Nix configuration](https://nixos.org/manual/nix/stable/advanced-topics/distributed-builds).
If you run the tests on a **macOS** machine, you also need a "remote" builder for Linux; possibly a VM. [nix-darwin](https://daiderd.com/nix-darwin/) users may enable [`nix.linux-builder.enable`](https://daiderd.com/nix-darwin/manual/index.html#opt-nix.linux-builder.enable) to launch such a VM.

View File

@@ -0,0 +1,629 @@
# Options for Program Settings {#sec-settings-options}
Many programs have configuration files where program-specific settings
can be declared. File formats can be separated into two categories:
- Nix-representable ones: These can trivially be mapped to a subset of
Nix syntax. E.g. JSON is an example, since its values like
`{"foo":{"bar":10}}` can be mapped directly to Nix:
`{ foo = { bar = 10; }; }`. Other examples are INI, YAML and TOML.
The following section explains the convention for these settings.
- Non-nix-representable ones: These can't be trivially mapped to a
subset of Nix syntax. Most generic programming languages are in this
group, e.g. bash, since the statement `if true; then echo hi; fi`
doesn't have a trivial representation in Nix.
Currently there are no fixed conventions for these, but it is common
to have a `configFile` option for setting the configuration file
path directly. The default value of `configFile` can be an
auto-generated file, with convenient options for controlling the
contents. For example an option of type `attrsOf str` can be used
for representing environment variables which generates a section
like `export FOO="foo"`. Often it can also be useful to also include
an `extraConfig` option of type `lines` to allow arbitrary text
after the autogenerated part of the file.
## Nix-representable Formats (JSON, YAML, TOML, INI, ...) {#sec-settings-nix-representable}
By convention, formats like this are handled with a generic `settings`
option, representing the full program configuration as a Nix value. The
type of this option should represent the format. The most common formats
have a predefined type and string generator already declared under
`pkgs.formats`:
`pkgs.formats.javaProperties` { *`comment`* ? `"Generated with Nix"` }
: A function taking an attribute set with values
`comment`
: A string to put at the start of the
file in a comment. It can have multiple
lines.
It returns the `type`: `attrsOf str` and a function
`generate` to build a Java `.properties` file, taking
care of the correct escaping, etc.
`pkgs.formats.hocon` { *`generator`* ? `<derivation>`, *`validator`* ? `<derivation>`, *`doCheck`* ? true }
: A function taking an attribute set with values
`generator`
: A derivation used for converting the JSON output
from the nix settings into HOCON. This might be
useful if your HOCON variant is slightly different
from the java-based one, or for testing purposes.
`validator`
: A derivation used for verifying that the HOCON
output is correct and parsable. This might be
useful if your HOCON variant is slightly different
from the java-based one, or for testing purposes.
`doCheck`
: Whether to enable/disable the validator check.
It returns an attrset with a `type`, `generate` function,
and a `lib` attset, as specified [below](#pkgs-formats-result).
Some of the lib functions will be best understood if you have
read the reference specification. You can find this
specification here:
<https://github.com/lightbend/config/blob/main/HOCON.md>
Inside of `lib`, you will find these functions
`mkInclude`
: This is used together with a specially named
attribute `includes`, to include other HOCON
sources into the document.
The function has a shorthand variant where it
is up to the HOCON parser to figure out what type
of include is being used. The include will default
to being non-required. If you want to be more
explicit about the details of the include, you can
provide an attrset with following arguments
`required`
: Whether the parser should fail upon failure
to include the document
`type`
: Type of the source of the included document.
Valid values are `file`, `url` and `classpath`.
See upstream documentation for the semantics
behind each value
`value`
: The URI/path/classpath pointing to the source of
the document to be included.
`Example usage:`
```nix
let
format = pkgs.formats.hocon { };
hocon_file = pkgs.writeText "to_include.hocon" ''
a = 1;
'';
in {
some.nested.hocon.attrset = {
_includes = [
(format.lib.mkInclude hocon_file)
(format.lib.mkInclude "https://example.com/to_include.hocon")
(format.lib.mkInclude {
required = true;
type = "file";
value = include_file;
})
];
...
};
}
```
`mkAppend`
: This is used to invoke the `+=` operator.
This can be useful if you need to add something
to a list that is included from outside of nix.
See upstream documentation for the semantics
behind the `+=` operation.
`Example usage:`
```nix
let
format = pkgs.formats.hocon { };
hocon_file = pkgs.writeText "to_include.hocon" ''
a = [ 1 ];
b = [ 2 ];
'';
in {
_includes = [
(format.lib.mkInclude hocon_file)
];
c = 3;
a = format.lib.mkAppend 3;
b = format.lib.mkAppend (format.lib.mkSubstitution "c");
}
```
`mkSubstitution`
: This is used to make HOCON substitutions.
Similarly to `mkInclude`, this function has
a shorthand variant where you just give it
the string with the substitution value.
The substitution is not optional by default.
Alternatively, you can provide an attrset
with more options
`optional`
: Whether the parser should fail upon
failure to fetch the substitution value.
`value`
: The name of the variable to use for
substitution.
See upstream documentation for semantics
behind the substitution functionality.
`Example usage:`
```nix
let
format = pkgs.formats.hocon { };
in {
a = 1;
b = format.lib.mkSubstitution "a";
c = format.lib.mkSubstitution "SOME_ENVVAR";
d = format.lib.mkSubstitution {
value = "SOME_OPTIONAL_ENVVAR";
optional = true;
};
}
```
`Implementation notes:`
- classpath includes are not implemented in pyhocon,
which is used for validating the HOCON output. This
means that if you are using classpath includes,
you will want to either use an alternative validator
or set `doCheck = false` in the format options.
`pkgs.formats.libconfig` { *`generator`* ? `<derivation>`, *`validator`* ? `<derivation>` }
: A function taking an attribute set with values
`generator`
: A derivation used for converting the JSON output
from the nix settings into libconfig. This might be
useful if your libconfig variant is slightly different
from the original one, or for testing purposes.
`validator`
: A derivation used for verifying that the libconfig
output is correct and parsable. This might be
useful if your libconfig variant is slightly different
from the original one, or for testing purposes.
It returns an attrset with a `type`, `generate` function,
and a `lib` attset, as specified [below](#pkgs-formats-result).
Some of the lib functions will be best understood if you have
read the reference specification. You can find this
specification here:
<https://hyperrealm.github.io/libconfig/libconfig_manual.html#Configuration-Files>
Inside of `lib`, you will find these functions
`mkHex`, `mkOctal`, `mkFloat`
: Use these to specify numbers in other formats.
`Example usage:`
```nix
let
format = pkgs.formats.libconfig { };
in {
myHexValue = format.lib.mkHex "0x1FC3";
myOctalValue = format.lib.mkOctal "0027";
myFloatValue = format.lib.mkFloat "1.2E-3";
}
```
`mkArray`, `mkList`
: Use these to differentiate between whether
a nix list should be considered as a libconfig
array or a libconfig list. See the upstream
documentation for the semantics behind these types.
`Example usage:`
```nix
let
format = pkgs.formats.libconfig { };
in {
myList = format.lib.mkList [ "foo" 1 true ];
myArray = format.lib.mkArray [ 1 2 3 ];
}
```
`Implementation notes:`
- Since libconfig does not allow setting names to start with an underscore,
this is used as a prefix for both special types and include directives.
- The difference between 32bit and 64bit values became optional in libconfig
1.5, so we assume 64bit values for all numbers.
`pkgs.formats.json` { }
: A function taking an empty attribute set (for future extensibility)
and returning a set with JSON-specific attributes `type` and
`generate` as specified [below](#pkgs-formats-result).
`pkgs.formats.yaml` { }
: A function taking an empty attribute set (for future extensibility)
and returning a set with YAML-specific attributes `type` and
`generate` as specified [below](#pkgs-formats-result).
`pkgs.formats.ini` { *`listsAsDuplicateKeys`* ? false, *`listToValue`* ? null, \.\.\. }
: A function taking an attribute set with values
`listsAsDuplicateKeys`
: A boolean for controlling whether list values can be used to
represent duplicate INI keys
`listToValue`
: A function for turning a list of values into a single value.
It returns a set with INI-specific attributes `type` and `generate`
as specified [below](#pkgs-formats-result).
The type of the input is an *attrset* of sections; key-value pairs where
the key is the section name and the value is the corresponding content
which is also an *attrset* of key-value pairs for the actual key-value
mappings of the INI format.
The values of the INI atoms are subject to the above parameters (e.g. lists
may be transformed into multiple key-value pairs depending on
`listToValue`).
The attribute `lib.type.atom` contains the used INI atom.
`pkgs.formats.iniWithGlobalSection` { *`listsAsDuplicateKeys`* ? false, *`listToValue`* ? null, \.\.\. }
: A function taking an attribute set with values
`listsAsDuplicateKeys`
: A boolean for controlling whether list values can be used to
represent duplicate INI keys
`listToValue`
: A function for turning a list of values into a single value.
It returns a set with INI-specific attributes `type` and `generate`
as specified [below](#pkgs-formats-result).
The type of the input is an *attrset* of the structure
`{ sections = {}; globalSection = {}; }` where *sections* are several
sections as with *pkgs.formats.ini* and *globalSection* being just a single
attrset of key-value pairs for a single section, the global section which
precedes the section definitions.
The attribute `lib.type.atom` contains the used INI atom.
`pkgs.formats.toml` { }
: A function taking an empty attribute set (for future extensibility)
and returning a set with TOML-specific attributes `type` and
`generate` as specified [below](#pkgs-formats-result).
`pkgs.formats.xml` { format ? "badgerfish", withHeader ? true}
: A function taking an attribute set with values
and returning a set with XML-specific attributes `type` and
`generate` as specified [below](#pkgs-formats-result).
`format`
: Input format. Because XML can not be translated one-to-one, we have to use intermediate formats. Possible values:
- `"badgerfish"`: Uses [badgerfish](http://www.sklar.com/badgerfish/) conversion.
`withHeader`
: Outputs the xml with header.
`pkgs.formats.plist` { escape ? true }
: A function taking an attribute set with values
`escape`
: Whether to escape XML special characters in string values and keys.
It returns a set with Property list (plist) specific attributes `type` and `generate` as specified [below](#pkgs-formats-result).
`pkgs.formats.pythonVars` { }
: A function taking an empty attribute set (for future extensibility)
and returning a set with python variable specific attributes `type`, `lib`, and
`generate` as specified [below](#pkgs-formats-result).
The `lib` attribute contains functions to be used in settings, for
generating special Python values:
`mkRaw pythonCode`
: Outputs the given string as raw Python code
`_imports`
`_imports` is a special value you can set to specify additional modules to be
imported on top of the file.
`Example usage:`
```nix
let
format = pkgs.formats.pythonVars { };
in {
_imports = [ "re" ];
conditional = format.lib.mkRaw "1 if True else 2";
function_result = format.lib.mkRaw "re.findall(r'\\bf[a-z]*', 'which foot or hand fell fastest')";
}
```
`pkgs.formats.cdn` { }
: A function taking an empty attribute set (for future extensibility)
and returning a set with [CDN](https://github.com/dzikoysk/cdn)-specific
attributes `type` and `generate` as specified [below](#pkgs-formats-result).
`pkgs.formats.elixirConf { elixir ? pkgs.elixir }`
: A function taking an attribute set with values
`elixir`
: The Elixir package which will be used to format the generated output
It returns a set with Elixir-Config-specific attributes `type`, `lib`, and
`generate` as specified [below](#pkgs-formats-result).
The `lib` attribute contains functions to be used in settings, for
generating special Elixir values:
`mkRaw elixirCode`
: Outputs the given string as raw Elixir code
`mkGetEnv { envVariable, fallback ? null }`
: Makes the configuration fetch an environment variable at runtime
`mkAtom atom`
: Outputs the given string as an Elixir atom, instead of the default
Elixir binary string. Note: lowercase atoms still needs to be prefixed
with `:`
`mkTuple array`
: Outputs the given array as an Elixir tuple, instead of the default
Elixir list
`mkMap attrset`
: Outputs the given attribute set as an Elixir map, instead of the
default Elixir keyword list
`pkgs.formats.lua { asBindings ? false, multiline ? true, columnWidth ? 100, indentWidth ? 2, indentUsingTabs ? false }`
: A function taking an attribute set with values
`asBindings` (default `false`)
: Whether to treat attributes as variable bindings
`multiline` (default `true`)
: Whether to produce a multiline output. The output may still wrap across
multiple lines if it would otherwise exceed `columnWidth`.
`columnWidth` (default `100`)
: The column width to use to attempt to wrap lines.
`indentWidth` (default `2`)
: The width of a single indentation level.
`indentUsingTabs` (default `false`)
: Whether the indentation should use tabs instead of spaces.
`pkgs.formats.php { finalVariable }` []{#pkgs-formats-php}
: A function taking an attribute set with values
`finalVariable`
: The variable that will store generated expression (usually `config`). If set to `null`, generated expression will contain `return`.
It returns a set with PHP-Config-specific attributes `type`, `lib`, and
`generate` as specified [below](#pkgs-formats-result).
The `lib` attribute contains functions to be used in settings, for
generating special PHP values:
`mkRaw phpCode`
: Outputs the given string as raw PHP code
`mkMixedArray list set`
: Creates PHP array that contains both indexed and associative values. For example, `lib.mkMixedArray [ "hello" "world" ] { "nix" = "is-great"; }` returns `['hello', 'world', 'nix' => 'is-great']`
[]{#pkgs-formats-result}
These functions all return an attribute set with these values:
`type`
: A module system type representing a value of the format
`lib`
: Utility functions for convenience, or special interactions with the format.
This attribute is optional. It may contain inside a `types` attribute
containing types specific to this format.
`generate` *`filename jsonValue`*
: A function that can render a value of the format to a file. Returns
a file path.
::: {.note}
This function puts the value contents in the Nix store. So this
should be avoided for secrets.
:::
::: {#ex-settings-nix-representable .example}
### Module with conventional `settings` option
The following shows a module for an example program that uses a JSON
configuration file. It demonstrates how above values can be used, along
with some other related best practices. See the comments for
explanations.
```nix
{
options,
config,
lib,
pkgs,
...
}:
let
cfg = config.services.foo;
# Define the settings format used for this program
settingsFormat = pkgs.formats.json { };
in
{
options.services.foo = {
enable = lib.mkEnableOption "foo service";
settings = lib.mkOption {
# Setting this type allows for correct merging behavior
type = settingsFormat.type;
default = { };
description = ''
Configuration for foo, see
<link xlink:href="https://example.com/docs/foo"/>
for supported settings.
'';
};
};
config = lib.mkIf cfg.enable {
# We can assign some default settings here to make the service work by just
# enabling it. We use `mkDefault` for values that can be changed without
# problems
services.foo.settings = {
# Fails at runtime without any value set
log_level = lib.mkDefault "WARN";
# We assume systemd's `StateDirectory` is used, so we require this value,
# therefore no mkDefault
data_path = "/var/lib/foo";
# Since we use this to create a user we need to know the default value at
# eval time
user = lib.mkDefault "foo";
};
environment.etc."foo.json".source =
# The formats generator function takes a filename and the Nix value
# representing the format value and produces a filepath with that value
# rendered in the format
settingsFormat.generate "foo-config.json" cfg.settings;
# We know that the `user` attribute exists because we set a default value
# for it above, allowing us to use it without worries here
users.users.${cfg.settings.user} = {
isSystemUser = true;
};
# ...
};
}
```
:::
### Option declarations for attributes {#sec-settings-attrs-options}
Some `settings` attributes may deserve some extra care. They may need a
different type, default or merging behavior, or they are essential
options that should show their documentation in the manual. This can be
done using [](#sec-freeform-modules).
We extend above example using freeform modules to declare an option for
the port, which will enforce it to be a valid integer and make it show
up in the manual.
::: {#ex-settings-typed-attrs .example}
### Declaring a type-checked `settings` attribute
```nix
{
settings = lib.mkOption {
type = lib.types.submodule {
freeformType = settingsFormat.type;
# Declare an option for the port such that the type is checked and this option
# is shown in the manual.
options.port = lib.mkOption {
type = lib.types.port;
default = 8080;
description = ''
Which port this service should listen on.
'';
};
};
default = { };
description = ''
Configuration for Foo, see
<link xlink:href="https://example.com/docs/foo"/>
for supported values.
'';
};
}
```
:::

View File

@@ -0,0 +1,77 @@
# Getting the Sources {#sec-getting-sources}
By default, NixOS's `nixos-rebuild` command uses the NixOS and Nixpkgs
sources provided by the `nixos` channel (kept in
`/nix/var/nix/profiles/per-user/root/channels/nixos`). To modify NixOS,
however, you should check out the latest sources from Git. This is as
follows:
```ShellSession
$ git clone https://github.com/NixOS/nixpkgs
$ cd nixpkgs
$ git remote update origin
```
This will check out the latest Nixpkgs sources to `./nixpkgs` the NixOS
sources to `./nixpkgs/nixos`. (The NixOS source tree lives in a
subdirectory of the Nixpkgs repository.) The `nixpkgs` repository has
branches that correspond to each Nixpkgs/NixOS channel (see
[](#sec-upgrading) for more information about channels). Thus, the
Git branch `origin/nixos-17.03` will contain the latest built and tested
version available in the `nixos-17.03` channel.
It's often inconvenient to develop directly on the master branch, since
if somebody has just committed (say) a change to GCC, then the binary
cache may not have caught up yet and you'll have to rebuild everything
from source. So you may want to create a local branch based on your
current NixOS version:
```ShellSession
$ nixos-version
17.09pre104379.6e0b727 (Hummingbird)
$ git checkout -b local 6e0b727
```
Or, to base your local branch on the latest version available in a NixOS
channel:
```ShellSession
$ git remote update origin
$ git checkout -b local origin/nixos-17.03
```
(Replace `nixos-17.03` with the name of the channel you want to use.)
You can use `git merge` or `git
rebase` to keep your local branch in sync with the channel, e.g.
```ShellSession
$ git remote update origin
$ git merge origin/nixos-17.03
```
You can use `git cherry-pick` to copy commits from your local branch to
the upstream branch.
If you want to rebuild your system using your (modified) sources, you
need to tell `nixos-rebuild` about them using the `-I` flag:
```ShellSession
# nixos-rebuild switch -I nixpkgs=/my/sources/nixpkgs
```
If you want `nix-env` to use the expressions in `/my/sources`, use
`nix-env -f
/my/sources/nixpkgs`, or change the default by adding a symlink in
`~/.nix-defexpr`:
```ShellSession
$ ln -s /my/sources/nixpkgs ~/.nix-defexpr/nixpkgs
```
You may want to delete the symlink `~/.nix-defexpr/channels_root` to
prevent root's NixOS channel from clashing with your own tree (this may
break the command-not-found utility though). If you want to go back to
the default state, you may just remove the `~/.nix-defexpr` directory
completely, log out and log in again and it should have been recreated
with a link to the root channels.

View File

@@ -0,0 +1,161 @@
# Testing Hardware Features {#sec-nixos-test-testing-hardware-features}
This section covers how to test various features using NixOS tests that would
normally only be possible with hardware. It is designed to showcase the NixOS test
framework's flexibility when combined with various hardware simulation libraries
or kernel modules.
## Wi-Fi {#sec-nixos-test-wifi}
Use `services.vwifi` to set up a virtual Wi-Fi physical layer. Create at least two nodes
for this kind of test: one with vwifi active, and either a station or an access point.
Give each a static IP address on the test network so they will never collide.
This module likely supports other topologies too; document them if you make one.
This NixOS module leverages [vwifi](https://github.com/Raizo62/vwifi). Read the
upstream repository's documentation for more information.
### vwifi server {#sec-nixos-test-wifi-vwifi-server}
This node runs the vwifi server, and otherwise does not interact with the network.
You can run `vwifi-ctrl` on this node to control characteristics of the simulated
physical layer.
```nix
{
airgap =
{ config, ... }:
{
networking.interfaces.eth1.ipv4.addresses = lib.mkForce [
{
address = "192.168.1.2";
prefixLength = 24;
}
];
services.vwifi = {
server = {
enable = true;
ports.tcp = 8212;
# uncomment if you want to enable monitor mode on another node
# ports.spy = 8213;
openFirewall = true;
};
};
};
}
```
### AP {#sec-nixos-test-wifi-ap}
A node like this will act as a wireless access point in infrastructure mode.
```nix
{
ap =
{ config, ... }:
{
networking.interfaces.eth1.ipv4.addresses = lib.mkForce [
{
address = "192.168.1.3";
prefixLength = 24;
}
];
services.hostapd = {
enable = true;
radios.wlan0 = {
channel = 1;
networks.wlan0 = {
ssid = "NixOS Test Wi-Fi Network";
authentication = {
mode = "wpa3-sae";
saePasswords = [ { password = "supersecret"; } ];
enableRecommendedPairwiseCiphers = true;
};
};
};
};
services.vwifi = {
module = {
enable = true;
macPrefix = "74:F8:F6:00:01";
};
client = {
enable = true;
serverAddress = "192.168.1.2";
};
};
};
}
```
### Station {#sec-nixos-test-wifi-station}
A node like this acts as a wireless client.
```nix
{
station =
{ config, ... }:
{
networking.interfaces.eth1.ipv4.addresses = lib.mkForce [
{
address = "192.168.1.3";
prefixLength = 24;
}
];
networking.wireless = {
# No, really, we want it enabled!
enable = lib.mkOverride 0 true;
interfaces = [ "wlan0" ];
networks = {
"NixOS Test Wi-Fi Network" = {
psk = "supersecret";
authProtocols = [ "SAE" ];
};
};
};
services.vwifi = {
module = {
enable = true;
macPrefix = "74:F8:F6:00:02";
};
client = {
enable = true;
serverAddress = "192.168.1.2";
};
};
};
}
```
### Monitor {#sec-nixos-test-wifi-monitor}
When the monitor mode interface is enabled, this node will receive
all packets broadcast by all other nodes through the spy interface.
```nix
{
monitor =
{ config, ... }:
{
networking.interfaces.eth1.ipv4.addresses = lib.mkForce [
{
address = "192.168.1.4";
prefixLength = 24;
}
];
services.vwifi = {
module = {
enable = true;
macPrefix = "74:F8:F6:00:03";
};
client = {
enable = true;
spy = true;
serverAddress = "192.168.1.2";
};
};
};
}
```

View File

@@ -0,0 +1,18 @@
# Testing the Installer {#ch-testing-installer}
Building, burning, and booting from an installation CD is rather
tedious, so here is a quick way to see if the installer works properly:
```ShellSession
# mount -t tmpfs none /mnt
# nixos-generate-config --root /mnt
$ nix-build '<nixpkgs>' -A nixos-install
# ./result/bin/nixos-install
```
To start a login shell in the new NixOS installation in `/mnt`:
```ShellSession
$ nix-build '<nixpkgs>' -A nixos-enter
# ./result/bin/nixos-enter
```

View File

@@ -0,0 +1,111 @@
# Unit handling {#sec-unit-handling}
To figure out what units need to be started/stopped/restarted/reloaded, the
script first checks the current state of the system, similar to what `systemctl
list-units` shows. For each of the units, the script goes through the following
checks:
- Is the unit file still in the new system? If not, **stop** the service unless
it sets `X-StopOnRemoval` in the `[Unit]` section to `false`.
- Is it a `.target` unit? If so, **start** it unless it sets
`RefuseManualStart` in the `[Unit]` section to `true` or `X-OnlyManualStart`
in the `[Unit]` section to `true`. Also **stop** the unit again unless it
sets `X-StopOnReconfiguration` to `false`.
- Are the contents of the unit files different? They are compared by parsing
them and comparing their contents. If they are different but only
`X-Reload-Triggers` in the `[Unit]` section is changed, **reload** the unit.
The NixOS module system allows setting these triggers with the option
[systemd.services.\<name\>.reloadTriggers](#opt-systemd.services). There are
some additional keys in the `[Unit]` section that are ignored as well. If the
unit files differ in any way, the following actions are performed:
- `.path` and `.slice` units are ignored. There is no need to restart them
since changes in their values are applied by systemd when systemd is
reloaded.
- `.mount` units are **reload**ed if only their `Options` changed. If anything
else changed (like `What`), they are **restart**ed unless they are the mount
unit for `/` or `/nix` in which case they are reloaded to prevent the system
from crashing. Note that this is the case for `.mount` units and not for
mounts from `/etc/fstab`. These are explained in [](#sec-switching-systems).
- `.socket` units are currently ignored. This is to be fixed at a later
point.
- The rest of the units (mostly `.service` units) are then **reload**ed if
`X-ReloadIfChanged` in the `[Service]` section is set to `true` (exposed
via [systemd.services.\<name\>.reloadIfChanged](#opt-systemd.services)).
A little exception is done for units that were deactivated in the meantime,
for example because they require a unit that got stopped before. These
are **start**ed instead of reloaded.
- If the reload flag is not set, some more flags decide if the unit is
skipped. These flags are `X-RestartIfChanged` in the `[Service]` section
(exposed via
[systemd.services.\<name\>.restartIfChanged](#opt-systemd.services)),
`RefuseManualStop` in the `[Unit]` section, and `X-OnlyManualStart` in the
`[Unit]` section.
- Further behavior depends on the unit having `X-StopIfChanged` in the
`[Service]` section set to `true` (exposed via
[systemd.services.\<name\>.stopIfChanged](#opt-systemd.services)). This is
set to `true` by default and must be explicitly turned off if not wanted.
If the flag is enabled, the unit is **stop**ped and then **start**ed. If
not, the unit is **restart**ed. The goal of the flag is to make sure that
the new unit never runs in the old environment which is still in place
before the activation script is run. This behavior is different when the
service is socket-activated, as outlined in the following steps.
- The last thing that is taken into account is whether the unit is a
service and socket-activated. A correspondence between a
`.service` and its `.socket` unit is detected automatically, but
services can **opt out** of that detection by setting
`X-NotSocketActivated` to `yes` in their `[Service]`
section. Otherwise, if `X-StopIfChanged` is **not** set, the
service is **restart**ed with the others. If it is set, both the
service and the socket are **stop**ped and the socket is
**start**ed, leaving socket activation to start the service when
it's needed.
## Sysinit reactivation {#sec-sysinit-reactivation}
[`sysinit.target`](https://www.freedesktop.org/software/systemd/man/latest/systemd.special.html#sysinit.target)
is a systemd target that encodes system initialization (i.e. early startup). A
few units that need to run very early in the bootup process are ordered to
finish before this target is reached. Probably the most notable one of these is
`systemd-tmpfiles-setup.service`. We will refer to these units as "sysinit
units".
"Normal" systemd units, by default, are ordered AFTER `sysinit.target`. In
other words, these "normal" units expect all services ordered before
`sysinit.target` to have finished without explicitly declaring this dependency
relationship for each dependency. See the [systemd
bootup](https://www.freedesktop.org/software/systemd/man/latest/bootup.html)
for more details on the bootup process.
When restarting both a unit ordered before `sysinit.target` as well as one
after, this presents a problem because they would be started at the same time
as they do not explicitly declare their dependency relations.
To solve this, NixOS has an artificial `sysinit-reactivation.target` which
allows you to ensure that services ordered before `sysinit.target` are
restarted correctly. This applies both to the ordering between these sysinit
services as well as ensuring that sysinit units are restarted before "normal"
units.
To make an existing sysinit service restart correctly during system switch, you
have to declare:
```nix
{
systemd.services.my-sysinit = {
requiredBy = [ "sysinit-reactivation.target" ];
before = [ "sysinit-reactivation.target" ];
restartTriggers = [ config.environment.etc."my-sysinit.d".source ];
};
}
```
You need to configure appropriate `restartTriggers` specific to your service.

View File

@@ -0,0 +1,62 @@
# What happens during a system switch? {#sec-switching-systems}
Running `nixos-rebuild switch` is one of the more common tasks under NixOS.
This chapter explains some of the internals of this command to make it simpler
for new module developers to configure their units correctly and to make it
easier to understand what is happening and why for curious administrators.
`nixos-rebuild`, like many deployment solutions, calls `switch-to-configuration`
which resides in a NixOS system at `$out/bin/switch-to-configuration`. The
script is called with the action that is to be performed like `switch`, `test`,
`boot`. There is also the `dry-activate` action which does not really perform
the actions but rather prints what it would do if you called it with `test`.
This feature can be used to check what service states would be changed if the
configuration was switched to.
If the action is `switch` or `boot`, the bootloader is updated first so the
configuration will be the next one to boot. Unless `NIXOS_NO_SYNC` is set to
`1`, `/nix/store` is synced to disk.
If the action is `switch` or `test`, the currently running system is inspected
and the actions to switch to the new system are calculated. This process takes
two data sources into account: `/etc/fstab` and the current systemd status.
Mounts and swaps are read from `/etc/fstab` and the corresponding actions are
generated. If the options of a mount are modified, for example, the proper `.mount`
unit is reloaded (or restarted if anything else changed and it's neither the root
mount or the nix store). The current systemd state is inspected, the difference
between the current system and the desired configuration is calculated and
actions are generated to get to this state. There are a lot of nuances that can
be controlled by the units which are explained here.
After calculating what should be done, the actions are carried out. The order
of actions is always the same:
- Stop units (`systemctl stop`)
- Run activation script (`$out/activate`)
- See if the activation script requested more units to restart
- Restart systemd if needed (`systemd daemon-reexec`)
- Forget about the failed state of units (`systemctl reset-failed`)
- Reload systemd (`systemctl daemon-reload`)
- Reload systemd user instances (`systemctl --user daemon-reload`)
- Reactivate sysinit (`systemctl restart sysinit-reactivation.target`)
- Reload units (`systemctl reload`)
- Restart units (`systemctl restart`)
- Start units (`systemctl start`)
- Inspect what changed during these actions and print units that failed and
that were newly started
By default, some units are filtered from the outputs to make it less spammy.
This can be disabled for development or testing by setting the environment variable
`STC_DISPLAY_ALL_UNITS=1`.
More detailed output can be displayed by setting `STC_DEBUG=1`.
Most of these actions are either self-explaining but some of them have to do
with our units or the activation script. For this reason, these topics are
explained in the next sections.
```{=include=} sections
unit-handling.section.md
activation-script.section.md
non-switchable-systems.section.md
etc-overlay.section.md
```

View File

@@ -0,0 +1,31 @@
# Writing NixOS Documentation {#sec-writing-documentation}
As NixOS grows, so too does the need for a catalogue and explanation of
its extensive functionality. Collecting pertinent information from
disparate sources and presenting it in an accessible style would be a
worthy contribution to the project.
## Building the Manual {#sec-writing-docs-building-the-manual}
The sources of the [](#book-nixos-manual) are in the
[`nixos/doc/manual`](https://github.com/NixOS/nixpkgs/tree/master/nixos/doc/manual)
subdirectory of the Nixpkgs repository.
You can quickly validate your edits with `devmode`:
```ShellSession
$ cd /path/to/nixpkgs/nixos/doc/manual
$ nix-shell
[nix-shell:~]$ devmode
```
Once you are done making modifications to the manual, it's important to
build it before committing. You can do that as follows:
```ShellSession
nix-build nixos/release.nix -A manual.x86_64-linux
```
When this command successfully finishes, it will tell you where the
manual got generated. The HTML will be accessible through the `result`
symlink at `./result/share/doc/nixos/index.html`.

View File

@@ -0,0 +1,223 @@
# Writing NixOS Modules {#sec-writing-modules}
NixOS has a modular system for declarative configuration. This system
combines multiple *modules* to produce the full system configuration.
One of the modules that constitute the configuration is
`/etc/nixos/configuration.nix`. Most of the others live in the
[`nixos/modules`](https://github.com/NixOS/nixpkgs/tree/master/nixos/modules)
subdirectory of the Nixpkgs tree.
Each NixOS module is a file that handles one logical aspect of the
configuration, such as a specific kind of hardware, a service, or
network settings. A module configuration does not have to handle
everything from scratch; it can use the functionality provided by other
modules for its implementation. Thus a module can *declare* options that
can be used by other modules, and conversely can *define* options
provided by other modules in its own implementation. For example, the
module
[`pam.nix`](https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/security/pam.nix)
declares the option `security.pam.services` that allows other modules (e.g.
[`sshd.nix`](https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/services/networking/ssh/sshd.nix))
to define PAM services; and it defines the option `environment.etc` (declared by
[`etc.nix`](https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/system/etc/etc.nix))
to cause files to be created in `/etc/pam.d`.
In [](#sec-configuration-syntax), we saw the following structure of
NixOS modules:
```nix
{ config, pkgs, ... }:
{
# option definitions
}
```
This is actually an *abbreviated* form of module that only defines
options, but does not declare any. The structure of full NixOS modules
is shown in [Example: Structure of NixOS Modules](#ex-module-syntax).
::: {#ex-module-syntax .example}
### Structure of NixOS Modules
```nix
{ config, pkgs, ... }:
{
imports = [
# paths of other modules
];
options = {
# option declarations
};
config = {
# option definitions
};
}
```
:::
The meaning of each part is as follows.
- The first line makes the current Nix expression a function. The variable
`pkgs` contains Nixpkgs (by default, it takes the `nixpkgs` entry of
`NIX_PATH`, see the [Nix manual](https://nixos.org/manual/nix/stable/#sec-common-env)
for further details), while `config` contains the full system
configuration. This line can be omitted if there is no reference to
`pkgs` and `config` inside the module.
- This `imports` list enumerates the paths to other NixOS modules that
should be included in the evaluation of the system configuration. A
default set of modules is defined in the file `modules/module-list.nix`.
These don't need to be added in the import list.
- The attribute `options` is a nested set of *option declarations*
(described below).
- The attribute `config` is a nested set of *option definitions* (also
described below).
[Example: NixOS Module for the "locate" Service](#locate-example)
shows a module that handles the regular update of the "locate" database,
an index of all files in the file system. This module declares two
options that can be defined by other modules (typically the user's
`configuration.nix`): `services.locate.enable` (whether the database should
be updated) and `services.locate.interval` (when the update should be done).
It implements its functionality by defining two options declared by other
modules: `systemd.services` (the set of all systemd services) and
`systemd.timers` (the list of commands to be executed periodically by
`systemd`).
Care must be taken when writing systemd services using `Exec*` directives. By
default systemd performs substitution on `%<char>` specifiers in these
directives, expands environment variables from `$FOO` and `${FOO}`, splits
arguments on whitespace, and splits commands on `;`. All of these must be escaped
to avoid unexpected substitution or splitting when interpolating into an `Exec*`
directive, e.g. when using an `extraArgs` option to pass additional arguments to
the service. The functions `utils.escapeSystemdExecArg` and
`utils.escapeSystemdExecArgs` are provided for this, see [Example: Escaping in
Exec directives](#exec-escaping-example) for an example. When using these
functions system environment substitution should *not* be disabled explicitly.
::: {#locate-example .example}
### NixOS Module for the "locate" Service
```nix
{
config,
lib,
pkgs,
...
}:
let
inherit (lib)
concatStringsSep
mkIf
mkOption
optionalString
types
;
cfg = config.services.locate;
in
{
options.services.locate = {
enable = mkOption {
type = types.bool;
default = false;
description = ''
If enabled, NixOS will periodically update the database of
files used by the locate command.
'';
};
interval = mkOption {
type = types.str;
default = "02:15";
example = "hourly";
description = ''
Update the locate database at this interval. Updates by
default at 2:15 AM every day.
The format is described in
systemd.time(7).
'';
};
# Other options omitted for documentation
};
config = {
systemd.services.update-locatedb = {
description = "Update Locate Database";
path = [ pkgs.su ];
script = ''
mkdir -p $(dirname ${toString cfg.output})
chmod 0755 $(dirname ${toString cfg.output})
exec updatedb \
--localuser=${cfg.localuser} \
${optionalString (!cfg.includeStore) "--prunepaths='/nix/store'"} \
--output=${toString cfg.output} ${concatStringsSep " " cfg.extraFlags}
'';
};
systemd.timers.update-locatedb = mkIf cfg.enable {
description = "Update timer for locate database";
partOf = [ "update-locatedb.service" ];
wantedBy = [ "timers.target" ];
timerConfig.OnCalendar = cfg.interval;
};
};
}
```
:::
::: {#exec-escaping-example .example}
### Escaping in Exec directives
```nix
{
config,
pkgs,
utils,
...
}:
let
cfg = config.services.echo;
echoAll = pkgs.writeScript "echo-all" ''
#! ${pkgs.runtimeShell}
for s in "$@"; do
printf '%s\n' "$s"
done
'';
args = [
"a%Nything"
"lang=\${LANG}"
";"
"/bin/sh -c date"
];
in
{
systemd.services.echo = {
description = "Echo to the journal";
wantedBy = [ "multi-user.target" ];
serviceConfig.Type = "oneshot";
serviceConfig.ExecStart = ''
${echoAll} ${utils.escapeSystemdExecArgs args}
'';
};
}
```
:::
```{=include=} sections
option-declarations.section.md
option-types.section.md
option-def.section.md
assertions.section.md
meta-attributes.section.md
importing-modules.section.md
replace-modules.section.md
freeform-modules.section.md
settings-options.section.md
```

View File

@@ -0,0 +1,406 @@
# Writing Tests {#sec-writing-nixos-tests}
A NixOS test is a module that has the following structure:
```nix
{
# One or more machines:
nodes = {
machine =
{ config, pkgs, ... }:
{
# ...
};
machine2 =
{ config, pkgs, ... }:
{
# ...
};
# …
};
testScript = ''
Python code
'';
}
```
We refer to the whole test above as a test module, whereas the values
in [`nodes.<name>`](#test-opt-nodes) are NixOS modules themselves.
The option [`testScript`](#test-opt-testScript) is a piece of Python code that executes the
test (described below). During the test, it will start one or more
virtual machines, the configuration of which is described by
the option [`nodes`](#test-opt-nodes).
An example of a single-node test is
[`login.nix`](https://github.com/NixOS/nixpkgs/blob/master/nixos/tests/login.nix).
It only needs a single machine to test whether users can log in
on the virtual console, whether device ownership is correctly maintained
when switching between consoles, and so on. An interesting multi-node test is
[`nfs/simple.nix`](https://github.com/NixOS/nixpkgs/blob/master/nixos/tests/nfs/simple.nix).
It uses two client nodes to test correct locking across server crashes.
## Calling a test {#sec-calling-nixos-tests}
Tests are invoked differently depending on whether the test is part of NixOS or lives in a different project.
### Testing within NixOS {#sec-call-nixos-test-in-nixos}
Tests that are part of NixOS are added to [`nixos/tests/all-tests.nix`](https://github.com/NixOS/nixpkgs/blob/master/nixos/tests/all-tests.nix).
```nix
{ hostname = runTest ./hostname.nix; }
```
Overrides can be added by defining an anonymous module in `all-tests.nix`.
```nix
{
hostname = runTest {
imports = [ ./hostname.nix ];
defaults.networking.firewall.enable = false;
};
}
```
You can run a test with attribute name `hostname` in `nixos/tests/all-tests.nix` by invoking:
```shell
cd /my/git/clone/of/nixpkgs
nix-build -A nixosTests.hostname
```
### Testing outside the NixOS project {#sec-call-nixos-test-outside-nixos}
Outside the `nixpkgs` repository, you can use the `runNixOSTest` function from
`pkgs.testers`:
```nix
let
pkgs = import <nixpkgs> { };
in
pkgs.testers.runNixOSTest {
imports = [ ./test.nix ];
defaults.services.foo.package = mypkg;
}
```
`runNixOSTest` returns a derivation that runs the test.
## Configuring the nodes {#sec-nixos-test-nodes}
There are a few special NixOS options for test VMs:
`virtualisation.memorySize`
: The memory of the VM in MiB (1024×1024 bytes).
`virtualisation.vlans`
: The virtual networks to which the VM is connected. See
[`nat.nix`](https://github.com/NixOS/nixpkgs/blob/master/nixos/tests/nat.nix)
for an example.
`virtualisation.writableStore`
: By default, the Nix store in the VM is not writable. If you enable
this option, a writable union file system is mounted on top of the
Nix store to make it appear writable. This is necessary for tests
that run Nix operations that modify the store.
For more options, see the module
[`qemu-vm.nix`](https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/virtualisation/qemu-vm.nix).
The test script is a sequence of Python statements that perform various
actions, such as starting VMs, executing commands in the VMs, and so on.
Each virtual machine is represented as an object stored in the variable
`name` if this is also the identifier of the machine in the declarative
config. If you specified a node `nodes.machine`, the following example starts the
machine, waits until it has finished booting, then executes a command
and checks that the output is more-or-less correct:
```py
machine.start()
machine.wait_for_unit("default.target")
t.assertIn("Linux", machine.succeed("uname"), "Wrong OS")
```
The first line is technically unnecessary; machines are implicitly started
when you first execute an action on them (such as `wait_for_unit` or
`succeed`). If you have multiple machines, you can speed up the test by
starting them in parallel:
```py
start_all()
```
Under the variable `t`, all assertions from [`unittest.TestCase`](https://docs.python.org/3/library/unittest.html) are available.
If the hostname of a node contains characters that can't be used in a
Python variable name, those characters will be replaced with
underscores in the variable name, so `nodes.machine-a` will be exposed
to Python as `machine_a`.
## Machine objects {#ssec-machine-objects}
The following methods are available on machine objects:
@PYTHON_MACHINE_METHODS@
To test user units declared by `systemd.user.services` the optional
`user` argument can be used:
```py
machine.start()
machine.wait_for_x()
machine.wait_for_unit("xautolock.service", "x-session-user")
```
This applies to `systemctl`, `get_unit_info`, `wait_for_unit`,
`start_job` and `stop_job`.
For faster dev cycles it's also possible to disable the code-linters
(this shouldn't be committed though):
```nix
{
skipLint = true;
nodes.machine =
{ config, pkgs, ... }:
{
# configuration…
};
testScript = ''
Python code
'';
}
```
This will produce a Nix warning at evaluation time. To fully disable the
linter, wrap the test script in comment directives to disable the Black
linter directly (again, don't commit this within the Nixpkgs
repository):
```nix
{
testScript = ''
# fmt: off
Python code
# fmt: on
'';
}
```
Similarly, the type checking of test scripts can be disabled in the following
way:
```nix
{
skipTypeCheck = true;
nodes.machine =
{ config, pkgs, ... }:
{
# configuration…
};
}
```
## Failing tests early {#ssec-failing-tests-early}
To fail tests early when certain invariants are no longer met (instead of waiting for the build to time out), the decorator `polling_condition` is provided. For example, if we are testing a program `foo` that should not quit after being started, we might write the following:
```py
@polling_condition
def foo_running():
machine.succeed("pgrep -x foo")
machine.succeed("foo --start")
machine.wait_until_succeeds("pgrep -x foo")
with foo_running:
... # Put `foo` through its paces
```
`polling_condition` takes the following (optional) arguments:
`seconds_interval`
: specifies how often the condition should be polled:
```py
@polling_condition(seconds_interval=10)
def foo_running():
machine.succeed("pgrep -x foo")
```
`description`
: is used in the log when the condition is checked. If this is not provided, the description is pulled from the docstring of the function. These two are therefore equivalent:
```py
@polling_condition
def foo_running():
"check that foo is running"
machine.succeed("pgrep -x foo")
```
```py
@polling_condition(description="check that foo is running")
def foo_running():
machine.succeed("pgrep -x foo")
```
## Adding Python packages to the test script {#ssec-python-packages-in-test-script}
When additional Python libraries are required in the test script, they can be
added using the parameter `extraPythonPackages`. For example, you could add
`numpy` like this:
```nix
{
extraPythonPackages = p: [ p.numpy ];
nodes = { };
# Type checking on extra packages doesn't work yet
skipTypeCheck = true;
testScript = ''
import numpy as np
assert str(np.zeros(4)) == "[0. 0. 0. 0.]"
'';
}
```
In that case, `numpy` is chosen from the generic `python3Packages`.
## Overriding a test {#sec-override-nixos-test}
The NixOS test framework returns tests with multiple overriding methods.
`overrideTestDerivation` *function*
: Like applying `overrideAttrs` on the [test](#test-opt-test) derivation.
This is a convenience for `extend` with an override on the [`rawTestDerivationArg`](#test-opt-rawTestDerivationArg) option.
*function*
: An extension function, e.g. `finalAttrs: prevAttrs: { /* … */ }`, the result of which is passed to [`mkDerivation`](https://nixos.org/manual/nixpkgs/stable/#sec-using-stdenv).
Just as with `overrideAttrs`, an abbreviated form can be used, e.g. `prevAttrs: { /* … */ }` or even `{ /* … */ }`.
See [`lib.extends`](https://nixos.org/manual/nixpkgs/stable/#function-library-lib.fixedPoints.extends).
`extendNixOS { module = ` *module* `; specialArgs = ` *specialArgs* `; }`
: Evaluates the test with additional NixOS modules and/or arguments.
`module`
: A NixOS module to add to all the nodes in the test. Sets test option [`extraBaseModules`](#test-opt-extraBaseModules).
`specialArgs`
: An attribute set of arguments to pass to all NixOS modules. These override the existing arguments, as well as any `_module.args.<name>` that the modules may define. Sets test option [`node.specialArgs`](#test-opt-node.specialArgs).
This is a convenience function for `extend` that overrides the aforementioned test options.
:::{.example #ex-nixos-test-extendNixOS}
# Using extendNixOS in `passthru.tests` to make `(openssh.tests.overrideAttrs f).tests.nixos` coherent
```nix
mkDerivation (finalAttrs: {
# …
passthru = {
tests = {
nixos = nixosTests.openssh.extendNixOS {
module = {
services.openssh.package = finalAttrs.finalPackage;
};
};
};
};
})
```
:::
`extend { modules = ` *modules* `; specialArgs = ` *specialArgs* `; }`
: Adds new `nixosTest` modules and/or module arguments to the test, which are evaluated together with the existing modules and [built-in options](#sec-test-options-reference).
If you're only looking to extend the _NixOS_ configurations of the test, and not something else about the test, you may use the `extendNixOS` convenience function instead.
`modules`
: A list of modules to add to the test. These are added to the existing modules and then [evaluated](https://nixos.org/manual/nixpkgs/stable/index.html#module-system-lib-evalModules) together.
`specialArgs`
: An attribute of arguments to pass to the test. These override the existing arguments, as well as any `_module.args.<name>` that the modules may define. See [`evalModules`/`specialArgs`](https://nixos.org/manual/nixpkgs/stable/#module-system-lib-evalModules-param-specialArgs).
## Test Options Reference {#sec-test-options-reference}
The following options can be used when writing tests.
```{=include=} options
id-prefix: test-opt-
list-id: test-options-list
source: @NIXOS_TEST_OPTIONS_JSON@
```
## Accessing VMs in the sandbox with SSH {#sec-test-sandbox-breakpoint}
::: {.note}
For debugging with SSH access into the machines, it's recommended to try using
[the interactive driver](#sec-running-nixos-tests-interactively) with its
[SSH backdoor](#sec-nixos-test-ssh-access) first.
This feature is mostly intended to debug flaky test failures that aren't
reproducible elsewhere.
:::
As explained in [](#sec-nixos-test-ssh-access), it's possible to configure an
SSH backdoor based on AF_VSOCK. This can be used to SSH into a VM of a running
build in a sandbox.
This can be done when something in the test fails, e.g.
```nix
{
nodes.machine = { };
sshBackdoor.enable = true;
enableDebugHook = true;
testScript = ''
start_all()
machine.succeed("false") # this will fail
'';
}
```
For the AF_VSOCK feature to work, `/dev/vhost-vsock` is needed in the sandbox
which can be done with e.g.
```
nix-build -A nixosTests.foo --option sandbox-paths /dev/vhost-vsock
```
This will halt the test execution on a test-failure and print instructions
on how to enter the sandbox shell of the VM test. Inside, one can log into
e.g. `machine` with
```
ssh -F ./ssh_config vsock/3
```
As described in [](#sec-nixos-test-ssh-access), the numbers for vsock start at
`3` instead of `1`. So the first VM in the network (sorted alphabetically) can
be accessed with `vsock/3`.
Alternatively, it's possible to explicitly set a breakpoint with
`debug.breakpoint()`. This also has the benefit, that one can step through
`testScript` with `pdb` like this:
```
$ sudo /nix/store/eeeee-attach <id>
bash# telnet 127.0.0.1 4444
pdb$ …
```

Some files were not shown because too many files have changed in this diff Show More