nix: a services.nxdns module that runs the packaged unit in file mode against a configuration the pinned binary accepted
This commit is contained in:
@@ -1,12 +1,12 @@
|
||||
# Install nxdns with Nix
|
||||
|
||||
Adds nxdns to a NixOS machine as a flake input pinned to a release tag. At the end `pkgs`-style references to `inputs.nxdns.packages.${system}.default` resolve to the published release binary, and a Renovate custom manager opens a pull request when a new tag appears.
|
||||
Adds nxdns to a NixOS machine as a flake input pinned to a release tag and runs it with the flake's `services.nxdns` module. At the end the machine serves DNS on port 53 from a configuration file that the pinned binary checked at build time, and a Renovate custom manager opens a pull request when a new tag appears.
|
||||
|
||||
nxdns publishes its own `flake.nix`. Its packages do not build nxdns from source: each one fetches the release tarball for the target and pins its SHA-256 hash, so a changed byte fails the build. The two supported systems are `aarch64-linux` and `x86_64-linux`, both static musl builds that need nothing on the host.
|
||||
|
||||
For the signature and checksum checks a human does once, see [verify a release](verify-a-release.md). For what each configuration field means, see [the configuration reference](../reference/configuration.md).
|
||||
|
||||
> Verification: the commands in step 1 and step 2 were run on the machine that wrote this page, against the flake at nxdns 0.0.16. `nix flake check --no-build` passed and `nix build` produced a binary that printed `nxdns 0.0.16`. The consumer snippets in step 3 and step 4 are copied from the shape `rpi.mial.net` already uses for another flake input of the same author; they were not evaluated from this checkout, which is not a NixOS configuration.
|
||||
> Verification: the commands in step 1 and step 2 were run on the machine that wrote this page, against the flake at nxdns 0.0.16. `nix flake check --no-build` passed and `nix build` produced a binary that printed `nxdns 0.0.16`. Step 3 was verified on 2026-10-20 by the flake's own checks, built with Nix 2.35.3 on an x86_64 host with KVM and the module running the 0.0.22 release: `checks.x86_64-linux.nixos-module` boots a NixOS VM with the module and `openFirewall`, gets `nas.lan` from `dig @127.0.0.1`, finds the packaged unit with its drop-in in `systemctl cat`, finds port 53 open over UDP and TCP, and switches to a configuration-only change that restarts the service and changes the answer; `checks.x86_64-linux.nixos-module-rejects-config` fails a system build on a bad regex with `FAIL rules[0].pattern: '(' is not a valid regex pattern`. The Renovate snippet in step 4 is copied from the shape `rpi.mial.net` already uses for another flake input of the same author.
|
||||
|
||||
## 1. Add the input, pinned to a tag
|
||||
|
||||
@@ -42,18 +42,56 @@ nix eval .#packages.x86_64-linux.default.outPath
|
||||
|
||||
Evaluation does not fetch the tarball. The download happens at build time, and the hash in nxdns's flake is what the build asserts the bytes against.
|
||||
|
||||
## 3. Use the package in a NixOS configuration
|
||||
## 3. Run the service
|
||||
|
||||
Pass the flake inputs to the module system, then reference the package:
|
||||
`nixosModules.default` exists from the first release after `v0.0.22`; pin that tag or a later one. A tag up to `v0.0.22` has the package only.
|
||||
|
||||
```nix
|
||||
{ inputs, pkgs, ... }:
|
||||
{
|
||||
environment.systemPackages = [ inputs.nxdns.packages.${pkgs.stdenv.hostPlatform.system}.default ];
|
||||
Write the configuration next to the NixOS configuration that uses it. The smallest file that starts is one group named `default` and one enabled upstream:
|
||||
|
||||
```zon
|
||||
.{
|
||||
.groups = .{ .{ .name = "default" } },
|
||||
.upstreams = .{ .{ .url = "https://cloudflare-dns.com/dns-query" } },
|
||||
}
|
||||
```
|
||||
|
||||
The derivation installs `bin/nxdns`, plus `LICENSE` and `THIRD-PARTY-NOTICES` under `share/doc/nxdns`. It sets `meta.mainProgram`, so `lib.getExe` resolves to the binary. Run it as a service with the unit from [install with systemd](install-with-systemd.md), or write your own module around it.
|
||||
Pass the flake inputs to the module system, import the module, and enable it:
|
||||
|
||||
```nix
|
||||
{ inputs, ... }:
|
||||
{
|
||||
imports = [ inputs.nxdns.nixosModules.default ];
|
||||
|
||||
services.nxdns = {
|
||||
enable = true;
|
||||
configFile = ./nxdns-config.zon;
|
||||
openFirewall = true;
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
Then `nixos-rebuild switch`. The module has four options:
|
||||
|
||||
| Option | Default | What it does |
|
||||
| --- | --- | --- |
|
||||
| `enable` | `false` | Runs nxdns as `nxdns.service`, as the `nxdns` system user. |
|
||||
| `package` | the release of the pinned tag | The nxdns release to run. |
|
||||
| `configFile` | none, required | The configuration, in ZON. It is installed at `/etc/nxdns/config.zon`. |
|
||||
| `openFirewall` | `false` | Opens port 53 over UDP and TCP. The web interface on port 8080 and the DoH and DoT ports stay closed; open them yourself if you want them reachable from the network. |
|
||||
|
||||
`configFile` is copied into the Nix store, which every local user can read. Do not put a plaintext `web.password` in it: put the `web.password_hash` from an export there instead, as [set up admin authentication](set-up-admin-authentication.md) describes.
|
||||
|
||||
What the module does with them:
|
||||
|
||||
- **The build checks the configuration.** `nxdns import` from the pinned `package` reads `configFile` into a throwaway database during the build. A file that `import` rejects, because it does not parse, breaks a field rule or does not reconcile, fails `nixos-rebuild` with the binary's own reason, as in `FAIL rules[0].pattern: ...`, and nothing is deployed. `nxdns check` is not used, because it queries every upstream and the build sandbox has no network. So the build does not load the DoH and DoT certificate and key files, and does not reach the upstreams: a missing certificate still stops the service at start. The build also says nothing about the database already on the machine; see the rollback note below.
|
||||
- **nxdns runs in file mode.** The service runs `nxdns run --config=/etc/nxdns/config.zon`: every start reconciles the database onto the file, and the web interface refuses configuration edits. Change the file and switch to change anything. A switch that changes only the configuration restarts the service.
|
||||
- **The unit is the packaged one.** The package installs `deploy/systemd/nxdns.service` from the release tarball, with its sandboxing and its `RestartPreventExitStatus=2 64`, and the module adds a drop-in that changes only the command line and leaves `/etc/nxdns` to NixOS. `systemctl cat nxdns.service` shows both.
|
||||
|
||||
The module does not touch the machine's own resolver. If you point `networking.nameservers` at `127.0.0.1`, the machine loses name resolution whenever nxdns is down, including while you repair it; a resolver outside the machine avoids that.
|
||||
|
||||
**Rolling back.** A `nixos-rebuild --rollback` or an older generation puts an older binary in front of a database that the newer one may have migrated. That binary refuses the database with `SchemaTooNew`, exit 2, and the unit stops instead of restarting. [Upgrade](upgrade.md#what-happens-to-the-database) describes the recovery.
|
||||
|
||||
The package alone is also available, for a machine that runs nxdns some other way: `inputs.nxdns.packages.${pkgs.stdenv.hostPlatform.system}.default` installs `bin/nxdns`, `lib/systemd/system/nxdns.service`, and `LICENSE` and `THIRD-PARTY-NOTICES` under `share/doc/nxdns`. It sets `meta.mainProgram`, so `lib.getExe` resolves to the binary.
|
||||
|
||||
## 4. Let Renovate bump the tag
|
||||
|
||||
|
||||
Reference in New Issue
Block a user