iToverDose/Software· 1 JULY 2026 · 00:05

Automate Homelab DNS with GitOps and dnsmasq

A DNS misconfiguration once crashed an entire homelab. Learn how GitOps turns host management into a safe, automated workflow using dnsmasq, GitHub, and cronjobs.

DEV Community5 min read0 Comments

A single typo in a hosts file once cascaded into a full-blown outage across a homelab. The Proxmox cluster lost node resolution, Ceph storage vanished, and every VM ground to a halt. The root cause? Manual DNS edits. That failure sparked a shift toward GitOps for DNS—a version-controlled, automated approach that prevents human error while keeping the network running smoothly.

In this guide, you’ll set up a GitOps-style DNS system using dnsmasq, GitHub, Bash scripts, and cronjobs. Every host entry lives in a repository, changes are tracked, and updates roll out automatically. Security is built in with deploy keys, and optional CI validation ensures clean, conflict-free configurations before they reach production.

Why GitOps is a game-changer for homelab DNS

GitOps transforms DNS from a fragile manual process into a resilient, auditable system. Instead of editing /etc/hosts directly or relying on ad-hoc notes, every hostname change is committed to a Git repository. This creates a single source of truth, lets you roll back mistakes with a single command, and automates deployment so your lab never suffers from DNS drift again.

Consider a typical homelab scenario: you add a new LXC container, assign it an IP, and update DNS. Without version control, typos slip through. With GitOps, the change is reviewed, tested in CI, and only pushed when validated—eliminating cascading failures from misconfigured hostnames.

Key advantages include:

  • Automated propagation – Changes in Git trigger immediate updates to dnsmasq
  • Full audit trail – Every edit is timestamped and traceable through commit history
  • Modular organization – Split hosts into separate .cfg files by function or environment
  • Security-first access – Deploy keys restrict repository access to only the DNS server
  • CI-based validation – Catch malformed records, duplicates, and syntax errors before they go live

Step-by-step: Install and configure dnsmasq for GitOps

Start by installing dnsmasq and Git on your DNS server. The process differs slightly between Linux distributions, but the core setup remains the same.

On RHEL-based systems (RHEL, CentOS, AlmaLinux):

sudo yum install -y dnsmasq git

On Debian-based systems (Ubuntu, Debian):

sudo apt install -y dnsmasq git

Next, configure dnsmasq to read host files from a dedicated directory. Create a configuration file at /etc/dnsmasq.d/000-base.conf with these essential settings:

# Bind to a specific network interface to avoid exposing DNS on all interfaces
domain=safesploit.com
expand-hosts
log-queries
no-hosts
addn-hosts=/etc/hosts.d
listen-address=172.16.5.27

⚠️ Always specify a listen-address. Binding to 0.0.0.0 exposes DNS to unintended networks and can cause security issues. Test the configuration with:

dnsmasq --test

Once validated, enable and start the service:

sudo systemctl enable dnsmasq
sudo systemctl start dnsmasq

Confirm it’s working by querying a hostname:

dig @172.16.5.27 ldap.safesploit.com +short

You should see the IP address you configured. If not, check logs with journalctl -u dnsmasq and verify the file paths and permissions.

Organizing hostnames with modular .cfg files

Instead of dumping all hosts into a single /etc/hosts file, split them into modular .cfg files inside /etc/hosts.d/. This structure makes it easier to manage, review, and restrict changes by team or function.

Create the directory and a set of template files:

sudo mkdir -p /etc/hosts.d
sudo touch /etc/hosts.d/005-critical-prod.cfg
sudo touch /etc/hosts.d/081-mgmt.cfg
sudo touch /etc/hosts.d/100-storage.cfg

Each file follows the standard hosts format: an IP address followed by one or more hostnames. For example:

172.16.5.10 ldap ldap.safesploit.com
172.16.100.10 nas1 nas1.safesploit.com media-nas

Naming conventions help with sorting and filtering. Use prefixes like 005- for critical production hosts, 081- for management networks, and 100- for storage tiers. This makes it easy to see the purpose of each file at a glance and keeps the directory clean as it grows.

