Files
nxdns/docs/how-to/back-up-and-restore.md
T

5.7 KiB

Back up and restore

The configuration database is the only state worth keeping. nxdns export writes it out as a ZON file and nxdns import writes one back. The query log is deliberately not part of a backup: it is expendable history, and if it is missing it gets recreated empty.

The commands below use the scratch lab from enable DoH and DoT, data directory /tmp/nxdns-lab/data. On a real install drop --data-dir and the default /var/lib/nxdns applies.

Back up

One command, against a stopped or a running server:

nxdns export --data-dir /tmp/nxdns-lab/data --out /tmp/nxdns-lab/backup.zon
wrote /tmp/nxdns-lab/backup.zon

The write is a temp file plus a rename, so an interrupted export leaves no half-written backup, and the result is mode 0600:

stat -c '%a %n' /tmp/nxdns-lab/backup.zon
600 /tmp/nxdns-lab/backup.zon

That mode is not decoration. The file carries web.password_hash:

grep password /tmp/nxdns-lab/backup.zon
        .password = "",
        .password_hash = "$argon2id$v=19$m=19456,t=2,p=1$Gh+zg9xke6BqSVOiouRbqG50+Bs8ZGcXA6oKgs7lrKg$crTNMu5OI8yKBkp31r4+Y1OUQmLiAlH/qvsIxjBQRq4",

Treat backups as secrets. .password is always exported as "" — the plaintext is never stored anywhere — so the file re-imports without anyone knowing the password.

Without --out the export goes to stdout, where the file mode is your redirect's problem:

nxdns export --data-dir /tmp/nxdns-lab/data | head -6
// nxdns configuration
// generated by `nxdns export` — the database is the source of truth
.{
    .upstream = .{ .read_timeout_ms = 3000, .total_timeout_ms = 5000 },
    .dns = .{
        .bind_ipv4 = "127.0.0.1",

Runtime facts are left out on purpose: client first-seen and last-seen times, rule creation times, per-source domain counts and checksums. They are things a running server produces, not configuration, and including them would make two exports taken minutes apart differ.

Restore onto a fresh data directory

This is the normal restore: new machine, new disk, empty data directory. No --force, because there is nothing to overwrite.

nxdns import /tmp/nxdns-lab/backup.zon --data-dir /tmp/nxdns-lab/data-restored
info(migrations): config.db migrated from schema version 0 to 2
imported /tmp/nxdns-lab/backup.zon

The migration line is expected: import creates and migrates the database before writing to it.

Restore over an existing database

import refuses a database that already has content, so a plain import can never clobber a configured server by accident:

nxdns import /tmp/nxdns-lab/backup.zon --data-dir /tmp/nxdns-lab/data
import failed: DatabaseNotEmpty

That exits 2. Say --force when replacing is what you mean:

nxdns import /tmp/nxdns-lab/backup.zon --force --data-dir /tmp/nxdns-lab/data
imported /tmp/nxdns-lab/backup.zon

Stop the server first. import replaces the whole configuration underneath a process that has already read it, and a running server will not notice.

On a real install that is the systemd unit:

systemctl stop nxdns
nxdns import /var/backups/nxdns-config.zon --force
systemctl start nxdns

Not verified on this host. Those three lines are the only commands on this page that were not run: this machine has no installed nxdns systemd unit (systemctl status nxdns answers Unit nxdns.service could not be found.) and systemctl stop/start need root. The lab equivalent below was run, and it exercises the same stop-import-start sequence. In the lab the server is a foreground nxdns run, so stopping it is Ctrl-C in its own terminal:

nxdns export --data-dir /tmp/nxdns-lab/data --out /tmp/nxdns-lab/pre-restore.zon
# Ctrl-C the `nxdns run` terminal, or `kill` its pid from another shell
nxdns import /tmp/nxdns-lab/pre-restore.zon --force --data-dir /tmp/nxdns-lab/data
nxdns run --data-dir /tmp/nxdns-lab/data --config /tmp/nxdns-lab/etc/config.zon
wrote /tmp/nxdns-lab/pre-restore.zon
imported /tmp/nxdns-lab/pre-restore.zon

Verify a backup

The round trip is byte-stable: exporting, importing and exporting again gives an identical file. That is the cheapest check that a backup is complete and that it will load.

nxdns export --data-dir /tmp/nxdns-lab/data --out /tmp/nxdns-lab/backup2.zon
diff /tmp/nxdns-lab/backup.zon /tmp/nxdns-lab/backup2.zon \
  && echo "round trip is byte-identical"
wrote /tmp/nxdns-lab/backup2.zon
round trip is byte-identical

The same check works across data directories — export from the restored copy and diff against the backup you restored from:

nxdns export --data-dir /tmp/nxdns-lab/data-restored --out /tmp/nxdns-lab/backup3.zon
diff /tmp/nxdns-lab/backup.zon /tmp/nxdns-lab/backup3.zon \
  && echo "restored database exports identically"
wrote /tmp/nxdns-lab/backup3.zon
restored database exports identically

What is not in the backup

Everything under the data directory other than config.db:

  • querylog.db — expendable history, recreated empty when absent.
  • blocklists/ — compiled snapshots. They are rebuilt from the sources named in the configuration, so restoring the configuration is enough; the first refresh after a restore downloads them again.

The data directory layout is in files and directories.

A backup before every upgrade

There is no downgrade path. Schema migrations run forward automatically at startup and before check, export and import; nothing walks them back. Take an export before installing a new binary — see upgrade.

Every command on this page was executed on this host as written, except the systemctl block marked Not verified on this host above.