fix: the name server is the primary of any number of domains, each with secondary name servers and a switch for the records of the sites.
Release / release (push) Successful in 13s

This commit is contained in:
slawek committed 2026-10-26 21:26:47 +01:00
1 parent 57e8bbcffe
commit 1697e1aa38
9 files changed
+412 -150

No files matched your search

+36 -22
View File
@@ -15,7 +15,7 @@ A Debian package that configures a Linux host or virtual machine as a VPN router
- metrics of the router kept in PostgreSQL, served for an OpenTelemetry Collector and pushed
over OTLP
- static web sites served by Caddy, uploaded through the web service or WebDAV, and an optional
authoritative name server (PowerDNS) for a zone of the sites
primary name server (PowerDNS) of the router's domains, with secondaries and records for the sites
Nothing in the package is specific to a cloud provider. It is built on the external and
internal NIC names, and a `mode` setting says how much of the rest you are supplying and
@@ -147,10 +147,9 @@ must have the type shown below; an unknown section or setting is an error.
| `sites` | `upload_max_mb` | integer | `512` | The largest upload of a site's file or zip archive, in MiB, 1 to 10240 |
| `sites` | `webdav` | boolean | `false` | WebDAV of the sites' folders, which needs `https.enabled` and `wan.local_fqdn` (see WebDAV) |
| `sites` | `webdav_port` | integer | `7445` | HTTPS port of WebDAV |
| `dns` | `enabled` | boolean | `false` | The name server of `dns.zone`, which needs `dns.zone`, `dns.nameserver` and `dns.addresses` (see Name server) |
| `dns` | `zone` | string | | The zone the name server answers for |
| `dns` | `nameserver` | string | | The name server's host name |
| `dns` | `addresses` | list | | The public addresses of the zone's apex, the name server and the sites' host names |
| `dns` | `enabled` | boolean | `false` | The primary name server of the router's domains, which needs `dns.nameserver` and `dns.addresses` (see Name server) |
| `dns` | `nameserver` | string | | The name server's host name, the primary NS of every domain |
| `dns` | `addresses` | list | | The public addresses of the name server, the domains' apexes and the sites' host names |
| `dns` | `listen` | string | `external` | The interfaces the name server answers on: `internal`, `external` or `both` |
| `dns` | `ttl` | integer | `300` | TTL of the records, 60 to 86400 seconds |
| `pki` | `root_name` | string | `VPN Router Root CA` | Common name of the root CA, when the router creates it |
@@ -1177,10 +1176,15 @@ curl -X PUT -H "Authorization: Bearer $TOKEN" --data-binary @site.zip \
| Request | Answer |
| --- | --- |
| `GET /dns` | `{"settings", "installed", "running", "records", "manual", "problem"}`: the `dns` section, whether PowerDNS is installed and runs, the records it serves, the manual records, and why they cannot be read, `null` when they can |
| `GET /dns` | `{"settings", "installed", "running", "domains", "problem"}`: the `dns` section, whether PowerDNS is installed and runs, the domains, each `{"name", "sites", "ttl", "secondaries", "manual", "records"}` with its secondaries `{"nameserver", "address"}`, its manual records and the records it serves, and why they cannot be read, `null` when they can |
| `PUT /dns` | Changes any of the settings of the `dns` section |
| `POST /dns/records` | Adds a manual record: `{"name", "type", "content", "ttl"?}`; `name` is relative to `dns.zone`, `@` for the zone itself, or absolute with a final dot, and `ttl` is `dns.ttl` without it |
| `DELETE /dns/records?name=&type=&content=` | Removes the manual records of the name and type, only the one of `content` when it is given |
| `POST /dns/domains` | Adds a domain: `{"name", "sites"?, "ttl"?}`; an existing name is 409 |
| `PUT /dns/domains/<domain>` | Changes `sites` or `ttl` of the domain |
| `DELETE /dns/domains/<domain>` | Removes the domain with its secondaries and manual records |
| `POST /dns/domains/<domain>/secondaries` | Adds a secondary name server, or changes its address: `{"nameserver", "address"}` |
| `DELETE /dns/domains/<domain>/secondaries/<nameserver>` | Removes the secondary name server |
| `POST /dns/domains/<domain>/records` | Adds a manual record: `{"name", "type", "content", "ttl"?}`; `name` is relative to the domain, `@` for the domain itself, or absolute with a final dot, and `ttl` is the domain's without it |
| `DELETE /dns/domains/<domain>/records?name=&type=&content=` | Removes the manual records of the name and type, only the one of `content` when it is given |
A TXT content without quotes is quoted; MX is `<preference> <host>`, SRV `<priority> <weight>
<port> <host>` and CAA `<flags> <tag> "<value>"`. A CNAME must be its name's only record.
@@ -1583,9 +1587,9 @@ vpn-config-edit set --restart sites.webdav true
### Name server
While `dns.enabled` is `true`, `vpn-router-setup` runs PowerDNS (`pdns.service`) as the
authoritative name server of one zone, `dns.zone`, on port 53 of the addresses of `dns.listen`
primary name server of the router's domains, on port 53 of the addresses of `dns.listen`
(`internal`, `external`, the default, or `both`), which the firewall opens for UDP and TCP. The
records are in the database `vpn-router-dns` (password in `/etc/vpn-router/dns-database.secret`),
domains and records are in the database `vpn-router-dns` (password in `/etc/vpn-router/dns-database.secret`),
read by PowerDNS's gpgsql backend; setup writes the settings
`/etc/powerdns/pdns.d/vpn-router.conf` (root, group `pdns`, 0640) and installs `pdns-server` and
`pdns-backend-pgsql` from the Ubuntu archive with `vpn-router-install@dns.service` when they are
@@ -1593,21 +1597,31 @@ missing, without the recommended bind backend.
| Setting | Meaning |
| --- | --- |
| `dns.zone` | The zone, such as `sites.example.com` |
| `dns.nameserver` | The name server's host name, the zone's NS and the SOA's primary |
| `dns.addresses` | The public addresses of the zone's apex, of the name server when it is in the zone, and of every host name of an enabled site in the zone |
| `dns.ttl` | The TTL of the records and the SOA's negative TTL, 60 to 86400 seconds, 300 by default |
| `dns.nameserver` | The name server's host name, the primary NS and the SOA's primary of every domain |
| `dns.addresses` | The public addresses of the domains' apexes, of the name server in a domain it is inside, and of the sites' host names |
| `dns.ttl` | The TTL of the records and the SOA's negative TTL of a domain without its own, 60 to 86400 seconds, 300 by default |
Records added with `/dns` or the Router Manager (A, AAAA, CNAME, TXT, MX, SRV, CAA) are served
too, but not those of a name and type the zone's own records have. Setup writes the zone at each
run; the SOA's serial grows only when the records change. While P2S, OpenVPN or WireGuard is enabled,
dnsmasq answers their clients on port 53 of the addresses of `p2s.dns_listen`, by default the
internal address, so `dns.listen` must not share an interface with it. The parent zone must delegate `dns.zone` to `dns.nameserver`, with glue records for
a name server inside the zone.
The domains are added with `/dns` or the Router Manager, each with:
- **Site records**: every host name of an enabled site gets A and AAAA records of `dns.addresses`
in the closest domain it is in, when that domain has site records;
- **TTL**: the TTL of its records, `dns.ttl` when not set;
- **Secondaries**: name servers, each a host name, which becomes an NS of the domain, and the
address it transfers the domain from. The router notifies that address of every change and
allows it zone transfers (AXFR); a secondary's name inside the domain gets an A or AAAA record of
that address;
- **Manual records** (A, AAAA, CNAME, TXT, MX, SRV, CAA), served too, but not those of a name and
type the domain's own records have.
A domain inside another domain of the router is delegated from it with NS records. Setup writes the
domains at each run, and after each change through `/dns`; the SOA's serial grows only when the
records change. While P2S, OpenVPN or WireGuard is enabled, dnsmasq answers their clients on port 53
of the addresses of `p2s.dns_listen`, by default the internal address, so `dns.listen` must not
share an interface with it. The parent zone of each domain must delegate it to `dns.nameserver` and
the secondaries, with glue records for name servers inside the domain.
```sh
vpn-config-edit set dns.zone sites.example.com
vpn-config-edit set dns.nameserver ns1.sites.example.com
vpn-config-edit set dns.nameserver ns1.example.com
vpn-config-edit set dns.addresses 203.0.113.10
vpn-config-edit set --restart dns.enabled true
```