Setting up the GitOps workflow: repository, keys, and automation

The heart of the GitOps approach is the repository. It stores the entire DNS configuration, including all .cfg files, and serves as the central hub for changes.

Start by creating a GitHub repository named something like dns-configs. The structure should mirror your server’s /etc/hosts.d/ directory:

dns-configs/
└── dnsmasq/
    └── hosts.d/
        ├── 005-critical-prod.cfg
        ├── 081-mgmt.cfg
        └── 100-storage.cfg

To allow the DNS server to pull updates securely, generate an SSH deploy key:

ssh-keygen -t ed25519 -f ~/.ssh/id_github_ed25519

Add the public key (id_github_ed25519.pub) to the repository’s Deploy Keys section in GitHub. Restrict access to read-only to prevent accidental pushes from the DNS server.

With the repository in place, create a Bash script to handle the synchronization. The script should:

  • Clone the repository using the deploy key
  • Compare the latest commit hash with the last applied hash
  • Sync the hosts.d/ directory to /etc/hosts.d/
  • Restart dnsmasq
  • Log the change and commit hash for audit purposes

Here’s a concise version of such a script:

#!/bin/bash
REPO="git@github.com:github_org/dns-configs.git"
TARGET_DIR="/etc/hosts.d"
LOG_FILE="/var/log/dns-gitops-sync.log"
LAST_COMMIT_FILE="/var/run/dns-last-commit"

# Clone repo (or pull if already cloned)
if [ -f "$LAST_COMMIT_FILE" ]; then
  git --git-dir=/tmp/dns-configs/.git --work-tree=/tmp/dns-configs pull >/dev/null 2>&1
else
  git clone "$REPO" /tmp/dns-configs >/dev/null 2>&1
fi

# Get latest commit hash
CURRENT_COMMIT=$(git --git-dir=/tmp/dns-configs/.git rev-parse HEAD)
PREV_COMMIT=$(cat "$LAST_COMMIT_FILE" 2>/dev/null || echo "")

# Only proceed if there’s a new commit
if [ "$CURRENT_COMMIT" != "$PREV_COMMIT" ]; then
  # Sync files
  rsync -a --delete /tmp/dns-configs/dnsmasq/hosts.d/ "$TARGET_DIR/"
  
  # Restart dnsmasq
  systemctl restart dnsmasq
  
  # Log the change
  echo "$(date) - Applied commit $CURRENT_COMMIT" >> "$LOG_FILE"
  echo "$CURRENT_COMMIT" > "$LAST_COMMIT_FILE"
fi

Schedule this script to run periodically using cron. A five-minute interval balances responsiveness with stability:

*/5 * * * * /root/git_clone_dnsmasq.sh

Optional: Validate configurations with GitHub Actions CI

While automation ensures speed, validation ensures safety. A bad hosts entry—like a duplicate hostname or malformed IP—can break DNS resolution for your entire homelab. GitHub Actions CI can catch these issues before they reach production.

The CI workflow runs in a clean AlmaLinux container that mirrors your DNS server’s environment. It performs the following checks:

  • Installs dnsmasq from the official package
  • Copies the Git repository’s dnsmasq.d and hosts.d files into the container
  • Validates the configuration using dnsmasq --test
  • Scans for duplicate hostnames and malformed entries
  • Simulates DNS resolution using dig against a test port (5353) to ensure records are resolvable

If any check fails, the workflow blocks the merge, preventing faulty configurations from being pushed. This safety net is especially useful in teams or shared homelabs where multiple people contribute to DNS.

With GitOps, dnsmasq, and CI validation in place, your homelab DNS becomes predictable, secure, and resilient—freeing you to focus on what matters most instead of firefighting DNS outages.

AI summary

Transform homelab DNS with GitOps: automate dnsmasq host updates using GitHub, Bash scripts, and cronjobs for error-free, version-controlled networking.

Comments

00
LEAVE A COMMENT
ID #LYQBQY

0 / 1200 CHARACTERS

Human check

6 + 7 = ?

Will appear after editor review

Moderation · Spam protection active

No approved comments yet. Be first.