milestone 14: build, package, sign and publish releases

This commit is contained in:
2026-08-08 12:38:29 +02:00
parent 6c507992e4
commit cdacc560b7
48 changed files with 7272 additions and 543 deletions
+106 -21
View File
@@ -1,7 +1,11 @@
# Upgrade nxdns
Replaces a running nxdns with a newer build without losing its configuration.
The database is migrated in place on the first start of the new binary.
Replaces a running nxdns with a newer release without losing its
configuration. The database is migrated in place on the first start of the new
binary.
The normal path is to download the new release, verify it, and swap the binary.
Upgrading a build you made yourself is the last section of this page.
> Verification: the export, the migration behaviour and the `version`/`check`
> steps below were run on the machine that wrote this page, against a
@@ -11,6 +15,11 @@ The database is migrated in place on the first start of the new binary.
> have (`/var/lib/nxdns`, `/some/backup`, a `target` host), and every block
> 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.
## 1. Take an export first
@@ -46,32 +55,60 @@ The file is written atomically at mode 0600 and carries
[Back up and restore](back-up-and-restore.md) for the full backup story. The
query log is deliberately not part of it.
## 2. Build the new binary
## 2. Download and verify the new release
Read the release notes for the version you are moving to before you take it —
the `CHANGELOG.md` section for that version is the release body.
```sh
(cd web && npm ci && npm run build)
zig build cross -Dweb-dist=web/dist -Doptimize=ReleaseSafe
BASE=https://git.mial.net/mokhtar/nxdns
VERSION=$(curl -fsS -o /dev/null -w '%{redirect_url}' "$BASE/releases/latest" |
sed 's#.*/releases/tag/v##')
mkdir -p ~/nxdns-release && cd ~/nxdns-release
curl -fLO "$BASE/releases/download/v$VERSION/nxdns-$VERSION-x86_64-linux-musl.tar.gz"
curl -fLO "$BASE/releases/download/v$VERSION/SHA256SUMS.txt"
curl -fLO "$BASE/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"
```
Rebuild `web/dist` before the binary on every upgrade. The admin interface is
embedded at build time, and an old bundle against a new API is a broken
settings page.
The first line asks the server which release is current, so this block does not
carry a version number that goes stale — Gitea redirects `releases/latest` to
the newest published release's tag page. To move to a particular version rather
than the newest, set `VERSION=<version>` yourself. Check it against what you are
running (`nxdns version`) before you download anything.
Take `aarch64-linux-musl` for a Raspberry Pi 5. Verify every time, not only on
the first install — an upgrade is a fresh download of a fresh artifact.
[Verify a release](verify-a-release.md) is the full procedure.
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`.
## 3. Replace the binary
### systemd
Step 2 leaves the new binary under `zig-out/cross`, one per target. Copy the
one that matches the host — `aarch64-linux-musl` for a Raspberry Pi 5:
Step 2 leaves the new binary in the extracted directory. Copy the one that
matches the host — `aarch64-linux-musl` for a Raspberry Pi 5:
```sh
scp zig-out/cross/x86_64-linux-musl/nxdns target:/tmp/nxdns
scp "nxdns-$VERSION-x86_64-linux-musl/nxdns" target:/tmp/nxdns
```
> Not run on this host: `target` is a placeholder for the machine running
> nxdns, and this host has no such second machine to copy to. What exists here
> is the local half — `zig build cross` produced
> `zig-out/cross/x86_64-linux-musl/nxdns`.
> nxdns, and this host has no such second machine to copy to. There is also no
> release to have extracted.
The tarball also carries `nxdns.service` and `nxdns.conf`. An upgrade does not
normally reinstall them, but compare them against what is on the target when
the release notes say the unit changed.
Then, as root on the target:
@@ -90,19 +127,23 @@ journalctl -u nxdns -f
### Docker
```sh
cd deploy/docker
docker compose build
docker compose up -d
NXDNS_VERSION=$VERSION docker compose -f deploy/docker/compose.yaml pull
NXDNS_VERSION=$VERSION docker compose -f deploy/docker/compose.yaml up -d
```
Compose recreates the container against the same `nxdns-data` volume. The seed
file in `etc-nxdns` is not read again; the database in the volume is the
configuration.
> Verified on this host for the first two lines: `docker compose config -q`
> exited 0, and `docker compose build` finished with `Image nxdns Built`.
> `docker compose up -d` was not run — it publishes host ports 53/udp, 53/tcp
> and 8080, which this workstation is not a deploy target for.
Set `NXDNS_VERSION` on both lines, or export it. Without it the compose file
falls back to `:latest`, and `pull` and `up` could then land on different
images if a release happens between them.
> Not run on this host: `pull` needs a published image, and there is none.
> What was run is `docker compose -f deploy/docker/compose.yaml config`, which
> resolves the variables without contacting a registry: `NXDNS_VERSION=0.0.1`
> gave `image: git.mial.net/mokhtar/nxdns:0.0.1`, and no variable at all gave
> `:latest`.
## 4. Confirm the upgrade
@@ -234,3 +275,47 @@ refusal on their own.
>
> The `systemctl stop`/`start` lines around them need root and an installed
> service and were not run; `$EDITOR` is yours to run.
## Upgrading to a build of your own
If you are running something you built rather than a release, step 2 is a
build instead of a download:
```sh
(cd web && npm ci && npm run build)
VERSION=$(sed -n 's/^[[:space:]]*\.version[[:space:]]*=[[:space:]]*"\([^"]*\)".*/\1/p' build.zig.zon)
zig build dist -Dversion-string="$VERSION" -Dgit-commit="$(git rev-parse HEAD)" \
-Dweb-dist=web/dist -Doptimize=ReleaseSafe
```
Rebuild `web/dist` before the binary on every upgrade. The admin interface is
embedded at build time, and an old bundle against a new API is a broken
settings page. `dist` refuses the `web/dist-placeholder` default outright, so
the only way to ship a stale bundle is to leave an old `web/dist` in place.
The staged payload for each target is under
`zig-out/dist/stage/nxdns-<version>-<triple>/`, and step 3 continues from there
with that path in place of the extracted one. The version string has to equal
`.version` in `build.zig.zon``verify-dist` asserts it, so a made-up one
builds and then fails verification. What tells your build apart from the
published release of the same version is `-Dgit-commit`, which `nxdns version`
prints beside the version.
Under Docker, build the image and name it instead of pulling:
```sh
DOCKER_BUILDKIT=1 docker build -t nxdns -f deploy/docker/Dockerfile .
NXDNS_IMAGE=nxdns docker compose -f deploy/docker/compose.yaml up -d
```
See [Install with Docker](install-with-docker.md) for what that build needs.
> Verified on this host for the two build commands in this section — the
> `zig build dist` block above and the `docker build` here. `dist` was run to
> completion with the version read out of `build.zig.zon` and exited 0, and the
> image was built from the resulting `zig-out/dist` tree, also exiting 0. The
> `docker compose ... up -d` line was not run in this round — the run itself is
> covered in [Install with Docker](install-with-docker.md#3-run-it), where a
> host port had to be moved to do it. See
> [Install with systemd](install-with-systemd.md#build-from-source-instead) for
> the `dist` and `verify-dist` detail.