docs: rewrite for people running nxdns; query-history refusals name their remedy and a refused start gives no wrong hints

This commit is contained in:
2026-10-21 17:03:00 +02:00
parent fbc8fd7882
commit c21e5a9542
31 changed files with 1186 additions and 3877 deletions
+153
View File
@@ -0,0 +1,153 @@
# Get started
Run nxdns on your own computer, point a query at it, and watch it block an ad domain from a real blocklist. Everything happens in one directory and on unprivileged ports, so nothing on your machine changes and nothing needs root. At the end you stop it and delete the directory.
You need a Linux machine (x86_64 or aarch64), `curl`, and `dig` (from bind-tools or dnsutils). nxdns is a single static binary with no dependencies.
## 1. Download
Make a directory to work in, download the release for your machine with its checksum file, and check the download:
```sh
mkdir ~/nxdns-try && cd ~/nxdns-try
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
sha256sum -c --ignore-missing SHA256SUMS.txt
```
```
nxdns-<version>-x86_64-linux-musl.tar.gz: OK
```
On a Raspberry Pi or another 64-bit ARM machine, replace `x86_64` with `aarch64` in the URL and in the commands below. The checksum file is signed; [Verify a release](../how-to/verify-a-release.md) shows how to check the signature as well, which is worth doing before a real install.
Unpack it and go into the directory it creates:
```sh
tar -xzf nxdns-<version>-x86_64-linux-musl.tar.gz
cd nxdns-<version>-x86_64-linux-musl
./nxdns version
```
```
nxdns <version>
zig 0.16.0
```
## 2. Write a configuration
nxdns needs two things before it starts: a group called `default`, which every device belongs to until you say otherwise, and an upstream resolver to forward the queries it does not answer itself. Create `config.zon`:
```sh
cat > config.zon <<'EOF'
.{
.dns = .{ .bind_ipv4 = "127.0.0.1", .bind_ipv6 = "::1", .port = 5300 },
.web = .{ .bind = "127.0.0.1", .port = 8080 },
.groups = .{ .{ .name = "default" } },
.upstreams = .{ .{ .url = "https://cloudflare-dns.com/dns-query" } },
}
EOF
```
DNS listens on port 5300 instead of 53, and both DNS and the web interface listen on this machine only. Port 53 needs root, which is a decision for a real install, not for a first try. Every field you did not set keeps its default; the [configuration reference](../reference/configuration.md) lists them all.
Check the file:
```sh
./nxdns check --config config.zon
```
```
checking configuration file config.zon
OK upstreams[0] https://cloudflare-dns.com
OK: no problems found
```
`check` validates the file and sends one real query to each upstream to confirm it answers. It changes nothing, so you can run it as often as you like.
## 3. Load it and start
Load the file into a new data directory, then start the server:
```sh
./nxdns import config.zon --data-dir data
./nxdns run --data-dir data
```
```
info(migrations): config.db migrated from schema version 0 to 1
imported config.zon
info(querylog_schema): created querylog database 'data/querylog.db'
info(blocklist_manager): blocklist snapshot generation 1: 0 of 0 sources loaded, 231 bytes
info(nxdns): authority: database
info(nxdns): nxdns <version> serving on udp [::1]:5300 udp 127.0.0.1:5300 tcp [::1]:5300 tcp 127.0.0.1:5300; 1 upstream(s); blocklist generation 1
info(web_server): web interface listening on 127.0.0.1:8080
```
`authority: database` means the configuration now lives in `data/config.db`, and you change it from the web interface. The file has done its job. (nxdns can also treat the file as the configuration at every start; [the configuration model](../explanation/configuration-model.md) explains both modes.)
Leave the server running in this terminal and open a second one.
## 4. Resolve a name
```sh
dig @127.0.0.1 -p 5300 example.com A +noall +answer
```
```
example.com. 214 IN A 104.20.23.154
example.com. 214 IN A 172.66.147.243
```
nxdns forwarded the query to Cloudflare over HTTPS and returned the answer. It blocks nothing yet: the log said `0 of 0 sources loaded`.
## 5. Add a blocklist
Open <http://127.0.0.1:8080> in a browser. There is no password yet, so the Overview opens straight away; [Set up admin authentication](../how-to/set-up-admin-authentication.md) adds one before the interface leaves your machine.
1. Go to **Protection** and open the **Sources** tab.
2. Under **Add source**, set **URL** to `https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts` and **Name** to `StevenBlack hosts`, then press **Add source**.
3. Open the **Groups** tab. The `default` group is selected. Under **Assigned sources**, tick **StevenBlack hosts** and press **Save sources**.
4. Back on the **Sources** tab, press **Update now**.
After a few seconds the source shows its size, something like `71,494 domains · 0 wildcards · 0 exceptions`, and the server log says `1 of 1 sources loaded`.
Step 3 matters. A source belongs to the whole installation, and each group picks the sources it uses, which is how one group of devices can get a strict list while another gets none. A source no group uses is downloaded and blocks nothing.
## 6. Watch a domain get blocked
In the browser, go to **Activity** and open the **Live** tab. Then, in your second terminal:
```sh
dig @127.0.0.1 -p 5300 doubleclick.net A +noall +answer
```
```
doubleclick.net. 5 IN A 0.0.0.0
```
`0.0.0.0` is the block answer, with a short TTL so a device forgets it soon after you unblock a domain. The query appears in the Live tab at once, marked **Blocked**.
A domain that is not on the list still resolves normally:
```sh
dig @127.0.0.1 -p 5300 wikipedia.org A +short
```
The **History** tab keeps every query. It is written to disk about once a minute, so give it that long. Then select `doubleclick.net` to see why it was blocked: the decision, the reason (`Blocklist (domain)`), the entry that matched and the list it came from (`StevenBlack hosts`).
A hosts list blocks exactly the names it lists. `doubleclick.net` and `ad.doubleclick.net` are both on this one, but a name the file does not list resolves even when its parent is blocked. To block every name under a domain, add a wildcard rule such as `*.doubleclick.net` under **Rules** on the group; it covers the names below `doubleclick.net`, not `doubleclick.net` itself. An Adblock Plus list's `||doubleclick.net^` entries cover both.
## 7. Stop and clean up
Press Ctrl-C in the first terminal. nxdns logs `shutting down` and exits. Then remove the directory:
```sh
rm -rf ~/nxdns-try
```
## Next
- Install it for real, on port 53 for your whole network: with [Docker](../how-to/install-with-docker.md), with [systemd](../how-to/install-with-systemd.md), or on [NixOS](../how-to/install-with-nix.md).
- [Set up admin authentication](../how-to/set-up-admin-authentication.md) before the web interface is reachable from other machines.
- [The configuration model](../explanation/configuration-model.md) explains the choice between configuring nxdns in the web interface and keeping a file in git.