Skip to content
GitHubLinkedIn

DNS split horizon

Split-horizon DNS ensures internal users (LAN & VPN) resolve selected public hostnames to internal IPs, while external users keep resolving them normally. This avoids hairpin NAT and keeps internal access deterministic.

Use split-horizon DNS when:

  • A service is hosted inside the LEF network.
  • The service has a public hostname.
  • LAN/VPN users must access it without routing out and back in.

Technitium DNS (https://dns.core.lef) serves different answers depending on where the client is coming from (RFC1918 ranges for LAN/VPN).

Split-horizon is applied per root domain (and then per hostname inside the zone).

The canonical list of internal zones vs public domains (and which public domains have split-horizon documented) lives under Domains. The conceptual model is described at DNS behavior.

NGINX on np-web is the single source of truth for which hostnames exist and what their internal targets are. The script get_hairpins.sh reads the NGINX configuration and generates the DNS record blocks to apply in Technitium.

  1. Update or add an NGINX virtual host on np-web.
  2. Run get_hairpins.sh on np-web to generate the Technitium records.
  3. In Technitium (https://dns.core.lef), update the matching conditional forwarder zone for the domain.
  4. Validate internal vs external resolution.

Internal (use the internal resolver):

nslookup s3.coragem.app dns.core.lef

External (use a public resolver):

nslookup s3.coragem.app 1.1.1.1
  • Internal users get public IPs: record missing or not applied to the split-horizon zone.
  • External users get internal IPs: zone scoping is wrong (public resolvers should never see internal answers).
  • Drift: NGINX changed, DNS block not regenerated/imported.
  • Caching: stale answers remain until TTL expires; flush client cache if needed.