docs: unwrap hand-wrapped prose repo-wide
Gates / frontend (push) Successful in 1m2s
Gates / test (push) Successful in 1m38s
Gates / package (push) Successful in 5m5s
Gates / test-aarch64 (push) Successful in 6m30s
Gates / container (push) Successful in 15s
CI / gates (push) Successful in 13m30s
Gates / frontend (push) Successful in 1m2s
Gates / test (push) Successful in 1m38s
Gates / package (push) Successful in 5m5s
Gates / test-aarch64 (push) Successful in 6m30s
Gates / container (push) Successful in 15s
CI / gates (push) Successful in 13m30s
This commit is contained in:
@@ -1,7 +1,6 @@
|
||||
# nxdns
|
||||
|
||||
nxdns is a DNS sinkhole for your LAN. It blocks the names you do not want, and
|
||||
forwards the rest over an encrypted connection.
|
||||
nxdns is a DNS sinkhole for your LAN. It blocks the names you do not want, and forwards the rest over an encrypted connection.
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
@@ -12,49 +11,30 @@ flowchart LR
|
||||
nxdns -- "blocked" --> sink["0.0.0.0 / NXDOMAIN"]
|
||||
```
|
||||
|
||||
One static Zig binary. SQLite holds the state and the query log, which the web
|
||||
UI, the REST API and `/metrics` read.
|
||||
One static Zig binary. SQLite holds the state and the query log, which the web UI, the REST API and `/metrics` read.
|
||||
|
||||
## Features
|
||||
|
||||
- Blocklist filtering: subscribe to hosts, domain and Adblock Plus lists —
|
||||
whose `@@` exception lines are honoured — plus your own allow and block rules,
|
||||
exact, wildcard (`*.example.com`) or regular expression
|
||||
- Two configuration modes: a database the web UI edits, or a ZON file you keep
|
||||
in git and converge onto at every start
|
||||
- Per-client policy groups: different filtering for the kids' tablet and
|
||||
your workstation
|
||||
- Blocklist filtering: subscribe to hosts, domain and Adblock Plus lists — whose `@@` exception lines are honoured — plus your own allow and block rules, exact, wildcard (`*.example.com`) or regular expression
|
||||
- Two configuration modes: a database the web UI edits, or a ZON file you keep in git and converge onto at every start
|
||||
- Per-client policy groups: different filtering for the kids' tablet and your workstation
|
||||
- Local DNS records and conditional forwarding for internal zones
|
||||
- Encrypted upstreams: DNS-over-HTTPS and DNS-over-TLS with failover
|
||||
- Built-in DoH and DoT server endpoints, with certificate hot-reload
|
||||
- Bounded in-memory DNS cache with TTL-respecting expiry
|
||||
- Query log with retention limits, live-streamed over SSE
|
||||
- Web UI (embedded in the binary) and a REST API with a served OpenAPI spec
|
||||
- Prometheus-style `/metrics`, per-client rate limiting, disk-full
|
||||
self-protection
|
||||
- Prometheus-style `/metrics`, per-client rate limiting, disk-full self-protection
|
||||
|
||||
## Install
|
||||
|
||||
**No release exists yet.** This repository has no tags, nothing has been
|
||||
published to <https://git.mial.net/mokhtar/nxdns/releases>, and no container
|
||||
image has been pushed. Every release URL on this page and in the how-to guides
|
||||
is a 404 today, and `docker pull` finds nothing. Until the first tag ships,
|
||||
building from source is the only way to get nxdns.
|
||||
**No release exists yet.** This repository has no tags, nothing has been published to <https://git.mial.net/mokhtar/nxdns/releases>, and no container image has been pushed. Every release URL on this page and in the how-to guides is a 404 today, and `docker pull` finds nothing. Until the first tag ships, building from source is the only way to get nxdns.
|
||||
|
||||
What a tag will publish, once one exists: five assets — two static musl
|
||||
tarballs (`nxdns-<version>-x86_64-linux-musl.tar.gz`,
|
||||
`nxdns-<version>-aarch64-linux-musl.tar.gz`), `IMAGE-DIGEST.txt` naming the
|
||||
multi-architecture container image by digest, `SHA256SUMS.txt` covering those
|
||||
three files, and `SHA256SUMS.txt.asc`, a detached OpenPGP signature over the
|
||||
checksum file. Verify what you downloaded before you run it:
|
||||
[docs/how-to/verify-a-release.md](docs/how-to/verify-a-release.md), which also
|
||||
says what that signature does and does not prove.
|
||||
What a tag will publish, once one exists: five assets — two static musl tarballs (`nxdns-<version>-x86_64-linux-musl.tar.gz`, `nxdns-<version>-aarch64-linux-musl.tar.gz`), `IMAGE-DIGEST.txt` naming the multi-architecture container image by digest, `SHA256SUMS.txt` covering those three files, and `SHA256SUMS.txt.asc`, a detached OpenPGP signature over the checksum file. Verify what you downloaded before you run it: [docs/how-to/verify-a-release.md](docs/how-to/verify-a-release.md), which also says what that signature does and does not prove.
|
||||
|
||||
## Quickstart (docker compose)
|
||||
|
||||
Write a minimal configuration and start the published image. This is what the
|
||||
first release will make possible; it does not work today, because there is no
|
||||
image in the registry to pull:
|
||||
Write a minimal configuration and start the published image. This is what the first release will make possible; it does not work today, because there is no image in the registry to pull:
|
||||
|
||||
```sh
|
||||
cd deploy/docker
|
||||
@@ -69,32 +49,15 @@ EOF
|
||||
NXDNS_VERSION=<version> docker compose up -d
|
||||
```
|
||||
|
||||
The compose file defaults to `:latest`; pin a version for anything you intend
|
||||
to keep running. To run it before a release exists, build the image yourself and
|
||||
name it — `NXDNS_IMAGE=nxdns docker compose up -d` — as
|
||||
[docs/how-to/install-with-docker.md](docs/how-to/install-with-docker.md)
|
||||
describes. DNS is on port 53, the web UI on <http://localhost:8080>.
|
||||
The compose file defaults to `:latest`; pin a version for anything you intend to keep running. To run it before a release exists, build the image yourself and name it — `NXDNS_IMAGE=nxdns docker compose up -d` — as [docs/how-to/install-with-docker.md](docs/how-to/install-with-docker.md) describes. DNS is on port 53, the web UI on <http://localhost:8080>.
|
||||
|
||||
The compose file runs `nxdns run --config=/etc/nxdns/config.zon`, which makes
|
||||
that file the configuration: every start reconciles the database onto it, and
|
||||
the UI refuses configuration edits. Edit the file and restart to change
|
||||
anything. Drop the `command:` line to run bare `nxdns run` instead, where the
|
||||
database is the configuration and changes go through the UI, the API, or
|
||||
`nxdns export` / `nxdns import` — the packaged systemd unit does that. Which
|
||||
mode is live is printed at every start (`authority: database` /
|
||||
`authority: file (<path>)`); see
|
||||
[docs/explanation/configuration-model.md](docs/explanation/configuration-model.md).
|
||||
The compose file runs `nxdns run --config=/etc/nxdns/config.zon`, which makes that file the configuration: every start reconciles the database onto it, and the UI refuses configuration edits. Edit the file and restart to change anything. Drop the `command:` line to run bare `nxdns run` instead, where the database is the configuration and changes go through the UI, the API, or `nxdns export` / `nxdns import` — the packaged systemd unit does that. Which mode is live is printed at every start (`authority: database` / `authority: file (<path>)`); see [docs/explanation/configuration-model.md](docs/explanation/configuration-model.md).
|
||||
|
||||
Full install instructions, including the systemd path and the Pi 5 recipe, are
|
||||
in
|
||||
[docs/how-to/install-with-systemd.md](docs/how-to/install-with-systemd.md) and
|
||||
[docs/how-to/install-with-docker.md](docs/how-to/install-with-docker.md).
|
||||
Full install instructions, including the systemd path and the Pi 5 recipe, are in [docs/how-to/install-with-systemd.md](docs/how-to/install-with-systemd.md) and [docs/how-to/install-with-docker.md](docs/how-to/install-with-docker.md).
|
||||
|
||||
## Building from source
|
||||
|
||||
Requires [Zig 0.16.0](https://ziglang.org/download/) and Node.js 24 (for
|
||||
the web UI). C dependencies (SQLite, mbedTLS) are vendored and built by
|
||||
`zig build`.
|
||||
Requires [Zig 0.16.0](https://ziglang.org/download/) and Node.js 24 (for the web UI). C dependencies (SQLite, mbedTLS) are vendored and built by `zig build`.
|
||||
|
||||
```sh
|
||||
(cd web && npm ci && npm run build) # web UI -> web/dist
|
||||
@@ -102,8 +65,7 @@ zig build -Dweb-dist=web/dist # native binary -> zig-out/bin/nxdn
|
||||
zig build test --summary all # unit tests
|
||||
```
|
||||
|
||||
The release artifacts come out of the same build graph, so the whole release
|
||||
build runs on a laptop exactly as it runs on the CI runner:
|
||||
The release artifacts come out of the same build graph, so the whole release build runs on a laptop exactly as it runs on the CI runner:
|
||||
|
||||
```sh
|
||||
(cd web && npm ci && npm run build) # required: dist refuses the placeholder
|
||||
@@ -114,45 +76,25 @@ zig build verify-dist -Dversion-string="$VERSION" -Dgit-commit=$(git rev-parse H
|
||||
-Dweb-dist=web/dist -Doptimize=ReleaseSafe # the release checks
|
||||
```
|
||||
|
||||
The version comes from `build.zig.zon` because `verify-dist` asserts the two
|
||||
agree; a tag sets both.
|
||||
The version comes from `build.zig.zon` because `verify-dist` asserts the two agree; a tag sets both.
|
||||
|
||||
That is not a claim that your tarball will hash the same as a published one.
|
||||
Nothing in this project measures whether two builds of the same commit on two
|
||||
different machines land on the same bytes, so no document here describes the
|
||||
build as reproducible. The gate that would settle it is a recorded deferral —
|
||||
`specs/milestone-14.md` ruling 12 — and
|
||||
[docs/how-to/verify-a-release.md](docs/how-to/verify-a-release.md) explains what
|
||||
a matching or differing hash is worth in the meantime.
|
||||
That is not a claim that your tarball will hash the same as a published one. Nothing in this project measures whether two builds of the same commit on two different machines land on the same bytes, so no document here describes the build as reproducible. The gate that would settle it is a recorded deferral — `specs/milestone-14.md` ruling 12 — and [docs/how-to/verify-a-release.md](docs/how-to/verify-a-release.md) explains what a matching or differing hash is worth in the meantime.
|
||||
|
||||
## Documentation
|
||||
|
||||
Start at [docs/README.md](docs/README.md), which splits the documentation
|
||||
into a tutorial, how-to guides, reference and explanation.
|
||||
Start at [docs/README.md](docs/README.md), which splits the documentation into a tutorial, how-to guides, reference and explanation.
|
||||
|
||||
- [docs/tutorial/first-run.md](docs/tutorial/first-run.md) — build it, resolve
|
||||
a name, block a domain, on a scratch directory
|
||||
- [docs/how-to/install-with-systemd.md](docs/how-to/install-with-systemd.md) —
|
||||
a real install, including the Raspberry Pi 5
|
||||
- [docs/how-to/verify-a-release.md](docs/how-to/verify-a-release.md) — checking
|
||||
the hashes and the signature before you install
|
||||
- [docs/reference/configuration.md](docs/reference/configuration.md) — every
|
||||
configuration field
|
||||
- [docs/tutorial/first-run.md](docs/tutorial/first-run.md) — build it, resolve a name, block a domain, on a scratch directory
|
||||
- [docs/how-to/install-with-systemd.md](docs/how-to/install-with-systemd.md) — a real install, including the Raspberry Pi 5
|
||||
- [docs/how-to/verify-a-release.md](docs/how-to/verify-a-release.md) — checking the hashes and the signature before you install
|
||||
- [docs/reference/configuration.md](docs/reference/configuration.md) — every configuration field
|
||||
- [docs/reference/api.md](docs/reference/api.md) — REST API, auth and SSE
|
||||
- [docs/reference/cli.md](docs/reference/cli.md) — subcommands, flags and exit
|
||||
codes
|
||||
- [docs/explanation/architecture.md](docs/explanation/architecture.md) — module
|
||||
map and design
|
||||
- [PLAN.md](PLAN.md) and [specs/](specs/) — scope, design decisions and
|
||||
per-milestone contracts
|
||||
- [docs/reference/cli.md](docs/reference/cli.md) — subcommands, flags and exit codes
|
||||
- [docs/explanation/architecture.md](docs/explanation/architecture.md) — module map and design
|
||||
- [PLAN.md](PLAN.md) and [specs/](specs/) — scope, design decisions and per-milestone contracts
|
||||
|
||||
## Licence
|
||||
|
||||
Copyright (c) 2026 Mokhtar Mial. nxdns is licensed under the European Union
|
||||
Public Licence v. 1.2 (`EUPL-1.2`); the full text is in [LICENSE](LICENSE).
|
||||
Copyright (c) 2026 Mokhtar Mial. nxdns is licensed under the European Union Public Licence v. 1.2 (`EUPL-1.2`); the full text is in [LICENSE](LICENSE).
|
||||
|
||||
Every released tarball and image carries a `THIRD-PARTY-NOTICES` file assembled
|
||||
from the reviewed inventory in [licenses/](licenses/), which covers what the
|
||||
artifacts actually contain: musl, the Zig runtime, SQLite, Mbed TLS and its
|
||||
vendored Everest and p256-m code, and the JavaScript and CSS bundled into the
|
||||
admin UI.
|
||||
Every released tarball and image carries a `THIRD-PARTY-NOTICES` file assembled from the reviewed inventory in [licenses/](licenses/), which covers what the artifacts actually contain: musl, the Zig runtime, SQLite, Mbed TLS and its vendored Everest and p256-m code, and the JavaScript and CSS bundled into the admin UI.
|
||||
|
||||
Reference in New Issue
Block a user