DNS

Split-horizon design: «MYDOMAIN» resolves only inside tailnets that point at the internal resolver. There are no public service records.

Internal zone — Technitium

technitiumdns (LXC 101) is authoritative for «MYDOMAIN». Every service hostname is an A record pointing at the caddy tailnet IP — Caddy routes by name from there (caddy).

RecordTargetService
cdb.«MYDOMAIN»«CADDY_TAILNET_IP»apache-couchdb / LiveSync
«GITEA_DOMAIN»«CADDY_TAILNET_IP»gitea
lldap.«MYDOMAIN»«CADDY_TAILNET_IP»lldap
pocketid.«MYDOMAIN»«CADDY_TAILNET_IP»pocket-id
wastebin.«MYDOMAIN»«CADDY_TAILNET_IP»wastebin
wiki.«MYDOMAIN»«CADDY_TAILNET_IP»wiki

External DNS — Cloudflare

  • «MYDOMAIN» registered at Namecheap, DNS hosted on Cloudflare.
  • Cloudflare holds: NS records for the domain, MX, and the TXT records used for Let’s Encrypt DNS-01 validation.
  • No public A records for any service — intentional (see decisions).

Client resolution

Tailnet clients use Split DNS:

  • «MYDOMAIN» queries → technitium at «TECHNITIUM_TAILNET_IP»
  • everything else → Quad9 upstream

Why this works despite the edge firewall

The provider edge drops all inbound UDP — including replies to outbound UDP — so plain UDP/53 to public resolvers cannot work from «HOSTNAME» or its guests. Nothing in this design depends on it: tailnet clients resolve via 100.100.100.100 (Tailscale account DNS overrides client settings — tailscaled forwards public queries over DoH/TCP and «MYDOMAIN» queries to technitium over the tailnet’s TCP/DERP transport). The host is a tailnet client, so it resolves the same way; SDN dnsmasq on 10.0.1.1 serves vnet0 guests, recursing through the host. See topology for the edge rules.

Tailscale MagicDNS is enabled on the tailnet but only used for machine-name access (machine.«TAILNET_DOMAIN»), not for service names.

Cross-tailnet sharing

Other users are not added to the primary tailnet. Instead:

  1. They run their own Tailscale account.
  2. The caddy and technitiumdns devices are shared to their tailnet.
  3. They configure Split DNS on their tailnet so «MYDOMAIN» resolves via the shared technitium IP.

This keeps shared-device count and tailnet user seats low while giving them full access to the HTTP services.