> ## Documentation Index
> Fetch the complete documentation index at: https://docs.dnzwithazee.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Upgrading

> Upgrade DNZ with Docker, the install script or a cluster, take a backup first, and what each release with breaking changes needs from you.

Most upgrades need nothing from you: DNZ upgrades its database by itself when the new version
starts. Some releases change the database in ways that can't be undone without a backup. They are
listed under [Breaking changes](#breaking-changes): read the ones between your version and the new
one before you start.

To see which version runs now:

```bash theme={null}
dnz --version
docker exec dnz dnz --version   # with Docker
```

## Take a backup first

A newer DNZ upgrades the database when it starts, and an older version may refuse it afterwards.
Take a backup before every upgrade, so you can go back.

> [tab] DNZ's own backups
>
> With a target set up under **Settings → Backups**, run every target now and wait for the result:
>
> ```bash theme={null}
> dnz backup run
> ```
>
> An archive restores onto the version that made it or a newer one; see
> [Backups and restore](https://docs.dnzwithazee.com/admin/backups.md). This works on every database, Redis included.

> [tab] SQLite (binary)
>
> ```bash theme={null}
> sqlite3 /var/lib/dnz/dnz.db ".backup '/root/dnz-before-upgrade-$(date +%F).db'"
> ```

> [tab] SQLite (Docker)
>
> The image has no `sqlite3`, so stop DNZ for a moment and copy the file out of the container:
>
> ```bash theme={null}
> docker compose stop dnz
> docker compose cp dnz:/data/dnz.db ./dnz-before-upgrade.db
> docker compose cp dnz:/data/dnz.db-wal ./dnz-before-upgrade.db-wal 2>/dev/null || true
> ```
>
> The upgrade below starts it again.

> [tab] Postgres or MySQL
>
> ```bash theme={null}
> pg_dump -Fc dnz > dnz-before-upgrade-$(date +%F).dump
> mysqldump --single-transaction dnz > dnz-before-upgrade-$(date +%F).sql
> ```
>
> With the Postgres container from [Docker with Postgres](https://docs.dnzwithazee.com/deploy/database.md#docker-with-postgres):
>
> ```bash theme={null}
> docker compose exec -T postgres pg_dump -U dnz -Fc dnz > dnz-before-upgrade-$(date +%F).dump
> ```

More on each database in [Backups and updates](https://docs.dnzwithazee.com/deploy/backups.md).

## Upgrade

> [tab] Docker Compose
>
> In the folder with your `docker-compose.yml`:
>
> ```bash theme={null}
> docker compose pull && docker compose up -d
> docker compose logs -f dnz
> ```
>
> With a pinned tag such as `terrificci/dnz:1.27.0`, change the tag in `docker-compose.yml` first.
> The log says when the database upgrade is done and DNS is listening.

> [tab] Install script
>
> Run the [install script](https://docs.dnzwithazee.com/deploy/install.md#linux-binary) again. It replaces `dnz` and `dnz-proxy`
> in `/usr/local/bin`; then restart the service:
>
> ```bash theme={null}
> curl -fsSL https://raw.githubusercontent.com/terrific-ci/dnz/main/install.sh | sh
> sudo systemctl restart dnz
> journalctl -u dnz -f
> ```
>
> Installed with `--service`, run it with `--service` again: it replaces the binary and restarts
> `dnz` itself. Add `--version` for one exact version instead of the latest.

> [tab] Binary
>
> [Copy the new binary](https://docs.dnzwithazee.com/deploy/install.md#linux-binary) out of the new image, replace it and
> restart:
>
> ```bash theme={null}
> sudo install -m 755 dnz/dnz /usr/local/bin/dnz
> sudo systemctl restart dnz
> ```

Then check that it runs the new version and answers:

```bash theme={null}
dnz --version
dnz healthcheck
```

If you run [DNZ Proxy](https://docs.dnzwithazee.com/proxy/dnz-proxy.md) nodes, upgrade them to the same version right after DNZ:
`docker compose pull && docker compose up -d` on each node, or the install script with
`--only dnz-proxy`.

### A cluster

Upgrade one node at a time: the first node on the new version upgrades the shared database, the
others keep answering meanwhile. Finish the other nodes soon after. See
[Cluster → Upgrading](https://docs.dnzwithazee.com/deploy/cluster.md#upgrading).

With [replication](https://docs.dnzwithazee.com/dns/replication.md), upgrade the primary and its secondaries to the same version.

### Going back

Stop DNZ, put the backup back in place of the database (for SQLite, remove any `dnz.db-wal` and
`dnz.db-shm` next to it, or restore the dump with `pg_restore` / `mysql`), then start the version
you came from. Changes made after the upgrade are lost. A DNZ archive restores onto the version that
made it.

## Breaking changes

Newest first. Upgrading across several versions at once is fine: what each one needs applies on
the way.

### v2.0.0

> [!WARNING]
>
> This release **permanently removes** what DNZ no longer reads: the old per-proxy services (replaced
> by [Proxy → Upstreams](https://docs.dnzwithazee.com/proxy/upstreams.md) in v1.27.0) and other tables and columns nothing uses.
> After it, going back to an older version needs a backup.

* **The copy DNZ makes.** Before dropping anything, DNZ copies a SQLite database (and the Redis
  backend's local copy) to `backups/before-cleanup-<time>.db` in the folder of the database:
  `/var/lib/dnz/backups/` with systemd, `/data/backups/` in the Docker volume. With **Postgres or
  MySQL**, DNZ makes no copy: [take a dump](#take-a-backup-first) before upgrading.
* **Going back.** After this upgrade, going back to an older version needs that copy or your own
  backup (v1.27 could still go back to v1.26 without one); see [Going back](#going-back).
* **Straight from v1.26 or older.** Allowed: the proxy services are moved into upstreams first, as
  in v1.27.0 (below), then the old tables are dropped. DNZ makes one copy before both,
  `backups/before-upstreams-<time>.db`. Check the proxies on a copy of the database before upgrading,
  as v1.27.0 describes, with the new version's image.
* **Middlewares and firewalls are every proxy's.** Each proxy's middlewares, firewalls and TCP
  middlewares are merged once into one list, **Proxy → Middlewares**. The same name with other
  settings on another proxy is renamed after that proxy (`office-edge2`): a Traefik's own routers
  (Docker labels, files) naming `dnz-office@http` there must name `dnz-office-edge2@http`. DNZ copies
  a SQLite database (and the Redis backend's local copy) to `backups/before-v2-<time>.db` first. See
  [From per-proxy middlewares](https://docs.dnzwithazee.com/proxy/middlewares.md#from-per-proxy-middlewares).
* **Transports become an upstream's connection settings.** An upstream that proxies connected to
  differently is split (`<upstream>-<proxy>`), and Caddy proxies start applying an upstream's
  connection settings. See [From per-proxy transports](https://docs.dnzwithazee.com/proxy/upstreams.md#from-per-proxy-transports).
* **Sites in DNS becomes read-only proxies.** Every Caddy and Traefik under Settings → Proxy →
  Sites in DNS becomes a [read-only proxy](https://docs.dnzwithazee.com/proxy/read-only.md) with the same settings (API and
  password, addresses or CNAME, TTL, read interval, add only, paused, division) and the same
  records, which it keeps managing. It keeps its name, or becomes `<name>-sites` when a proxy
  already has that name. Records lose the `caddy_id`, `origin_port` and `origin_https` fields.
  `dnz caddy` is now [`dnz proxy sites`](https://docs.dnzwithazee.com/cli/proxy-sites), and the API moved from
  `/api/divisions/{id}/caddies` and `/api/caddies/{id}` to [`/api/proxy-sites`](https://docs.dnzwithazee.com/api/proxy-sites)
  and `/api/proxies/{id}/sites`. See [Upgrading from v1](https://docs.dnzwithazee.com/proxy/read-only.md#upgrading-from-v1).
* **Metrics renamed.** `dnz_caddy_sync_success` and `dnz_caddy_sync_timestamp_seconds` are now
  `dnz_proxy_sites_sync_success` and `dnz_proxy_sites_sync_timestamp_seconds`, labelled `proxy`
  and `kind`. The old names are still exported for one release: move dashboards and alerts to the
  new ones. See [Prometheus](https://docs.dnzwithazee.com/dashboard/prometheus.md).
* **Check first.** `dnz proxy advanced-check --database <copy>`, run with the new version's image on a
  copy of the database, lists every merge, rename and split before you upgrade, and each Caddy and
  Traefik of Sites in DNS with the read-only proxy it becomes (see
  [Checking a proxy setup](https://docs.dnzwithazee.com/proxy/upstreams.md#checking-a-proxy-setup)).
* **Proxy YAML.** Exports are `version: 2` and hold TCP and UDP routes and each upstream's connection
  settings. Version-1 files still apply; one naming a middleware or upstream the upgrade renamed is
  refused with the new name. See [Configuration as code](https://docs.dnzwithazee.com/proxy/config-as-code.md).
* **API.** `/api/proxies/{id}/services` is gone (v1.27 answered `410 Gone`). Use
  [`/api/proxy/upstreams`](https://docs.dnzwithazee.com/proxy/upstreams) instead. `/api/proxies/{id}/middlewares` answers
  `410 Gone` too: use [`/api/proxy/middlewares`](https://docs.dnzwithazee.com/api/proxy#routes-routers-services-and-middlewares).
* **Certificate checks per server.** An upstream's *accept any certificate* switch moves onto each of
  its HTTPS servers (**Skip TLS verification** on the server's badge, `skip_tls_verify` on each server
  in the API and proxy YAML), so nothing changes for visitors. Skipping it per server is DNZ Proxy
  only: on **Traefik and Caddy**, an upstream mixing servers that skip the check with servers that
  don't has every server's certificate checked, with a warning on the proxy page. See
  [Certificate checks per server](https://docs.dnzwithazee.com/proxy/upstreams.md#certificate-checks-per-server).
* **CLI.** `dnz proxy middlewares add|edit`, `dnz notify add|set` and `dnz backup targets add|set` take
  their settings with `--settings` instead of `--config` (it clashed with the config file flag
  `-c`/`--config`). `dnz dhcp leases --search` is `-q` for short, no longer `-s`. List commands that
  page print the API's page with `--json` (`{zones, total, page, per_page}` and so on) instead of a
  bare array, and `dnz proxy routes list --json` prints `rows` with each proxy's copy in `entries`:
  scripts reading the old shapes need updating.
* **From v1.15 or older.** The server loses the query log those versions kept in the main
  database: it is dropped during the upgrade, in one step, with nothing to wait for (v1.16 and later
  keep the query log in day files). See
  [Upgrading to the day files](https://docs.dnzwithazee.com/dns/query-logs.md#upgrading-to-the-day-files).

To get the SQLite copies out of the Docker volume:

```bash theme={null}
docker compose cp dnz:/data/backups/ ./dnz-backups/
ls ./dnz-backups
```

### v1.27.0

Every proxy's services became shared upstreams on **Proxy → Upstreams**: services identical in
content became one upstream, the same name with other servers stayed apart, and nothing visitors get
changed. See [Upstreams](https://docs.dnzwithazee.com/proxy/upstreams.md#coming-from-per-proxy-services).

* DNZ copied a SQLite database to `backups/before-upstreams-<time>.db` next to it before the move.
  With **Postgres or MySQL**, take a dump before upgrading.
* The proxy page's *Advanced* tab is gone. To see before upgrading which routes hold settings only
  the proxy's YAML can change, check a copy of the database with the new version (read-only; the
  running server isn't touched):

  ```bash theme={null}
  mkdir -p ~/dnz-check
  docker cp dnz:/data/dnz.db ~/dnz-check/
  docker cp dnz:/data/dnz.db-wal ~/dnz-check/ 2>/dev/null || true
  docker run --rm --user "$(id -u):$(id -g)" -v ~/dnz-check:/check terrificci/dnz:1.27.0 \
    proxy advanced-check --database /check/dnz.db
  ```

  Without Docker:

  ```bash theme={null}
  dnz proxy advanced-check --database ./dnz-backup.db
  ```

  `--database` also takes a `postgres://` or `mysql://` URL of a restored copy. See
  [Checking a proxy setup](https://docs.dnzwithazee.com/proxy/upstreams.md#checking-a-proxy-setup).
* `/api/proxies/{id}/services` answers `410 Gone`: use `/api/proxy/upstreams`.
* Going back to v1.26 still works.

### v1.16.0

The query log moved out of the main database into one file per day on each server (`logs/` next to
the database). The old log is **not copied**: Query Logs starts empty after the upgrade and fills up
from then on. The charts and top lists keep their history. With SQLite, `dnz.db` keeps its old size
until you run `dnz db vacuum`. See
[Upgrading to the day files](https://docs.dnzwithazee.com/dns/query-logs.md#upgrading-to-the-day-files).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.