DNS as Foundational Dependency

dns-foundational-dependency Doc

architecture infrastructure dns

Thesis

DNS is the foundational dependency of nearly every project that serves users. It's the first thing that must work and the last thing you notice — until it doesn't. Every layer above it (TLS, reverse proxy, app routing, SSO redirects) assumes DNS is already correct. When DNS is broken, nothing above it can be debugged meaningfully.

The Dependency Chain

For any custom domain to go live, three waves must complete in order:
  • DNS records — A/CNAME records pointing the domain to the right IP. Without this, the domain doesn't resolve at all. This is pure IaC: godaddy_dns_record resources managed by OpenTofu.
  • Reverse proxy — Caddy/nginx config that accepts traffic for the domain, terminates TLS (via ACME/Let's Encrypt), and routes to the backend. TLS cert provisioning itself depends on DNS being correct — ACME HTTP-01 challenges need the domain to resolve to the proxy.
  • Application config — Rails config.hosts, Keycloak realm settings, CORS origins, OAuth redirect URIs. The app must know its own domain. This is the last mile, and it's meaningless without the first two.

Why DNS Is Special

  • Invisible when working. DNS is infrastructure you forget exists — until propagation delays, stale records, or missing entries make everything downstream look broken for no apparent reason.
  • Slow feedback loop. TTLs mean mistakes take minutes to hours to manifest and equally long to fix. You can't iterate on DNS the way you iterate on app code.
  • Blast radius. A wrong A record doesn't just break one endpoint — it breaks every service, cert renewal, and auth flow on that domain.
  • Hard to test locally. Unlike app code, you can't spin up DNS in a dev environment. You're always testing against the real thing (or maintaining /etc/hosts hacks that hide real issues).
  • Silent failures. A missing DNS record doesn't throw an error — the domain just doesn't resolve. Curl gets "could not resolve host." Users get a browser error page. There's no stack trace pointing at the root cause.

Implications for Platform Work

  • DNS goes first. When onboarding a new domain, create and verify DNS records before touching proxy or app config. Don't parallelize wave 1 with wave 2 — wave 2 literally can't succeed without wave 1.
  • DNS must be IaC. Manual DNS changes via a registrar UI are invisible to the rest of the platform. The godaddy-tofu provider exists specifically to keep DNS in the same tofu state as everything else.
  • Verify at the DNS layer first. When a domain isn't working, start with dig / nslookup before checking proxy logs or app config. 90% of "the domain is broken" issues are DNS issues.
  • Treat DNS changes as high-risk. TTL propagation means rollback isn't instant. A bad DNS change is a slow-motion incident.

pal-e Platform Context

On pal-e, the chain is:
The godaddy_dns_record resources in pal-e-platform/terraform/dns.tf point domains at module.hetzner_edge.server_ipv4, creating an explicit Terraform dependency: DNS records can't be planned without the Hetzner module refreshing first. This is correct — the IP must exist before DNS can reference it.