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:
4
dev/nixos-manual/README.md
Normal file
4
dev/nixos-manual/README.md
Normal 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
|
||||
65
dev/nixos-manual/_index.md
Normal file
65
dev/nixos-manual/_index.md
Normal 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 전환 기록
|
||||
41
dev/nixos-manual/administration/boot-problems.section.md
Normal file
41
dev/nixos-manual/administration/boot-problems.section.md
Normal 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 you’re 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.)
|
||||
64
dev/nixos-manual/administration/cleaning-store.chapter.md
Normal file
64
dev/nixos-manual/administration/cleaning-store.chapter.md
Normal 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.
|
||||
@@ -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.
|
||||
28
dev/nixos-manual/administration/containers.chapter.md
Normal file
28
dev/nixos-manual/administration/containers.chapter.md
Normal 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
|
||||
```
|
||||
59
dev/nixos-manual/administration/control-groups.chapter.md
Normal file
59
dev/nixos-manual/administration/control-groups.chapter.md
Normal 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.
|
||||
@@ -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`.
|
||||
115
dev/nixos-manual/administration/imperative-containers.section.md
Normal file
115
dev/nixos-manual/administration/imperative-containers.section.md
Normal 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
|
||||
```
|
||||
38
dev/nixos-manual/administration/logging.chapter.md
Normal file
38
dev/nixos-manual/administration/logging.chapter.md
Normal 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`.
|
||||
11
dev/nixos-manual/administration/maintenance-mode.section.md
Normal file
11
dev/nixos-manual/administration/maintenance-mode.section.md
Normal 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.
|
||||
21
dev/nixos-manual/administration/network-problems.section.md
Normal file
21
dev/nixos-manual/administration/network-problems.section.md
Normal 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/
|
||||
```
|
||||
28
dev/nixos-manual/administration/nixos-state.section.md
Normal file
28
dev/nixos-manual/administration/nixos-state.section.md
Normal 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)`.
|
||||
30
dev/nixos-manual/administration/rebooting.chapter.md
Normal file
30
dev/nixos-manual/administration/rebooting.chapter.md
Normal 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.
|
||||
38
dev/nixos-manual/administration/rollback.section.md
Normal file
38
dev/nixos-manual/administration/rollback.section.md
Normal 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
|
||||
```
|
||||
15
dev/nixos-manual/administration/running.md
Normal file
15
dev/nixos-manual/administration/running.md
Normal 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
|
||||
```
|
||||
173
dev/nixos-manual/administration/service-mgmt.chapter.md
Normal file
173
dev/nixos-manual/administration/service-mgmt.chapter.md
Normal 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
|
||||
};
|
||||
};
|
||||
}
|
||||
```
|
||||
28
dev/nixos-manual/administration/store-corruption.section.md
Normal file
28
dev/nixos-manual/administration/store-corruption.section.md
Normal 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.
|
||||
17
dev/nixos-manual/administration/system-state.chapter.md
Normal file
17
dev/nixos-manual/administration/system-state.chapter.md
Normal 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
|
||||
```
|
||||
52
dev/nixos-manual/administration/systemd-state.section.md
Normal file
52
dev/nixos-manual/administration/systemd-state.section.md
Normal 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`.
|
||||
12
dev/nixos-manual/administration/troubleshooting.chapter.md
Normal file
12
dev/nixos-manual/administration/troubleshooting.chapter.md
Normal 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
|
||||
```
|
||||
43
dev/nixos-manual/administration/user-sessions.chapter.md
Normal file
43
dev/nixos-manual/administration/user-sessions.chapter.md
Normal 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
|
||||
```
|
||||
16
dev/nixos-manual/administration/zfs-state.section.md
Normal file
16
dev/nixos-manual/administration/zfs-state.section.md
Normal 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.
|
||||
4
dev/nixos-manual/common.nix
Normal file
4
dev/nixos-manual/common.nix
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
outputPath = "share/doc/nixos";
|
||||
indexPath = "index.html";
|
||||
}
|
||||
94
dev/nixos-manual/configuration/abstractions.section.md
Normal file
94
dev/nixos-manual/configuration/abstractions.section.md
Normal file
@@ -0,0 +1,94 @@
|
||||
# Abstractions {#sec-module-abstractions}
|
||||
|
||||
If you find yourself repeating yourself over and over, it’s 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.
|
||||
@@ -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
|
||||
'';
|
||||
}
|
||||
```
|
||||
51
dev/nixos-manual/configuration/ad-hoc-packages.section.md
Normal file
51
dev/nixos-manual/configuration/ad-hoc-packages.section.md
Normal 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.
|
||||
119
dev/nixos-manual/configuration/adding-custom-packages.section.md
Normal file
119
dev/nixos-manual/configuration/adding-custom-packages.section.md
Normal 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.
|
||||
194
dev/nixos-manual/configuration/config-file.section.md
Normal file
194
dev/nixos-manual/configuration/config-file.section.md
Normal 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).
|
||||
18
dev/nixos-manual/configuration/config-syntax.chapter.md
Normal file
18
dev/nixos-manual/configuration/config-syntax.chapter.md
Normal 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
|
||||
```
|
||||
28
dev/nixos-manual/configuration/configuration.md
Normal file
28
dev/nixos-manual/configuration/configuration.md
Normal 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 -->
|
||||
121
dev/nixos-manual/configuration/customizing-packages.section.md
Normal file
121
dev/nixos-manual/configuration/customizing-packages.section.md
Normal 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.)
|
||||
@@ -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
|
||||
```
|
||||
45
dev/nixos-manual/configuration/file-systems.chapter.md
Normal file
45
dev/nixos-manual/configuration/file-systems.chapter.md
Normal 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
|
||||
```
|
||||
45
dev/nixos-manual/configuration/firewall.section.md
Normal file
45
dev/nixos-manual/configuration/firewall.section.md
Normal 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).
|
||||
197
dev/nixos-manual/configuration/gpu-accel.chapter.md
Normal file
197
dev/nixos-manual/configuration/gpu-accel.chapter.md
Normal 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.
|
||||
41
dev/nixos-manual/configuration/ipv4-config.section.md
Normal file
41
dev/nixos-manual/configuration/ipv4-config.section.md
Normal 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.
|
||||
48
dev/nixos-manual/configuration/ipv6-config.section.md
Normal file
48
dev/nixos-manual/configuration/ipv6-config.section.md
Normal 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.
|
||||
103
dev/nixos-manual/configuration/kubernetes.chapter.md
Normal file
103
dev/nixos-manual/configuration/kubernetes.chapter.md
Normal 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.
|
||||
139
dev/nixos-manual/configuration/linux-kernel.chapter.md
Normal file
139
dev/nixos-manual/configuration/linux-kernel.chapter.md
Normal 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`).
|
||||
122
dev/nixos-manual/configuration/luks-file-systems.section.md
Normal file
122
dev/nixos-manual/configuration/luks-file-systems.section.md
Normal 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
|
||||
```
|
||||
132
dev/nixos-manual/configuration/mattermost.chapter.md
Normal file
132
dev/nixos-manual/configuration/mattermost.chapter.md
Normal 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.
|
||||
142
dev/nixos-manual/configuration/modularity.section.md
Normal file
142
dev/nixos-manual/configuration/modularity.section.md
Normal 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") ];
|
||||
}
|
||||
```
|
||||
46
dev/nixos-manual/configuration/network-manager.section.md
Normal file
46
dev/nixos-manual/configuration/network-manager.section.md
Normal 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.
|
||||
:::
|
||||
16
dev/nixos-manual/configuration/networking.chapter.md
Normal file
16
dev/nixos-manual/configuration/networking.chapter.md
Normal 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 -->
|
||||
29
dev/nixos-manual/configuration/overlayfs.section.md
Normal file
29
dev/nixos-manual/configuration/overlayfs.section.md
Normal 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.
|
||||
18
dev/nixos-manual/configuration/package-mgmt.chapter.md
Normal file
18
dev/nixos-manual/configuration/package-mgmt.chapter.md
Normal 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
|
||||
```
|
||||
33
dev/nixos-manual/configuration/profiles.chapter.md
Normal file
33
dev/nixos-manual/configuration/profiles.chapter.md
Normal 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
|
||||
```
|
||||
@@ -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.
|
||||
7
dev/nixos-manual/configuration/profiles/base.section.md
Normal file
7
dev/nixos-manual/configuration/profiles/base.section.md
Normal 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).
|
||||
@@ -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`.
|
||||
4
dev/nixos-manual/configuration/profiles/demo.section.md
Normal file
4
dev/nixos-manual/configuration/profiles/demo.section.md
Normal 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).
|
||||
@@ -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).
|
||||
10
dev/nixos-manual/configuration/profiles/graphical.section.md
Normal file
10
dev/nixos-manual/configuration/profiles/graphical.section.md
Normal 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.
|
||||
20
dev/nixos-manual/configuration/profiles/hardened.section.md
Normal file
20
dev/nixos-manual/configuration/profiles/hardened.section.md
Normal 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.
|
||||
:::
|
||||
@@ -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.
|
||||
@@ -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.
|
||||
@@ -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).
|
||||
@@ -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".
|
||||
@@ -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.
|
||||
@@ -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.
|
||||
:::
|
||||
20
dev/nixos-manual/configuration/ssh.section.md
Normal file
20
dev/nixos-manual/configuration/ssh.section.md
Normal 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..." ];
|
||||
}
|
||||
```
|
||||
103
dev/nixos-manual/configuration/sshfs-file-systems.section.md
Normal file
103
dev/nixos-manual/configuration/sshfs-file-systems.section.md
Normal 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.
|
||||
:::
|
||||
116
dev/nixos-manual/configuration/subversion.chapter.md
Normal file
116
dev/nixos-manual/configuration/subversion.chapter.md
Normal 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`.
|
||||
167
dev/nixos-manual/configuration/user-mgmt.chapter.md
Normal file
167
dev/nixos-manual/configuration/user-mgmt.chapter.md
Normal 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.
|
||||
24
dev/nixos-manual/configuration/wayland.chapter.md
Normal file
24
dev/nixos-manual/configuration/wayland.chapter.md
Normal 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).
|
||||
74
dev/nixos-manual/configuration/wireless.section.md
Normal file
74
dev/nixos-manual/configuration/wireless.section.md
Normal 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
|
||||
```
|
||||
396
dev/nixos-manual/configuration/x-windows.chapter.md
Normal file
396
dev/nixos-manual/configuration/x-windows.chapter.md
Normal 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).
|
||||
61
dev/nixos-manual/configuration/xfce.chapter.md
Normal file
61
dev/nixos-manual/configuration/xfce.chapter.md
Normal 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.
|
||||
140
dev/nixos-manual/contributing-to-this-manual.chapter.md
Normal file
140
dev/nixos-manual/contributing-to-this-manual.chapter.md
Normal 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
|
||||
```
|
||||
295
dev/nixos-manual/default.nix
Normal file
295
dev/nixos-manual/default.nix
Normal 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
|
||||
'';
|
||||
|
||||
}
|
||||
74
dev/nixos-manual/development/activation-script.section.md
Normal file
74
dev/nixos-manual/development/activation-script.section.md
Normal 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`
|
||||
45
dev/nixos-manual/development/assertions.section.md
Normal file
45
dev/nixos-manual/development/assertions.section.md
Normal 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";
|
||||
}
|
||||
];
|
||||
};
|
||||
}
|
||||
```
|
||||
38
dev/nixos-manual/development/bootspec.chapter.md
Normal file
38
dev/nixos-manual/development/bootspec.chapter.md
Normal 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.
|
||||
74
dev/nixos-manual/development/building-parts.chapter.md
Normal file
74
dev/nixos-manual/development/building-parts.chapter.md
Normal 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.
|
||||
@@ -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.
|
||||
16
dev/nixos-manual/development/development.md
Normal file
16
dev/nixos-manual/development/development.md
Normal 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
|
||||
```
|
||||
36
dev/nixos-manual/development/etc-overlay.section.md
Normal file
36
dev/nixos-manual/development/etc-overlay.section.md
Normal 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`.
|
||||
79
dev/nixos-manual/development/freeform-modules.section.md
Normal file
79
dev/nixos-manual/development/freeform-modules.section.md
Normal 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.
|
||||
:::
|
||||
23
dev/nixos-manual/development/importing-modules.section.md
Normal file
23
dev/nixos-manual/development/importing-modules.section.md
Normal 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;
|
||||
}
|
||||
```
|
||||
@@ -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).
|
||||
73
dev/nixos-manual/development/meta-attributes.section.md
Normal file
73
dev/nixos-manual/development/meta-attributes.section.md
Normal 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).
|
||||
111
dev/nixos-manual/development/modular-services.md
Normal file
111
dev/nixos-manual/development/modular-services.md
Normal 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
|
||||
14
dev/nixos-manual/development/nixos-tests.chapter.md
Normal file
14
dev/nixos-manual/development/nixos-tests.chapter.md
Normal 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
|
||||
```
|
||||
@@ -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.
|
||||
269
dev/nixos-manual/development/option-declarations.section.md
Normal file
269
dev/nixos-manual/development/option-declarations.section.md
Normal 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" ])`.
|
||||
204
dev/nixos-manual/development/option-def.section.md
Normal file
204
dev/nixos-manual/development/option-def.section.md
Normal 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.
|
||||
795
dev/nixos-manual/development/option-types.section.md
Normal file
795
dev/nixos-manual/development/option-types.section.md
Normal 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/2−1 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^n−1 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 submodule’s 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.
|
||||
80
dev/nixos-manual/development/replace-modules.section.md
Normal file
80
dev/nixos-manual/development/replace-modules.section.md
Normal 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." ];
|
||||
};
|
||||
}
|
||||
```
|
||||
@@ -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`.
|
||||
30
dev/nixos-manual/development/running-nixos-tests.section.md
Normal file
30
dev/nixos-manual/development/running-nixos-tests.section.md
Normal 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.
|
||||
629
dev/nixos-manual/development/settings-options.section.md
Normal file
629
dev/nixos-manual/development/settings-options.section.md
Normal 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.
|
||||
'';
|
||||
};
|
||||
}
|
||||
```
|
||||
:::
|
||||
77
dev/nixos-manual/development/sources.chapter.md
Normal file
77
dev/nixos-manual/development/sources.chapter.md
Normal 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.
|
||||
@@ -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";
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
```
|
||||
18
dev/nixos-manual/development/testing-installer.chapter.md
Normal file
18
dev/nixos-manual/development/testing-installer.chapter.md
Normal 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
|
||||
```
|
||||
111
dev/nixos-manual/development/unit-handling.section.md
Normal file
111
dev/nixos-manual/development/unit-handling.section.md
Normal 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.
|
||||
@@ -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
|
||||
```
|
||||
@@ -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`.
|
||||
223
dev/nixos-manual/development/writing-modules.chapter.md
Normal file
223
dev/nixos-manual/development/writing-modules.chapter.md
Normal 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
|
||||
```
|
||||
406
dev/nixos-manual/development/writing-nixos-tests.section.md
Normal file
406
dev/nixos-manual/development/writing-nixos-tests.section.md
Normal 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
Reference in New Issue
Block a user