Skip to main content
A proxy’s configuration can live in Git. Export it as a YAML file, change the file in a pull request, and apply it again: DNZ shows what the file would add, change and remove before anything is written, like terraform plan. Applying a file the proxy already matches changes nothing, so a CI job can apply it on every push. It works the same for Traefik, DNZ Proxy and Caddy. Coming from Nginx? Importing its configuration gives you such a file to start from.

What the file holds

  • Routes, as the route dialog shows them: hostnames, path, where they go (upstreams of their own or an upstream of the list), HTTPS, every switch (cache, firewall, rate limit, password, sign-in, address list, custom headers, upload limits, under attack, waiting room, web application firewall), the redirect and the group. Routes set up under YAML or the dialog’s Matching come along with their conditions, priority and entry points. TCP and UDP routes are routes too.
  • Upstreams and middlewares the routes use, by name, with each upstream’s connection settings (transport). Both are every proxy’s: changing one in the file changes it on every proxy that uses it, and the plan says which. Files from before upstreams, with services: and service:, still apply.
  • Route defaults of a DNZ Proxy: redirect to https://, compression, security headers, the firewall on every route, upload limits.
Everything is named, never numbered: services, middlewares, the firewall and sign-in providers.
edge.yaml
A route without a name is named after its first hostname (app.example.com becomes app-example-com); the name is how a route is found again, so the same name updates the same route. Unknown keys are refused, so a typo such as cahce: 10m is an error instead of being ignored.

Servers from a DNS name

A load balancer whose servers come from every address of a DNS name has from_dns instead of servers. The servers DNZ found are never in the file, so a plan doesn’t change when the name’s addresses do.

TCP and UDP routes

A route with protocol: tcp or protocol: udp is a TCP or UDP route (Traefik and DNZ Proxy; Caddy has none). It goes to servers of its own (host:port) or to an upstream of the list with the same protocol. The TCP middlewares it runs are listed under middlewares with protocol: tcp, shared by every proxy’s TCP routes like the HTTP ones.
UDP routes take no hostnames, TLS, client addresses or middlewares. The route dialog’s checks apply: routing by hostname needs TLS, and a name another route of the proxy takes is refused. A version: 1 file has no TCP or UDP routes: applying it, even with --prune, leaves the proxy’s as they are.

Export and import in the dashboard

1

Export

On the proxy’s page, open YAML → Export. The file downloads as <proxy>.yaml.
2

Change it

Edit it, or keep it in a Git repository and change it there.
3

Import

Open YAML → Import…, choose the file or paste it, and click Show changes. Each route, upstream and middleware that would change is listed with its fields before and after.
4

Apply

Click Apply. Turn on Remove what the file doesn’t have to delete routes, services and middlewares the file leaves out.

From the CLI

How applying works

  • Nothing half applied. Every check the route dialog makes runs first: hostnames in your zones, one route per hostname, upstreams and middlewares that exist, sign-in providers, switches the proxy’s kind runs. An error names the route and its line, for example route shop-example-com (line 14): unknown key cahce, and nothing changes.
  • Nothing removed unless you ask. Routes, services and middlewares the file leaves out stay; --prune (or Remove what the file doesn’t have) deletes them, and their hostnames stop going through the proxy. An upstream or middleware a route still uses (on any proxy) is never removed.
  • DNS follows. A new route’s hostnames go through the proxy, with a new record pointing at it when a name has none. dns_record: false on a route leaves DNS alone.
  • Applying twice changes nothing.
  • History kept. Each route a file adds, changes or removes gets a version in route history, and every apply is in the audit log.

Secrets

Password hashes are left out of an export: each basic auth user is listed by name only, and applying keeps the hash the proxy already has for that user. A user the proxy doesn’t have needs one, written name:HASH (htpasswd -nbB name password makes it). Export with password hashes (--secrets) puts them in, for a copy that recreates the users on another server. Keep such a file out of public repositories.
The keys of an upstream’s client certificates (transport.certificates) are left out the same way: applying a certificate without its key keeps the key DNZ has, and --secrets puts them in. Sign-in routes name their provider; the provider and its client secret stay under Settings → Proxy → Sign-in and are never exported. The proxy itself (its addresses, token and Traefik API password), DNZ Proxy’s node settings, TLS certificates and entry points (the proxy’s Settings) aren’t in the file and are never touched by it, with or without prune.

GitOps with GitHub Actions

Keep the files in a repository. Pull requests show the plan; a merge to main applies it. Give the job an API token of a user who manages proxies and your DNZ server’s address.
.github/workflows/proxies.yml
A scheduled dnz proxy plan -f proxies/edge.yaml --exit-code exits with 2 when someone changed the proxy in the dashboard and it no longer matches the file: a drift check.

API

An AI assistant can export a proxy and plan a file it drafted (proxy_config_export, proxy_config_plan); applying stays with people. See AI assistants.