devto 2026-07-01 원문 보기 ↗
⚡ It started as a simple typo in /etc/hosts. One wrong hostname. One overlooked IP.
In an instant, my homelab descended into chaos:
It was a domino effect: a tiny DNS misconfiguration brought down my entire lab environment.
That’s when I realised: manual DNS editing was a ticking time bomb.
Enter GitOps for DNS - a workflow that stores every host entry in a repo under version control, automates deployment, and ensures a single source of truth.
No more human error. No more cascading failures.
In this guide, we’ll implement GitOps-style DNS using dnsmasq, GitHub, Bash, and a cronjob - making your homelab DNS predictable, maintainable, and secure.
Deploy keys (SSH keys) are used to secure repository access, ensuring only your DNS server can pull updates.
.cfg files for easier managementsudo yum install -y dnsmasq git # RHEL/CentOS/AlmaLinux
sudo apt install -y dnsmasq git # Debian/Ubuntu
Create a config file in /etc/dnsmasq.d/:
/etc/dnsmasq.d/000-base.conf
domain=safesploit.com
expand-hosts
log-queries
no-hosts
addn-hosts=/etc/hosts.d
listen-address=172.16.5.27
📝 Tip: Always bind dnsmasq to a specific NIC (
listen-address)⚠️ using
0.0.0.0is not supported.
Otherwise, dnsmasq will only respond on127.0.0.1.(
/etc/hosts.d/ (Optional, Modular Setup)
sudo mkdir -p /etc/hosts.d
sudo touch /etc/hosts.d/000-network.cfg
# sudo touch /etc/hosts.d/XXX-*.cfg # placeholder files
sudo systemctl enable dnsmasq
sudo systemctl start dnsmasq
Now dnsmasq is ready to resolve hostnames from /etc/hosts.d/.
Use dig @<DNS Server IP> <DNS Entry> to query:
dig @172.16.5.27 ldap.safesploit.com +short
This gives proof it works
Add new .cfg files to /etc/hosts.d/ following a consistent naming scheme like XXX-<subnet_name>.cfg:
005-critical-prod.cfg → critical production hosts081-mgmt.cfg → management network100-storage.cfg → storage serversEach .cfg file contains simple IP hostname mappings (just like /etc/hosts):
172.16.5.10 ldap
172.16.100.10 nas1
✅ This modular approach makes it easy to version control, review, and expand.
Assumed Knowledge: that you already know how to create a GitHub repo.
.dns-configs/
└── dnsmasq/
└── hosts.d/
├── 005-critical-prod.cfg
├── 081-mgmt.cfg
├── 100-storage.cfg
└── XXX-*.cfg
ssh-keygen -t ed25519 -f ~/.ssh/id_github_ed25519
main
/etc/hosts.d/ via rsync
dnsmasq
⚠️ Warning: Validate configs before restart:
dnsmasq --test systemctl restart dnsmasq
DNS GitOps Script:
⚠️ Make sure you adjust these for your setup
- REPO="dns-configs"
- OWNER="github_org/username"
- GITHUB_DEPLOY_KEY="${HOME}/.ssh/id_github_ed25519"
The script handles:
/etc/hosts.d/
Git Clone Bash Script - git_clone_dns_configs_dnsmasq.sh
*/5 * * * * /root/git_clone_dnsmasq.sh
🔧 Automatic updates reduce errors and maintain consistency.
At this point, the DNS server can pull host updates from Git.
However, blindly syncing DNS records from Git is risky. A bad hosts entry, duplicate hostname, or broken dnsmasq config could break DNS resolution.
To reduce that risk, I added a GitHub Actions workflow that validates the dnsmasq configuration before changes are accepted.
| CI check | Reason |
|---|---|
| Runs inside AlmaLinux 10 | Matches the RHEL-style target environment |
Installs real dnsmasq service |
Validates against the actual service |
Copies dnsmasq.d and hosts.d
|
Tests realistic file layout |
| Validates host format | Catches malformed records |
| Detects duplicate hostnames | Prevents ambiguous DNS |
| Creates CI-safe config | Avoids binding to homelab-only IPs in CI |
Starts dnsmasq on 127.0.0.1:5353
|
Tests real resolution safely |
Uses dig tests |
Proves records actually resolve |
GitHub Actions CI Dnsmasq - dnsmasq-ci.yml
[Client Request]
|
v
[DNS (dnsmasq)]
|
┌─────┴─────┐
v v
[Local hosts] [Upstream DNS]
🖼 Shows decision flow for DNS resolution.
chmod 600 ~/.ssh/id_github_ed25519)rsync --delete — deletions in Git remove files on serverGitOps makes your homelab DNS:
You now have a fully automated, version-controlled DNS workflow for your homelab.