Files
nxdns/docs/how-to/install-with-systemd.md
T

197 lines
7.1 KiB
Markdown

# Install with systemd
Install nxdns as a system service on a Linux machine with systemd, including a Raspberry Pi. At the end it answers DNS on port 53 for your network and starts on boot.
## 1. Download and verify
Each release has two builds: `x86_64-linux-musl` for a PC or server, and `aarch64-linux-musl` for a Raspberry Pi or another 64-bit ARM machine. Both are static binaries that need nothing installed. On the machine that will run nxdns:
```sh
mkdir -p ~/nxdns-release && cd ~/nxdns-release
curl -fLO https://git.mial.net/mokhtar/nxdns/releases/download/v<version>/nxdns-<version>-x86_64-linux-musl.tar.gz
curl -fLO https://git.mial.net/mokhtar/nxdns/releases/download/v<version>/SHA256SUMS.txt
curl -fLO https://git.mial.net/mokhtar/nxdns/releases/download/v<version>/SHA256SUMS.txt.asc
gpg --verify SHA256SUMS.txt.asc SHA256SUMS.txt
sha256sum -c --ignore-missing SHA256SUMS.txt
tar -xzf nxdns-<version>-x86_64-linux-musl.tar.gz
cd nxdns-<version>-x86_64-linux-musl
```
The signature covers `SHA256SUMS.txt`, and `SHA256SUMS.txt` covers the tarball. [Verify a release](verify-a-release.md) explains where the public key comes from and which fingerprint to expect; read it before your first install.
The directory holds the binary `nxdns`, the systemd unit `nxdns.service`, the sysusers file `nxdns.conf` that creates the `nxdns` user, the licences and a short `INSTALL.md`.
## 2. Install the binary, the user and the unit
As root:
```sh
install -m 0755 nxdns /usr/local/bin/nxdns
install -m 0644 nxdns.conf /usr/lib/sysusers.d/nxdns.conf
systemd-sysusers
install -m 0644 nxdns.service /etc/systemd/system/nxdns.service
systemctl daemon-reload
mkdir -p -m 0755 /etc/nxdns
```
Do not create `/var/lib/nxdns` or `/var/log/nxdns`. systemd creates them on the first start, with the right owner and modes.
## 3. Write the configuration
The smallest configuration that starts is a group named `default` and one upstream resolver. Write `/etc/nxdns/config.zon` and give the web interface a password:
```zon
.{
.groups = .{ .{ .name = "default" } },
.upstreams = .{ .{ .url = "https://cloudflare-dns.com/dns-query" } },
.web = .{ .password = "choose-a-real-password" },
}
```
The file holds a password in plain text, so restrict it:
```sh
chown root:nxdns /etc/nxdns/config.zon
chmod 0640 /etc/nxdns/config.zon
```
Check it, then load it into the database:
```sh
nxdns check --config /etc/nxdns/config.zon
nxdns import /etc/nxdns/config.zon
```
```
checking configuration file /etc/nxdns/config.zon
OK upstreams[0] https://cloudflare-dns.com
OK: no problems found
info(migrations): config.db migrated from schema version 0 to 1
imported /etc/nxdns/config.zon
```
`check` sends one real query through each upstream, so the machine needs working DNS when you run it. If it finds a problem it lists every one and exits 2.
The password is stored only as a hash, so once you have logged in (step 5) you can delete the file:
```sh
rm /etc/nxdns/config.zon
```
From now on you change settings in the web interface. This is database mode, and it is what the packaged unit runs. To keep `config.zon` in git as the configuration instead, keep the file and see [Run in file mode](#run-in-file-mode).
## 4. Start it
```sh
systemctl enable --now nxdns
journalctl -u nxdns -f
```
A healthy start names every socket it opened:
```
info(nxdns): nxdns <version> serving on udp [::]:53 tcp [::]:53 tcp 0.0.0.0:53; 1 upstream(s); blocklist generation 1
```
The unit grants the capability to bind port 53 and runs nxdns as the `nxdns` user. It does not restart nxdns after exit code 2 (a configuration problem) or 64 (a wrong command line), because a retry cannot fix either; the journal says what is wrong. Fix it and start the service again.
### If port 53 is already taken
```
cannot bind udp [::1]:53: AddressInUse
nxdns run failed: AddressInUse
```
On most systemd distributions `systemd-resolved` holds port 53 with its stub listener. Turn the stub off and keep resolved for the machine's own lookups:
```sh
mkdir -p /etc/systemd/resolved.conf.d
printf '[Resolve]\nDNSStubListener=no\n' > /etc/systemd/resolved.conf.d/nxdns.conf
systemctl restart systemd-resolved
```
If `/etc/resolv.conf` is a link to `/run/systemd/resolve/stub-resolv.conf`, point it at `/run/systemd/resolve/resolv.conf` so the machine still resolves names. `ss -lnup 'sport = :53'` shows what else holds the port.
## 5. Check it and point your network at it
From another machine on your network:
```sh
dig @<server-ip> example.com A +short
```
Open `http://<server-ip>:8080` and log in with the password from step 3. Then add blocklists on the **Protection** page, as [Get started](../tutorial/get-started.md#5-add-a-blocklist) shows.
To make every device use nxdns, set the DNS server your router hands out (its DHCP settings) to the nxdns machine's address. Leave the nxdns machine itself on another resolver: nxdns looks up its upstreams' names through it, and that should not depend on nxdns already running.
## Run in file mode
In file mode `/etc/nxdns/config.zon` is the configuration. Every start applies the file, and the web interface refuses configuration changes and names the file instead. Use it when the file lives in git and a tool deploys it. [The configuration model](../explanation/configuration-model.md) compares the two modes.
### Switch to file mode
Stop the service first, so no change made in the web interface is lost, then write the current configuration out as the file:
```sh
systemctl stop nxdns
nxdns export --out /etc/nxdns/config.zon
chown root:nxdns /etc/nxdns/config.zon
chmod 0640 /etc/nxdns/config.zon
nxdns check --config /etc/nxdns/config.zon
```
Add a drop-in that passes the file, and start:
```sh
mkdir -p /etc/systemd/system/nxdns.service.d
cat > /etc/systemd/system/nxdns.service.d/file-mode.conf <<'EOF'
[Service]
ExecStart=
ExecStart=/usr/local/bin/nxdns run --config=/etc/nxdns/config.zon
EOF
systemctl daemon-reload
systemctl start nxdns
```
The empty `ExecStart=` line is required: it clears the unit's own command instead of adding a second one. The first start changes nothing, because the file was written from the database it now governs:
```
reconciled '/etc/nxdns/config.zon': no changes
info(nxdns): authority: file (/etc/nxdns/config.zon)
```
Blocklists, their downloads and the query history all carry over.
### Change the configuration
Edit the file, check it, restart:
```sh
$EDITOR /etc/nxdns/config.zon
nxdns check --config /etc/nxdns/config.zon
systemctl restart nxdns
```
The restart logs what it changed:
```
reconciled '/etc/nxdns/config.zon': upstreams +1 ~0 -0; settings +0 ~2 -0;
settings keys changed: dns.port web.port
```
Because the file is read at every start, a broken file stops the service at its next restart, whenever that is. If a tool deploys the file, run `nxdns check --config` before it restarts nxdns, so a mistake fails the deploy instead.
### Go back to database mode
Remove the drop-in and restart. The database already holds the last configuration the file set:
```sh
rm /etc/systemd/system/nxdns.service.d/file-mode.conf
systemctl daemon-reload
systemctl restart nxdns
```
```
info(nxdns): authority: database
```