When you run services across multiple data centers or cloud regions, getting users to the nearest endpoint matters. Every extra hop adds latency, and a user in Tokyo hitting your US East server can easily see 150-200ms of unnecessary round-trip time. Geographic DNS — or GeoDNS — solves this at the DNS layer by returning different IP addresses based on where the query originates.
While managed services like Cloudflare Load Balancing or AWS Route 53 Latency Routing offer this out of the box, running your own GeoDNS gives you full control, zero per-query costs, and no vendor lock-in. This guide covers three open-source approaches to self-hosted GeoDNS: PowerDNS with its GeoIP backend, BIND9 with views, and CoreDNS with the geoip plugin.
Why Self-Host GeoDNS?
GeoDNS routing is a foundational technique for any globally distributed infrastructure. Whether you’re serving a web application from multiple regions, running a CDN edge network, or distributing API traffic across continents, DNS-level geographic routing delivers tangible benefits:
- Reduced latency: Users get routed to the physically closest server, cutting round-trip time by 50-80% for international traffic.
- Compliance and data residency: Route European users to EU-based servers to satisfy GDPR requirements, or keep traffic within specific jurisdictions.
- Cost control: Managed GeoDNS providers charge per million queries. At scale, self-hosting saves thousands of dollars per year.
- Failover integration: Combine geographic routing with health checks so traffic automatically shifts when a region goes down.
- No vendor lock-in: Your DNS configuration lives in your own infrastructure, not a cloud provider’s proprietary format.
If you’re already running your own self-hosted DNS servers, adding GeoDNS capabilities is a natural next step. And for broader load-balancing needs, you can pair GeoDNS with DNS-level load balancing tools or reverse proxy solutions.
How GeoDNS Works
GeoDNS operates by examining the source IP address of each DNS query and mapping it to a geographic region using a GeoIP database. The DNS server then returns a different A or AAAA record depending on which region the query came from.
The workflow looks like this:
- A user’s resolver sends a DNS query for
app.example.com - Your authoritative DNS server extracts the resolver’s IP address
- A GeoIP database (MaxMind, DB-IP, or IP2Location) maps that IP to a country, continent, or city
- The DNS server selects the matching record set for that region
- The resolver receives an IP address pointing to the nearest regional endpoint
The accuracy of GeoDNS depends on the quality of your GeoIP database. Country-level accuracy is typically 95-99%, while city-level accuracy ranges from 50-80%. For most GeoDNS use cases, country or continent-level routing is sufficient and more reliable.
PowerDNS Authoritative with GeoIP Backend
PowerDNS is one of the most flexible authoritative DNS servers available, with a modular backend architecture that lets you store zone data in various sources — SQL databases, zone files, and GeoIP databases. The GeoIP backend, geoip, is specifically designed for geographic DNS routing.
Key stats (as of April 2026): 4,345 GitHub stars, last updated April 17, 2026. Written in C++.
How PowerDNS GeoIP Works
The PowerDNS GeoIP backend reads a YAML zone file that maps IP ranges (via GeoIP lookups) to specific record sets. You define regions — typically by country code or continent code — and assign different A records to each region.
GeoIP Zone File Format
PowerDNS uses a custom YAML format for GeoIP zones. Here’s a complete example:
| |
PowerDNS Configuration
Add the GeoIP backend to your pdns.conf:
| |
docker Compose Setup
PowerDNS provides an official docker-compose configuration. Here’s a production-ready setup combining the authoritative server with a backend database:
| |
Download the GeoIP database from MaxMind (free GeoLite2 version available) and place it in the geoip/ directory. PowerDNS will automatically perform GeoIP lookups for each query and return the region-appropriate record.
BIND9 with Views
BIND9 is the oldest and most widely deployed DNS server. Its “views” feature provides a built-in mechanism for geographic DNS routing without requiring any additional backends or plugins.
Key stats (as of April 2026): 737 GitHub stars, last updated August 2025. Written in C. Maintained by ISC (Internet Systems Consortium).
How BIND9 Views Work
BIND9 views partition the DNS namespace into different “views” based on the source IP of the query. Each view can have its own zone data, meaning you can serve different A records to different geographic regions. You define ACLs (Access Control Lists) for IP ranges corresponding to regions, then assign each ACL to a view.
BIND9 GeoDNS Configuration
| |
Each zone file contains the region-specific records:
| |
Docker Setup for BIND9
BIND9 doesn’t have an official Docker image, but the Ubuntu-based image from Ubuntu/ISC works well:
| |
Managing GeoIP ACLs in BIND9
The main challenge with BIND9 views is maintaining the IP-to-region ACL mappings. Since BIND9 doesn’t have built-in GeoIP lookup, you need to pre-compute CIDR blocks for each region. Several tools help with this:
- ip2location CIDR generator: Converts GeoIP databases to BIND-compatible ACL files
- maxmind-geoip2-bind: Script that reads GeoLite2 databases and outputs named.conf ACL blocks
- Custom Python scripts: Parse GeoIP CSV exports and generate CIDR ranges
A typical workflow is to regenerate the ACL file weekly from an updated GeoIP database and reload BIND9 with rndc reload.
CoreDNS with GeoIP Plugin
CoreDNS is a modern, cloud-native DNS server written in Go. Its plugin architecture makes it highly extensible, and the geoip plugin adds geographic DNS routing capabilities.
Key stats (as of April 2026): 13,997 GitHub stars, last updated April 16, 2026. Written in Go. Now a graduated CNCF project.
How CoreDNS GeoIP Works
CoreDNS’s geoip plugin reads a MaxMind GeoIP database and uses it to determine the geographic origin of each query. Combined with the rewrite or hosts plugins, you can return different records based on the detected region.
Corefile Configuration
| |
Docker Compose for CoreDNS
CoreDNS ships as a single binary and has an official Docker image:
| |
CoreDNS is the simplest to deploy of the three options — it’s a single binary, starts in milliseconds, and uses minimal memory. The plugin ecosystem also means you can chain GeoDNS with rate limiting, caching, and health checking in the same server.
Comparison Table
| Feature | PowerDNS GeoIP | BIND9 Views | CoreDNS GeoIP |
|---|---|---|---|
| GeoIP method | Native GeoIP backend | Manual CIDR ACLs | GeoIP plugin |
| Database support | MaxMind, DB-IP | External CIDR mapping | MaxMind GeoLite2 |
| Granularity | Country, continent | CIDR-based | Country, continent |
| Dynamic updates | API-driven, live reload | Requires rndc reload | Hot-reload Corefile |
| Setup complexity | Medium | High (manual ACLs) | Low |
| Performance | Excellent | Excellent | Excellent |
| Memory usage | ~100-200 MB | ~50-150 MB | ~20-50 MB |
| Web UI / API | Yes (built-in REST API) | No | No (plugins available) |
| Docker image | Official | Community (ubuntu/bind9) | Official |
| Cloud-native | No | No | Yes (CNCF graduated) |
| Best for | Large deploymentskubernetesackends | Legacy DNS infra, enterprise | Kubernetes, microservices |
| GitHub stars | 4,345 | 737 | 13,997 |
| Language | C++ | C | Go |
Choosing the Right Solution
Pick PowerDNS GeoIP if:
- You need a battle-tested authoritative DNS server with database-backed zones
- You want built-in API access for automated zone management
- You need multi-backend support (GeoIP + SQL + zone files simultaneously)
- You’re running a large-scale DNS infrastructure with complex zone requirements
Pick BIND9 Views if:
- You’re already running BIND9 and want to add GeoDNS without introducing a new server
- You need maximum compatibility with existing DNS tooling and monitoring
- Your organization has BIND9 expertise and standardized on ISC software
- You need fine-grained control over IP-to-region mappings at the CIDR level
Pick CoreDNS GeoIP if:
- You’re running Kubernetes or a cloud-native stack
- You want the simplest deployment (single binary, minimal config)
- You need to chain DNS features (GeoDNS + caching + rate limiting + health checks)
- Memory footprint matters — CoreDNS uses 2-5x less RAM than PowerDNS or BIND9
Practical Deployment Tips
GeoIP Database Updates
All GeoDNS solutions depend on the accuracy of your GeoIP database. Set up automated updates:
| |
Health Check Integration
GeoDNS becomes powerful when combined with regional health checks. If your Tokyo endpoint goes down, you want Asian traffic to fail over to Singapore or the US automatically. CoreDNS’s health and rewrite plugins can implement this pattern. PowerDNS offers the lua backend for custom health check logic.
Testing Your GeoDNS Setup
Verify that queries from different regions return the correct IPs:
| |
Each subnet query should return the IP address associated with that geographic region.
FAQ
What is GeoDNS and how does it differ from regular DNS?
Regular DNS returns the same IP address for every user regardless of location. GeoDNS (geographic DNS) examines the source IP of each query and returns different IP addresses based on the user’s geographic location. This enables you to route European users to a Frankfurt data center, Asian users to Tokyo, and US users to Virginia — all through standard DNS resolution.
How accurate is GeoDNS routing?
Country-level GeoIP accuracy is typically 95-99%. City-level accuracy ranges from 50-80%. For GeoDNS routing, country or continent-level granularity is recommended because it provides the best balance of accuracy and coverage. The accuracy depends on the GeoIP database you use — MaxMind GeoLite2 is the most popular free option.
Can I use GeoDNS with a CDN?
Yes. In fact, GeoDNS and CDNs complement each other well. GeoDNS routes users to the nearest regional entry point, and the CDN handles caching and distribution within that region. You can also use GeoDNS as a CDN alternative for simpler setups, routing traffic directly to your own regional servers.
How often should I update the GeoIP database?
Weekly updates are recommended. IP address allocations change regularly as ISPs reassign addresses and new ranges come online. MaxMind releases GeoLite2 database updates weekly. Set up a cron job to download the latest database and reload your DNS server automatically.
What happens if a user’s IP is not in any defined region?
All three solutions support a default or fallback region. If a query’s IP doesn’t match any defined country or ACL, the DNS server returns the default record set. Always configure a sensible default — typically pointing to your largest or most cost-effective data center — so that unmapped traffic still gets served.
Is self-hosted GeoDNS better than Cloudflare or AWS Route 53?
It depends on your scale and needs. Cloudflare and Route 53 are easier to set up and include health checks, but they charge per million DNS queries. At 100+ million queries per month, self-hosting becomes significantly cheaper. Self-hosted GeoDNS also gives you full control over routing logic, no vendor lock-in, and the ability to integrate with internal systems.
Can I combine GeoDNS with load balancing?
Absolutely. GeoDNS handles the first layer — routing users to the right region. Within each region, you can use standard load balancers (HAProxy, NGINX, Envoy) to distribute traffic across multiple servers. This two-tier approach (GeoDNS → regional load balancer → backend servers) is the architecture used by many large-scale web platforms.