6 Months After Leaving Bind9: Lessons Learned from CoreDNS
After half a year of running CoreDNS in production, I’ve reached a conclusion: if Bind9 is a rugged old truck, CoreDNS is a Tesla – fast, responsive, and requiring very little maintenance. If you’ve ever had a headache from Bind9’s convoluted zone file syntax or config reloads taking seconds, CoreDNS will completely change that experience.
Written in Go, CoreDNS is extremely lightweight (consuming only about 15-30MB of RAM for a small cluster) and operates on a plugin-based architecture. Need logging? Use a plugin. Want to forward DNS to Google? There’s a plugin for that. It’s even the default DNS for Kubernetes. The biggest selling point is the configuration file (Corefile), which is very intuitive—you can understand exactly where requests are being routed just by reading through it.
Deploying CoreDNS in 5 Minutes
Instead of just talking theory, we will install the binary directly on Ubuntu/CentOS to see how simple it really is.
1. Download and Install
# Download the release (Example v1.11.1)
wget https://github.com/coredns/coredns/releases/download/v1.11.1/coredns_1.11.1_linux_amd64.tgz
# Extract and move to system bin
tar -xzvf coredns_1.11.1_linux_amd64.tgz
sudo mv coredns /usr/local/bin/
2. Create the Corefile Configuration
Create a file named Corefile. This is where all your DNS routing logic lives:
.:53 {
forward . 8.8.8.8 1.1.1.1
log
errors
}
3. Running it in Practice
# Run with sudo to bind to port 53
sudo coredns -conf Corefile
Open a new terminal and type dig @localhost google.com. If the CoreDNS terminal jumps with logs immediately, you’ve configured it correctly. Response times are usually measured in milliseconds.
Decoding the Corefile Structure
The CoreDNS structure revolves around Server Blocks. Each block represents a specific zone or port. Inside them are Plugins that act like checkpoints.
An important note: the order of plugins written in the Corefile does not affect the execution order. This order is hard-coded in the plugin.cfg file during compilation. While this may seem restrictive, it makes the system extremely stable and prevents plugins from conflicting with each other.
Configuring Internal DNS (Internal Domain)
Suppose you have a fleet of servers under .itfromzero.lan. When subnetting this fleet, if I’m too lazy to calculate manually, I often use an IP Subnet Calculator to quickly get the IP range and Broadcast address. This ensures the network configuration file is accurate from the start.
Here is how I map internal domains in the Corefile:
itfromzero.lan {
hosts {
10.0.0.10 web.itfromzero.lan
10.0.0.11 api.itfromzero.lan
fallthrough
}
log
}
. {
forward . 8.8.8.8
cache 30
}
In which:
- The domain
itfromzero.lanis handled separately via thehostsplugin. - All other requests are forwarded to Google DNS.
cache 30significantly reduces international bandwidth load by caching results for 30 seconds.
Optimizing for Production Environments
Running as a Systemd Service
To ensure CoreDNS restarts automatically after a server reboot, create a service file. Before that, remember to create a dedicated user using the command sudo useradd -r -s /usr/sbin/nologin coredns for security.
[Service]
PermissionsStartOnly=true
LimitNOFILE=1048576
CapabilityBoundingSet=CAP_NET_BIND_SERVICE
AmbientCapabilities=CAP_NET_BIND_SERVICE
User=coredns
ExecStart=/usr/local/bin/coredns -conf /etc/coredns/Corefile
Restart=on-failure
Rewrite Plugin: A Lifesaver When Renaming Services
Once, I needed to rename an API from old to new without wanting to modify code in dozens of clients. The rewrite plugin handled it in a heartbeat:
rewrite name old-api.lan new-api.lan
Real-world Experience
1. Always Enable the Health Plugin: Add health :8080 to your Corefile. Tools like Uptime Kuma or Load Balancers will rely on this endpoint to know if the DNS service is “breathing”.
2. Monitor with Prometheus: With just the line prometheus :9153, you’ll immediately have a professional dashboard to monitor latency and error rates.
3. Handling Port 53 Conflicts: On Ubuntu, systemd-resolved often occupies port 53. If CoreDNS reports an address already in use error, you need to disable it using sudo systemctl stop systemd-resolved.
4. Blocking DNS Attacks: Use the acl plugin to only allow internal IP ranges to query, preventing the server from being exploited for DNS Amplification attacks.
Conclusion
CoreDNS is the top choice if you need flexibility and a lightweight footprint. Managing it is much easier than Bind9. Try installing it in a lab environment before moving to production. If you encounter any difficulties with subnetting or zone configuration, feel free to leave a comment below!

