DNS hosting (dnso.city)
dnso.city hosts the DNS for customers' domains: they keep their zones and records on Zappocity, and dnso.city's name servers answer for them. It was built in seven steps (docs/plans/dnso.md): zones and records on the account page and over the API, the name server dnsod with DNSSEC, secondary DNS both ways, the delegation check, Mailocity teams' domains published there by automatic DNS, and billing. It is coming in the catalog until you make it available under Products: do that once dnso.city's name servers are set and two or more dnsod are answering.
Plans
| Plan | Price a month (billed yearly; monthly 20% more) | Zones | Records per zone |
|---|---|---|---|
| Free | $0 | 3 | 100 |
| Personal | $3 | 25 | 500 |
| Business | $9 | 100 | 2,000 |
| Agency | $29 | 500 | 5,000 |
Every plan has DNSSEC; Personal and up add the API and secondary DNS, Business zone import and team access, Agency priority support and your own name servers. Queries are not counted (fair use: a zone that draws abusive traffic is rate limited). A Mailocity team's own domains are free on dnso.city. Prices, limits and features are changed under Products โ dnso.city like any product's (limits: zones, recordsPerZone).
Billing: a DNS account starts on Free, renewed monthly without an invoice. On the organization's subscription on the account page, owners and billing members choose the plan and Monthly or Yearly. A dearer plan is invoiced at once for what is left of the current period (the difference in price, in proportion); a yearly or monthly period starts at the next renewal, which invoices the new period at its price; a cheaper plan takes effect without a refund. A plan the account does not fit (more zones, or more records in a zone) is refused.
For customers
On the account page, DNS hosting โ Start a DNS account makes an organization they own on the Free plan (once dnso.city is available; up to three each). Then:
- Add the zone: a domain such as
example.com. A domain is served for one account only; if someone else added yours, support moves it. - Records: name (
@for the domain itself,www,*for a wildcard), type, TTL and data, written as DNS writes them:192.0.2.1;10 mail.example.com.for MX; any text for TXT (split for DNS as needed);0 issue "letsencrypt.org"for CAA.- A name with a CNAME has nothing else, and the domain itself cannot be a CNAME: use ALIAS there, which answers with the addresses of the host it names.
- NS records delegate a name below the domain; the domain's own name servers are dnso.city's.
- Each change raises the zone's serial.
- Delegation, on the zone's page: dnso.city asks the domain's parent (the registry, such as
com) directly whether it names dnso.city's name servers for the domain (delegated), some of them (partly), others (elsewhere: set the name servers at the registrar), or has no such domain (unregistered); and whether its DS record is the zone's (on), another key's (mismatch: resolvers that check DNSSEC fail until it is replaced at the registrar) or missing (off). The answer is kept a minute; Check again asks again after that. Over the API:GET .../zones/{zoneId}/delegation;corpsuite dns zone delegation. - The organization's owners change its zones; other members read them. Owners change the plan on the organization's subscription there (a plan the account does not fit, with more zones or records than it allows, is refused).
The name servers (dnsod)
dnsod answers for every zone of an active DNS account, authoritatively, over UDP and TCP, and refuses everything else (it never looks names up for others). It reads the zones from the platform every 30 seconds, fetching only those whose serial moved, and keeps them on disk: when the platform is down, it goes on answering with what it has.
- On the platform (zappocityd, or corpsuited running the platform), make a dnsod token (32 random characters or more) and set its SHA-256 in
CORPSUITE_DNS_TOKEN_SHA256. The token only reads zones (and asks for a secondary zone to be checked when its primary sends NOTIFY). - Under Settings โ DNS hosting (Zappocity panel) or with
corpsuite dns settings set nameServers:='["ns1.dnso.city","ns2.dnso.city"]' hostmaster=hostmaster@dnso.city, name dnso.city's name servers: they are every zone's NS records, and the first is in its SOA. - Build
dnsod(make dnsod) and run one on each name server withDNSOD_PLATFORM_URL(the platform,https://...),DNSOD_TOKEN, and optionallyDNSOD_LISTEN(:53),DNSOD_DIR(/var/lib/dnsod) andDNSOD_RATE(answers a second per client network over UDP, 200). NOTIFY goes only to addresses on the internet;DNSOD_ALLOW_PRIVATE=1allows private and loopback ones, for development. A NOTIFY from a secondary zone's primary is passed on to the platform with the same token. The platform's DNS secondaries job (every minute) transfers secondary zones. - Give the name servers' addresses to the registry as glue for the name servers' own domain.
What it answers: the records as kept; CNAME chains within the zone; wildcards (*) for names that do not exist below them; referrals with glue for names delegated with NS records; ALIAS at a zone's apex as its target's current addresses (looked up at most once a minute); SOA and the apex NS from the settings; NXDOMAIN or no data with the SOA (its minimum TTL, 5 minutes); ANY with the short answer of RFC 8482.
DNSSEC
Every zone is signed. It gets a key of its own when it is added (one ECDSA P-256 key, algorithm 13, both for the zone's keys and its records); the private part is kept sealed with the platform's key file and handed to dnsod with the zone. dnsod signs its answers as it makes them, for resolvers that ask for DNSSEC, so names answered from a wildcard or an ALIAS are signed too. It proves a name or type absent with a compact denial (RFC 9824: an NSEC at the name asked, listing what it has or NXNAME), which cannot be walked to list the zone's names.
DNSSEC is on for a domain once its registrar publishes the zone's DS record, which the zone's page on the account page shows (and the zone API as dnssec.ds). Without it, resolvers use the answers unsigned.
Secondary DNS: transfers to other name servers
On plans with secondary DNS (Personal and up), a zone can also be served by name servers elsewhere, as secondaries of dnso.city. On the zone's page, under Secondary DNS, list their IP addresses (up to 10, on the internet) and save:
- The first time, the zone gets a TSIG key, named
xfr.and the domain (xfr.example.com.), HMAC-SHA256. Its secret shows this once: set the key on the other name servers. Make a new key replaces it (the old one stops within a minute) and shows the new secret once. - dnsod transfers the zone (AXFR; an IXFR gets the whole zone too) over TCP, only to a listed address and only when the request is signed with the zone's key. Anything else is refused.
- When the zone changes, dnsod sends the addresses a NOTIFY, signed with the key, so they fetch it at once.
- An empty list stops transfers. A plan without secondary DNS stops them too (the list is kept for when it returns).
What goes out: the SOA, dnso.city's NS records, and every record, except ALIAS (it has no record of its own; the secondaries cannot answer it). The zone goes out unsigned: dnsod signs as it answers, so a secondary has no signatures to give. While the domain's registrar has the zone's DS record, resolvers that check DNSSEC fail on the secondaries' answers; use secondaries elsewhere only for zones without the DS record, or keep to dnso.city's own name servers.
On a secondary such as BIND:
key "xfr.example.com." { algorithm hmac-sha256; secret "the secret"; };
zone "example.com" { type secondary; primaries { 198.51.100.53 key "xfr.example.com."; }; };
with dnso.city's name servers' addresses as the primaries.
Secondary DNS: dnso.city as the secondary of zones kept elsewhere
On plans with secondary DNS, a zone whose records are kept on name servers elsewhere (the primaries) can be served by dnso.city too. On the account page, under the DNS account, Or serve a domain as a secondary of name servers elsewhere: the domain, the primaries' IP addresses (up to 10, on the internet, asked on port 53), and the TSIG key they sign transfers with, if any (name, HMAC-SHA256, -384 or -512, and its secret, kept sealed and never shown again).
- The platform asks the primaries for the zone's SOA and, when its serial moved, transfers the zone (AXFR over TCP). It does so on the schedule the SOA sets (refresh, between 5 minutes and a day; retry after a failure), within a minute of a primary sending NOTIFY to dnso.city's name servers (from a primary's own address only), and at once with Check now.
- The zone is served once first transferred, as the primaries give it: their SOA and NS, and every record type. Its records are read on the zone's page, not changed there. When the primaries have not answered for the SOA's expire time, it stops being served.
- What went wrong with the last check (a primary not answering, a wrong key, more records than the plan allows) shows on the zone's page; the zone as last transferred goes on being served meanwhile.
- A zone signed at its primary (with DNSKEY, RRSIG or NSEC records) is not taken yet: dnso.city would serve it without the signatures it needs.
- At the primary, allow transfers to dnso.city's name servers' and the platform's addresses, send NOTIFY to dnso.city's name servers, and add dnso.city's name servers to the zone's NS records (and at the registrar) for them to be asked.
Mailocity teams' domains
A Mailocity team's own domains are free on dnso.city: under Automatic DNS on a domain's page, a team publishes at dnso.city instead of Route53 (see automatic DNS). The zone is made in a DNS account of the team's organization on the Mailocity domains plan (any number of zones, 200 records each, DNSSEC; not sold, and not listed for sale). Its owners manage it like any other zone; the mail records are kept right by automatic DNS every hour.
For staff
A dnso.city subscription's resource is its DNS account. Staff manage its zones at /v1/platform/dns/accounts/{accountId}/zones (api/platform.yaml) and on the command line: corpsuite dns zones ACCOUNT-ID, dns zone add, dns zone, dns zone remove, dns record add, dns record set, dns record remove, dns zone transfers set, dns zone transfers new-key, dns zone primaries set, dns zone refresh, dns zone delegation (see the command line).