diff --git a/README.md b/README.md index 6f54d37..7d2255c 100644 --- a/README.md +++ b/README.md @@ -28,13 +28,11 @@ One static Zig binary. SQLite holds the state and the query log, which the web U ## Install -**No release exists yet.** This repository has no tags, nothing has been published to , 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--x86_64-linux-musl.tar.gz`, `nxdns--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. +Releases are published at , and the container image at `git.mial.net/mokhtar/nxdns`, which pulls without an account. Each tag publishes five assets — two static musl tarballs (`nxdns--x86_64-linux-musl.tar.gz`, `nxdns--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: ```sh cd deploy/docker @@ -49,7 +47,7 @@ EOF NXDNS_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 . +The compose file defaults to `:latest`; pin a version for anything you intend to keep running. To run an image you built yourself, 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 . 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 ()`); see [docs/explanation/configuration-model.md](docs/explanation/configuration-model.md). diff --git a/docs/how-to/install-with-docker.md b/docs/how-to/install-with-docker.md index 3492f45..34391b0 100644 --- a/docs/how-to/install-with-docker.md +++ b/docs/how-to/install-with-docker.md @@ -6,18 +6,9 @@ The image is multi-architecture — `linux/amd64` and `linux/arm64` — so the s For what each configuration field means, see [the configuration reference](../reference/configuration.md). -> Verification: the failure modes, the run and the two checks in step 3 were run -> on the machine that wrote an earlier revision of this page, against an image -> built from this checkout rather than pulled from the registry — no release is -> published yet, so nothing on this page could be run against a pulled image, -> and step 1 could not be run at all. One command was run in altered form: host -> port 8080 was occupied there, so the run and the verification commands in -> step 3 were executed with the host side of the port mappings moved to 25353 -> and 28088 rather than the 53 and 8080 printed below. The container side was -> unchanged. See the note in step 3. The `chown` to uid 65532 needs root and was -> not run. +> Verification: on 2026-10-02, steps 1 to 3 were run against the published `v0.0.21` release with an image pulled anonymously from the registry, on the host ports printed below; the notes in those steps carry the detail. The failure modes in step 2 were run on the machine that wrote an earlier revision of this page, against an image built from this checkout. The `chown` to uid 65532 needs root and was not run. > -> **Not re-run for the file-mode revision.** The compose file now ships +> **Earlier, for the file-mode revision.** The compose file now ships > `command: ["run", "--config=/etc/nxdns/config.zon"]`, and no container was > started against that command on this host: staging a release image needs > `zig build dist`, which refuses to run while `admin/dist` is stale, and the web @@ -56,12 +47,7 @@ cut -d@ -f2 IMAGE-DIGEST.txt The last two have to print the same string — `IMAGE-DIGEST.txt` holds a whole pinned reference, `name:tag@sha256:…`, so the `cut` is what reduces it to the digest `imagetools` prints. [Verify a release](verify-a-release.md) covers the key, the fingerprint, every failure message, and what the signature does and does not prove. -> Not verified on this host: no image and no release are published yet, so -> `docker pull` and every URL here fail today, and the `releases/latest` lookup -> returns 404 and leaves `VERSION` empty. That lookup was run against -> `gitea.com/gitea/tea` on Gitea `1.27.0+dev` and printed `0.15.1`. The -> `docker buildx imagetools inspect --format` shape was run here against -> `alpine:3.22` on Docker Hub and printed that image's index digest. +> Verified on 2026-10-02 against `v0.0.21`, with an empty `DOCKER_CONFIG`, so no registry credentials: the lookup printed `0.0.21`, `docker pull` succeeded without a login, `gpg --verify` printed `Good signature` with the primary fingerprint above, `sha256sum -c` printed `OK` for all three files, and `imagetools inspect` and the `cut` both printed `sha256:ce1fef32c7ee6c23656abd94e53e4d4d6b1d34fe88a2c842b82c7202d8b904c3`. ## 2. Get the compose file and write the configuration @@ -72,9 +58,7 @@ mkdir -p ~/nxdns && cd ~/nxdns curl -fLO "$BASE/raw/tag/v$VERSION/deploy/docker/compose.yaml" ``` -> Not verified against nxdns: there is no tag yet. The Gitea raw-file URL shape -> `/raw/tag//` was run here against `gitea.com/gitea/tea` on -> Gitea `1.27.0+dev` and returned the file with a 200. +> Verified on 2026-10-02: the `curl` returned `compose.yaml` from the `v0.0.21` tag with a 200. Compose bind-mounts `deploy/docker/etc-nxdns` read-only at `/etc/nxdns`. Create it and put the configuration in it: @@ -166,7 +150,7 @@ A healthy first start logs the reconcile, the authority and the bound sockets: ``` info(migrations): config.db migrated from schema version 0 to 1 -reconciled '/etc/nxdns/config.zon': upstreams +1 ~0 -0; settings +45 ~0 -0; +reconciled '/etc/nxdns/config.zon': upstreams +1 ~0 -0; settings +46 ~0 -0; settings keys changed: dns.bind_ipv4 dns.bind_ipv6 dns.port web.bind web.port … web authentication is now enabled info(nxdns): authority: file (/etc/nxdns/config.zon) @@ -183,15 +167,7 @@ dig @127.0.0.1 example.com A +short curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:8080/ ``` -> On the machine that wrote this page, host port 8080 was already taken by an -> unrelated process, so the container was verified with the host side of the -> port mappings moved to 25353 and 28088 — everything inside the container was -> unchanged, and the log still reads `serving on udp [::]:53`. Against those -> ports `dig` returned the A records for `example.com` and `curl` returned 200. -> `docker compose up -d` fails with -> `failed to bind host port 0.0.0.0:8080/tcp: address already in use` when a -> host port is occupied; free the port or edit the `ports:` list. The image -> under test was built locally, not pulled: there is nothing published to pull. +> Verified on 2026-10-02 with the pulled `v0.0.21` image, the configuration above and the unchanged `compose.yaml`, on host ports 53 and 8080: the first start logged the lines above, `dig` returned the A records for `example.com`, `curl` returned 200, and `/api/health` reported `"status":"ok"` with one of one upstreams available. `docker compose up -d` fails with `failed to bind host port 0.0.0.0:8080/tcp: address already in use` when a host port is occupied; free the port or edit the `ports:` list. The compose file publishes 53/udp, 53/tcp and 8080, keeps `/var/lib/nxdns` in the named volume `nxdns-data`, and sets the per-namespace sysctl `net.ipv4.ip_unprivileged_port_start=0` so uid 65532 can bind port 53 without any capability. Uncomment the 443 and 853 mappings when you enable the DoH or DoT listener; see [Enable DoH and DoT](enable-doh-and-dot.md). @@ -209,9 +185,7 @@ To pull the arm64 image from an x86_64 machine — to inspect it, or to save and docker pull --platform linux/arm64 git.mial.net/mokhtar/nxdns:$VERSION ``` -> Not verified on this host: nothing is published to pull, and this host is -> x86_64 with no emulation, so an arm64 image could not be started here even -> if it were. +> Verified on 2026-10-02 against `v0.0.21`: `imagetools inspect` lists `linux/amd64` and `linux/arm64`, and the pull above fetched an image whose `docker image inspect` reports `linux/arm64`. It was not started: this host is x86_64 with no emulation. ## Build the image from source instead diff --git a/docs/how-to/install-with-systemd.md b/docs/how-to/install-with-systemd.md index 41f79ac..9a8e313 100644 --- a/docs/how-to/install-with-systemd.md +++ b/docs/how-to/install-with-systemd.md @@ -14,12 +14,7 @@ For what each flag does, see [the CLI reference](../reference/cli.md); for what > target host — `install`, `systemd-sysusers`, `systemctl` — were not run; they > are marked where they appear. > -> The download in step 1 could not be run at all: this repository has no tags -> and no published release, so every release URL on this page is a 404 today. -> Its commands are the ones [Verify a release](verify-a-release.md) covers in -> full, and the URL shapes — including the `releases/latest` redirect the -> version is read from — were probed there against `gitea.com`, a public -> instance running the same Gitea series. +> The download in step 1 was run on 2026-10-02 against the published `v0.0.21` release; its note carries the detail. > > The `zig build dist` and `zig build verify-dist` blocks in the last section > were run here, both to completion and both exiting 0; that section carries @@ -62,10 +57,7 @@ The extracted directory `nxdns-$VERSION-x86_64-linux-musl/` holds everything thi | `THIRD-PARTY-NOTICES` | Licences of everything compiled or bundled in | | `INSTALL.md` | A short version of this page | -> Not verified on this host: no release exists yet, so none of these commands -> could be run against one — the `releases/latest` lookup returns 404 for this -> repository and leaves `VERSION` empty. The same lookup was run against -> `gitea.com/gitea/tea` on Gitea `1.27.0+dev` and printed `0.15.1`. +> Verified on 2026-10-02 against `v0.0.21`, from a clean directory with a clean `GNUPGHOME` holding only the key from keys.openpgp.org: the lookup printed `0.0.21`, `gpg --verify` printed `Good signature` over primary fingerprint `A206 1F6A B24D F2C0 E923 46FD 1509 B549 46D0 8A95`, `sha256sum -c` printed `OK` for both tarballs and `IMAGE-DIGEST.txt`, and the extracted directory held the six files in the table below at the modes given, with `./nxdns version` printing `nxdns 0.0.21`. ## 2. Copy the files to the target @@ -364,9 +356,7 @@ scp nxdns nxdns.service nxdns.conf pi:/tmp/ Then follow steps 3 to 6 on the Pi. -> Not verified on this host: no release exists to download, `pi` is a -> placeholder for your Pi's hostname, and this page was written on an x86_64 -> machine with no Pi attached. +> Partly verified on 2026-10-02: the `v0.0.21` aarch64 tarball downloaded and `sha256sum -c` printed `OK` for it. The `scp` and steps 3 to 6 were not run: `pi` is a placeholder for your Pi's hostname, and this page was written on an x86_64 machine with no Pi attached. ## Build from source instead diff --git a/docs/how-to/upgrade.md b/docs/how-to/upgrade.md index 4aa05a4..9020fc0 100644 --- a/docs/how-to/upgrade.md +++ b/docs/how-to/upgrade.md @@ -13,10 +13,7 @@ The normal path is to download the new release, verify it, and swap the binary. > where the substitution matters, or which was not run at all, carries its own > note. Nothing here was verified except where a note says so. > -> Step 2 could not be run at all: no nxdns release is published yet, so every -> release URL and the `docker compose pull` on this page fail today. The URL -> shapes and the verification commands are covered by -> [Verify a release](verify-a-release.md), which says what was probed and how. +> The download in step 2 was run on 2026-10-02 against the published `v0.0.21` release; its note carries the detail. ## Breaking change: `run --config` now means file authority @@ -137,10 +134,7 @@ Take `aarch64-linux-musl` for a Raspberry Pi 5. Verify every time, not only on t Under Docker there is nothing to download: step 3 pulls the image, and the `IMAGE-DIGEST.txt` asset is what you verify instead. -> Not verified on this host: no release exists yet, so the `releases/latest` -> lookup returns 404 and leaves `VERSION` empty, and every `curl` below it is a -> 404 too. The lookup form was run against `gitea.com/gitea/tea` on Gitea -> `1.27.0+dev` and printed `0.15.1`. +> Verified on 2026-10-02 against `v0.0.21`: the lookup printed `0.0.21`, every `curl` succeeded, `gpg --verify` printed `Good signature`, `sha256sum -c` printed `OK`, and the tarball extracted. [Install with systemd](install-with-systemd.md) has the detail. ## 3. Replace the binary