How Sliplane Built a Custom DNS Server in Go to Solve Propagation Latency
These articles are AI-generated summaries. Please check the original sources for full details.
How We Built Our Own DNS Server
Jonas Scholz and the Sliplane team replaced their managed DNS provider with a custom Go-based server to bypass a 10,000-record limit. This system dropped record propagation times from 90 minutes to just a few seconds.
Why This Matters
In high-growth PaaS environments, managed DNS providers often impose rigid record caps or suffer from significant API-to-nameserver propagation delays that disrupt user experience. By adopting the hidden primary pattern and utilizing standard protocols like AXFR and IXFR, engineers can achieve infrastructure independence and sub-second scaling without the overhead of ‘contact sales’ pricing models.
This architecture proves that standard database features like Postgres LISTEN/NOTIFY can effectively replace complex message queues for low-volume infrastructure events. It highlights the technical reality that standard RFC-compliant protocols allow for building highly specialized, internal tools that outperform generic managed services at scale.
Key Insights
- Sliplane reached a 10,000-record hard cap on Hetzner DNS, which would have been exceeded within weeks due to linear growth per service (2026).
- Managed DNS API propagation can take up to 90 minutes, creating a ‘broken’ experience for users deploying new services in a PaaS environment.
- The hidden primary pattern uses a private authoritative server to push zone data to public secondaries, avoiding the need for anycast or redundant global deployments.
- Postgres functions as a lightweight event bus using pg_notify(‘dns_zone_changed’, ”), handling zone change volumes that occur a few times per minute.
- Implementing IXFR (RFC 1995) is essential because some secondary providers, like Hetzner Robot, do not always fall back cleanly to full AXFR transfers.
- The sliplane-dns server uses the miekg/dns Go library to build zones and serve them via TCP-based AXFR transfers.
Working Examples
A minimal Go DNS server implementation that serves a hardcoded zone for example.com via AXFR.
package main
import (
"context"
"log"
"net/netip"
"codeberg.org/miekg/dns"
"codeberg.org/miekg/dns/rdata"
)
func main() {
soa := &dns.SOA{
Hdr: dns.Header{Name: "example.com.", TTL: 3600, Class: dns.ClassINET},
SOA: rdata.SOA{Ns: "ns1.example.com.", Mbox: "admin.example.com.", Serial: 1},
}
records := []dns.RR{
soa,
&dns.A{
Hdr: dns.Header{Name: "app.example.com.", TTL: 300, Class: dns.ClassINET},
A: rdata.A{Addr: netip.MustParseAddr("1.2.3.4")},
},
soa,
}
mux := dns.NewServeMux()
mux.HandleFunc("example.com.", func(_ context.Context, w dns.ResponseWriter, r *dns.Msg) {
r.Unpack()
w.Hijack()
env := make(chan *dns.Envelope, len(records))
for _, rr := range records {
env <- &dns.Envelope{Answer: []dns.RR{rr}}
}
close(env)
dns.NewClient().TransferOut(w, r, env)
w.Close()
})
srv := dns.NewServer()
srv.Addr = ":5553"
srv.Net = "tcp"
srv.Handler = mux
log.Fatal(srv.ListenAndServe())
}
Practical Applications
- Use Case: PaaS platforms requiring a managed subdomain for every user service can use hidden primaries to maintain thousands of A/AAAA records without per-record provider fees.
- Pitfall: Failing to implement IXFR (Incremental Zone Transfer) can lead to stale records if the secondary nameserver does not reliably fall back to AXFR.
- Use Case: Organizations with strict data residency requirements (e.g., EU-only) can use this pattern to keep primary records on internal infrastructure while using regional secondaries.
- Pitfall: Migrating nameservers requires a Saturday night cutover window due to NS record caching; cached old records will return stale data until the TTL expires.
References:
Continue reading
Next article
Actools: A CLI-Driven Drupal 11 Installer with Automated Security Auditing
Related Content
Streamlining GitHub Repository Creation with GitHub CLI
Eliminate manual browser steps by using the GitHub CLI to create and link remote repositories directly from the terminal.
Solved: Canceled my $15K/year ZoomInfo subscription. Built my own for $50/month.
A Reddit user reduced annual data costs from $15,000 to $600 by building a custom data solution using open-source tools and APIs.
Automating AquaChain: Building a Robust CI/CD Pipeline with GitHub Actions
Learn how AquaChain transitioned from manual SSH deployments to an automated GitHub Actions pipeline that completes in under 5 minutes.