nas.office.lan, *.lab.internal, a zone DNZ serves only inside your network) can’t get
a certificate from Let’s Encrypt or any other public CA: none of them can check a name the internet doesn’t
see. DNZ’s private certificate authority signs them itself. Routes on such names get a certificate at
once, with no challenge, and every device you install the CA’s root on trusts it.
It lives under Proxy → Certificates → Private CA in the dashboard, and dnz ca on the command line
(CLI).
Make the CA
Your issuer name, key, validity and the names it may sign.
Trust the root
A step-by-step guide per device, ending with the download address and a QR code.
Certificates it signs
For routes, Traefik, Caddy, DNZ’s own DoT and DoH, and client certificates (mTLS).
ACME
Traefik, Caddy, cert-manager and certbot ask the CA for certificates themselves.
Secondaries and clusters
Shared in a cluster; carried across a take over by export and import.
Making the CA
The CA is never made by default. A superadmin makes it on demand: Make the private CA on the Private CA tab (ordnz ca init). Every detail is yours to set, every one is editable later from the dashboard,
and every one shows in the certificates the CA signs:
Together, the subject fields are the issuer of every certificate the CA signs: the root’s subject
(common name, organization, unit, country, state, locality, e-mail), and with an intermediate, the
intermediate’s (its own common name, the rest the root’s).
Name constraints
The names the CA may sign are written into the root (and the intermediate). Devices refuse a certificate for any other name, so even a leaked key can’t vouch forgoogle.com or your bank.
- A domain name covers itself and every name under it:
lab.internalcoversnas.lab.internal. - An address range covers its addresses:
10.0.0.0/8.
.internal, .lan, .local,
.home.arpa and the like, or ones the internet doesn’t ask DNZ for), else internal, lan, local and
home.arpa, plus 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, 100.64.0.0/10 and fc00::/7.
Empty lists let the CA sign any name; DNZ warns before making such a CA. DNZ refuses to sign a name
outside the constraints.
Changing the CA: versions
A root can’t be edited in place: devices trust that exact certificate. Change on the CA card opens the same dialog, and changing the issuer, the key type, the root’s validity, the intermediate or the name constraints makes a new version with a new root. The dialog says so before saving (Make version N).- The new version is active at once. DNZ issues every certificate again from it in the background (within a minute); meanwhile the old ones stay valid and served.
- Devices that installed the old root must install the new one. The Versions list shows how often each old root was downloaded, as a reminder (“N devices may still trust only the old root”).
- Once nothing an old version signed is in use, Retire it: its keys are deleted for good, its root is no longer offered, and its last revocation list stays served.
dnz ca new-version).
Certificates
What the CA signs is listed under Private CA → Certificates (a page at a time, with a search) and with the other certificates under Proxy → Certificates. Each certificate has:
Actions on a certificate:
- Issue again now: a new key and serial.
- Revoke: its serial goes into the revocation list, with a reason, and DNZ never serves it again. A route that used it gets a new one.
- Download: the certificate and its chain as PEM. With its private key for superadmins only; every such download is in the audit log.
Where DNZ uses it by itself
DNZ Proxy routes
DNZ Proxy routes
A route on internal names gets its certificate from the CA before any public CA is asked: it is the
first step of Automatic certificates. A name is
internal when the CA may sign it and it is under
.internal, .lan, .local, .home.arpa,
.localdomain, .intranet, .corp, .home, .private or .test, or under one of the
constraints’ domain names.The route dialog’s certificate step says Private CA for such names. For other names the CA may
sign, it offers Use DNZ’s private CA (the route’s resolver is then private-ca).Traefik and Caddy proxies
Traefik and Caddy proxies
They get the certificates of their internal routes the way they get uploaded ones (Traefik’s
tls.certificates, Caddy’s load_pem): Traefik routes without a resolver and Caddy routes, with
internal names or naming the private-ca resolver.DNZ's own certificate (DoT, DoH, HTTPS)
DNZ's own certificate (DoT, DoH, HTTPS)
Settings → General → Encrypted DNS → Certificate from DNZ can pick Private CA, for internal
names and IP addresses too, so DoT and DoH work inside a network without a public name. See
Encrypted DNS.
Client certificates (mTLS)
Client certificates (mTLS)
Issue client certificates for people or devices and download them as PEM. For routes that
require client certificates, paste the root (the CA card’s Root as PEM) into a TLS option’s CAs
that sign client certificates (the proxy’s TLS settings). For an upstream that wants a client
certificate, use one from the CA as the upstream’s
client certificate.
Trusting the root on devices
A device trusts the CA’s certificates once its root is installed there. Trust the root on the Private CA tab walks through it in four steps, with your address already filled in:1
Pick where to install it
Windows, macOS, iPhone / iPad, Android, Linux, Chrome / Edge, Firefox, or Docker / servers. The
guide picks the system of the browser you opened it in first. Install the root once per device (or
per container image); every certificate the CA signs is then trusted there.
2
Follow the steps for it
Each step is a menu path to click through or one paste-and-run command, with a copy button. The
steps for every platform are below.
3
Download the root
The guide ends with the download address in large type, a copy button and a QR code: on a
phone on the same network, scan it with the camera. Below it are the files for that platform
(
dnz-root.crt, dnz-root.cer, dnz-root.mobileconfig) and the root’s SHA-256 fingerprint, with
how to show it on the device: compare the two after installing.The address comes from Settings → General → Server → Device address and DNZ’s HTTP port, unless
the CA has one of its own. It can be changed right there (DNZ warns on localhost or 127.0.0.1,
which is the machine you are on, not where devices reach DNZ; behind a reverse proxy, use the
proxy’s address), and a superadmin can Save as the CA’s address.4
Check it
The guide lists HTTPS addresses with a certificate from the CA: DNZ’s own
/ca/check when the CA
signs DNZ’s certificate, and routes on internal names. Open one on the device: no warning means it
is trusted. Test from this browser checks it from the browser you are in.The steps per platform
Replacehttp://192.168.1.10:8080 with the address the guide shows (the guide fills it in for you).
- Windows
- macOS
- iPhone / iPad
- Android
- Linux
- Chrome / Edge
- Firefox
- Docker / servers
Windows keeps one trust store for the whole machine: Chrome, Edge and most programs use it.
-
Open PowerShell as administrator (Start → type PowerShell → Run as administrator) and paste
this. It downloads the root and adds it to Trusted Root Certification Authorities:
-
Or by hand: download
dnz-root.crt, double-click it, then Install Certificate… → Local Machine → Place all certificates in the following store → Browse… → Trusted Root Certification Authorities → Finish. - Many PCs in a domain: import it once in a Group Policy instead: Group Policy Management → Computer Configuration → Policies → Windows Settings → Security Settings → Public Key Policies → Trusted Root Certification Authorities → Import….
- Close every browser window and open the browser again.
certutil -hashfile dnz-root.cer SHA256.Public addresses
The root is public and needs no sign-in: it is the certificate only, no key.
The same files are also under
/api/ca/root.crt, /api/ca/root.cer and /api/ca/root.mobileconfig.
ACME
Traefik, Caddy, cert-manager, certbot and lego can ask the CA for certificates themselves over ACME (RFC 8555), as they would ask Let’s Encrypt, and renew them by themselves. Private CA → ACME in the dashboard,dnz ca acme on the command line. It is off by default: nothing answers
under /acme/ until a superadmin turns it on.
The directory address to give clients is https://<DNZ>/acme/private-ca/directory. It names the CA, not a
version, so it stays the same through new versions.
Who gets which names
An order is only taken when every name in it is inside the CA’s name constraints and on the account’s allow list: zones or suffixes (lab.internal covers it and every name under it,
wildcards included).
An account gets its list from the external key it signed up with (external account binding): a key a
superadmin makes per client, with what that client may ask for. A key binds one account, and its secret shows
once, when it is made. If anyone may sign up, a new account gets the What new accounts may ask for list; left
empty, it can’t get anything until a superadmin gives it a list.
The allow list is what authorizes a name in a zone DNZ holds, since DNZ answers that DNS challenge itself.
Keep it as narrow as each client needs.
Challenges
tls-alpn-01 is not offered. Only DNS names are ordered; addresses aren’t. A pending answer sits next to any
real TXT record at the name, and costs DNS nothing while no challenge is pending.
Set up a client
The dashboard has a guide per client with the address, the name and the key filled in and a copy button on each block. Run it on the machine with the client: it doesn’t have to be DNZ’s. Withhttps://dns.lab.internal as
DNZ’s address, and the root downloaded first (Public addresses):
- certbot
- lego
- Caddy
- Traefik
- cert-manager
http-01, --standalone --preferred-challenges http in place of the --manual line: port 80 must
reach this machine from DNZ’s network.What it signs
Every certificate is listed under Private CA → Certificates (For an ACME client), and every issuance is in the audit log (ca.acme.issue, by acme account <id>). DNZ never holds its private key, so it is
neither served to proxies, nor renewed by DNZ, nor counted in the alerts about expiring certificates: the client
renews, and an old certificate simply ends. Revoke works as for any other certificate, here or over ACME (by
the account that ordered it, by one holding valid authorizations for all its names, or with the certificate’s own
key), and lands in the revocation list.
A new version of the CA doesn’t touch these certificates: they keep working until they end, and each client’s next
renewal comes from the new version. An older version can be retired only after they ended. Orders that finished and
certificates that ended stay for 30 days, then go.
In a cluster, on a secondary
- In a cluster any server answers: accounts and orders live in the database. Nonces are per
server, so a nonce from another server gets
badNoncewith a fresh one, which clients retry with. - A DNZ secondary following a primary signs nothing:
/acme/answers 503 there, and its settings are refused. It does answer the primary’s pendingdns-01challenges, within a minute. A client that checks all of a zone’s name servers before it says it is ready (lego, cert-manager) may wait that long. - After a take over, the new primary has no CA of the old one, so clients have to sign up again there.
Security
- The CA’s keys live in DNZ’s database like every private key DNZ holds, so they are in its backups too: encrypt the archives. They never appear in an API answer, a list, the proxy YAML export, the logs or to an AI assistant.
- Making, changing, exporting and importing the CA, and downloading a certificate’s private key, need a
superadmin. Issuing, renewing, revoking and downloading certificates need Manage proxies
(
proxy.manage). - Everything is in the audit log:
ca.create,ca.change,ca.version,ca.retire,ca.export,ca.import,ca.certificate.issue,ca.certificate.reissue,ca.certificate.revokeandca.certificate.download_key. - The ACME server’s settings, external keys and allow lists need a superadmin and are audited too
(
ca.acme.settings,ca.acme.key_create,ca.acme.key_delete,ca.acme.account_allow,ca.acme.account_deactivate), and so is what clients do (ca.acme.account,ca.acme.issue,ca.acme.revoke,ca.acme.key_change). - Export (superadmin, confirmed) gives the active version with its keys as one PEM file, to back it up or move it. Import makes such a file the active version. Anyone with the file can sign certificates every device that trusts the root accepts: keep it like a password.
- The AI assistant tools
private_caandprivate_ca_acmeread the CA, its certificates, the root and the ACME server’s accounts, keys and orders, never a key or a key’s secret. An assistant signed in over OAuth can’t download a certificate’s key, export the CA, or change anything of the ACME server.
Secondaries and clusters
- In a cluster the servers share the CA (one database); the leader renews and moves certificates.
- A DNZ secondary following a primary over replication signs nothing and refuses changes to the CA: its certificates are the primary’s. The CA isn’t copied to a secondary (certificates aren’t DNS answers).
- After a take over, the new primary has no CA of the old primary’s. Export the CA on the old primary first and import it on the new one, so devices keep trusting the same root.
- Dashboard
- CLI
On the old primary: Proxy → Certificates → Private CA → Export. On the new primary: the same tab
→ Import, and paste the file.
Metrics
Certificates the CA signs also count in
dnz_certificate_expiry_timestamp_seconds (source="ca") and in
the proxy alerts for certificates about to expire. See
Prometheus.
From the terminal and the API
Not yet
- OCSP (the revocation list covers revocation inside a network).
- Over ACME: addresses as names (RFC 8738),
tls-alpn-01, renewal information (ARI). - An offline root (only the intermediate inside DNZ).