Tutorial: set up a local DHCP and DNS server with dnsmasq on Debian for development
Redes & Segurança · By Kevin Marcondes · Published on · Updated on · 9 min read
This tutorial walks you through configuring a local DHCP and DNS server using dnsmasq on Debian for a development environment. You will create a local zone, forward external queries, define a DHCP range, reserve IPs by MAC and validate everything with simple tests. Useful for teams that need predictable names and stable IPs in the lab.
Prerequisites and network plan
We will provision a Debian host as a DNS (forwarder + cache) and DHCP server for the development network. Never run two DHCP servers on the same segment. Disable the router's DHCP or isolate this service in a VLAN. Choose a local domain that won't conflict with others. Prefer subdomains of home.arpa (e.g., dev.home.arpa) or the .test suffix. Avoid .local.
Prerequisites:
- Recent Debian (11/12) with root or sudo access.
- A static IP for the server on the development subnet.
- A maintenance window to enable DHCP without affecting other hosts.
Define your network plan and keep the values below handy.
- Recent Debian with root/sudo
- Server fixed IP on the subnet
- Maintenance window to enable DHCP
| Item | Example | Notes |
|---|---|---|
| Network/subnet | 192.168.50.0/24 | Lab/dev subnet |
| Server IP (dnsmasq) | 192.168.50.2 | Host that will run DNS/DHCP |
| Gateway/router | 192.168.50.1 | Internet uplink |
| DHCP range | 192.168.50.100–192.168.50.150 | Size according to number of clients |
| Local domain | dev.home.arpa | Avoid .local; prefer home.arpa or .test |
| Upstream DNS | 1.1.1.1 and 8.8.8.8 | Public resolvers or your provider |
Step 1 — Install dnsmasq and utilities
Install dnsmasq and tools for DNS debugging. dnsmasq provides a lightweight DNS cache/forwarder and DHCP server, ideal for labs. After installation, the service starts with a basic configuration. We'll make adjustments in files under /etc/dnsmasq.d/.
If another service is already listening on port 53, stop it before proceeding (for example, a local systemd-resolved).
sudo apt update
sudo apt install -y dnsmasq dnsutils
# Verifique o status do serviço
systemctl status dnsmasq --no-pager
# (Opcional) Confira se a porta 53 está livre e usada pelo dnsmasq
ss -luntp | grep -E ':53 ' || true
Step 2 — Confirm static IP and default route
Ensure the server has a static IP on the lab subnet. A simple approach is to reserve the server's MAC on the router and fix the IP there. If this host's IP changes, clients may lose DNS and DHCP.
Confirm the server's current IP and default route before configuring dnsmasq.
ip -4 addr show | grep -E 'inet .* brd' | awk '{print $2, $NF}'
ip route | grep default
Step 3 — Configure local DNS and forwarding
Create an upstream resolvers file for dnsmasq and a configuration file for your local zone. We'll use dev.home.arpa as an example. Adjust addresses according to your network plan. The examples include some static records and a wildcard to make temporary subdomains easier in development.
In the end, dnsmasq will listen on the server IP, answer for the local zone, forward external queries to the defined resolvers and keep a cache.
# Defina DNS upstream usados pelo dnsmasq (não mexe no /etc/resolv.conf do sistema)
sudo tee /etc/dnsmasq.resolv.conf >/dev/null <<'EOF'
nameserver 1.1.1.1
nameserver 8.8.8.8
EOF
# Crie a configuração da zona local
sudo tee /etc/dnsmasq.d/dev.conf >/dev/null <<'EOF'
# Zona local
domain=dev.home.arpa
local=/dev.home.arpa/
expand-hosts
# Interface/IP de escuta (ajuste o IP do servidor)
listen-address=192.168.50.2,127.0.0.1
bind-interfaces
# Regras de resolução
domain-needed
bogus-priv
no-resolv
resolv-file=/etc/dnsmasq.resolv.conf
cache-size=10000
# Registros locais úteis (exemplos)
# Registros tipo A
host-record=registry.dev.home.arpa,192.168.50.10
address=/app.dev.home.arpa/192.168.50.20
# Wildcard para facilitar prévias por subdomínio (ex.: *.svc.dev.home.arpa)
address=/.dev.home.arpa/192.168.50.30
EOF
Step 4 — Enable basic DHCP and reservations
Enable DHCP for the defined range. The example includes default options for gateway, DNS and search domain. You can also reserve IPs by MAC for critical hosts like a database or CI runner.
Attention: when you start DHCP, all clients on the segment may receive addresses from this server. Run this within a maintenance window, with the old DHCP disabled or in an isolated VLAN.
# Acrescente as diretivas de DHCP ao mesmo arquivo
sudo tee -a /etc/dnsmasq.d/dev.conf >/dev/null <<'EOF'
# DHCP básico
# Faixa: 192.168.50.100–150, concessão de 12h
dhcp-range=192.168.50.100,192.168.50.150,255.255.255.0,12h
# Gateway padrão
dhcp-option=option:router,192.168.50.1
# Servidor(es) DNS oferecido(s) aos clientes (use o próprio servidor)
dhcp-option=option:dns-server,192.168.50.2
# Domínio de busca
dhcp-option=option:domain-search,dev.home.arpa
# (Opcional) Declare autoridade na sub-rede (use somente se este for o único DHCP)
# dhcp-authoritative
# (Opcional) Reservas por MAC (exemplos)
dhcp-host=AA:BB:CC:DD:EE:01,192.168.50.10,ci-runner,12h
dhcp-host=AA:BB:CC:DD:EE:02,192.168.50.20,db-dev,12h
EOF
Step 5 — Open ports and start the service
Open firewall ports for DNS (TCP/UDP 53) and DHCP (UDP 67). Then restart and enable dnsmasq at boot. Check logs to confirm it's listening on the correct interface and advertising the DHCP range.
If you use UFW, see the guide How to Set Up a Firewall on Ubuntu with UFW to review rules and policies.
- DNS ports: 53/TCP and 53/UDP
- DHCP port: 67/UDP
- Enable dnsmasq at boot and check logs
# Abrir portas no UFW (se em uso)
sudo ufw allow 53/udp
sudo ufw allow 53/tcp
sudo ufw allow 67/udp
# Reiniciar e habilitar o serviço
echo "Reiniciando dnsmasq..."
sudo systemctl restart dnsmasq
sudo systemctl enable dnsmasq
# Logs e checagens
journalctl -u dnsmasq -n 50 --no-pager
ss -luntp | grep -E ':53 |:67 ' || true
Step 6 — Practical DNS and DHCP tests
Test the local DNS directly on the server and from a client. Then validate DHCP by renewing a lease on a machine in the development network. On non-Linux clients, use the GUI to disconnect and reconnect to the network.
During tests, keep a terminal open with dnsmasq logs so you can observe DNS queries and IP leases in real time.
# Testar DNS no servidor (local)
dig +short registry.dev.home.arpa @127.0.0.1
dig +short app.dev.home.arpa @127.0.0.1
dig +time=1 +tries=1 debian.org @127.0.0.1 # Encaminhamento externo
# Em um cliente Linux da mesma sub-rede:
# 1) Configure para obter IP automaticamente (DHCP)
# 2) Renove o lease (pode desconectar/reconectar a interface)
sudo dhclient -r || true
sudo dhclient -v
# Confirme IP obtido e DNS aplicado
ip -4 a show
grep -E 'nameserver|search' /etc/resolv.conf || true
Troubleshooting common issues
DHCP conflict: if another DHCP is active on the segment, clients may receive addresses from different servers. Disable the router's DHCP or isolate the development network.
Port 53 in use: check which process is listening on port 53. Stop it or configure dnsmasq to listen only on the server IP (bind-interfaces + listen-address).
No external browsing: review the DHCP router option and dnsmasq's resolv-file. Confirm the server can reach the gateway and upstream DNS resolvers.
Local resolution failing: check the domain (dev.home.arpa), names and IPs in host-record/address entries. Clear client caches before retesting.
Harden the host: apply system hardening and monitor services. The VPS Linux Security Checklist helps review critical points.
- Disable conflicting DHCP on the router or isolate the VLAN
- Fix processes using port 53
- Review DHCP gateway/DNS options
- Clear caches and verify the local zone
- Harden and monitor the DNS/DHCP host
Advanced tips for development teams
Wildcard DNS speeds up previews and ephemeral environments. Combine it with a reverse proxy to route *.dev.home.arpa to internal services. See the comparison Traefik vs Nginx as a reverse proxy to choose the best fit for your stack.
Secure remote access to the lab by creating a VPN so the team can use the same internal DNS from outside the office. Follow the WireGuard road‑warrior on Debian guide for a step-by-step setup.
Strengthen the foundation: apply consistent hardening and firewall policies on the dnsmasq host. This reduces surprises during sprints and hard-to-debug incidents.
- Wildcard + reverse proxy for previews
- VPN for secure remote access to the lab
- Hardening and firewall on the DNS/DHCP host
Frequently asked questions
Can I use .local for the lab domain?
Avoid .local. That suffix is used by mDNS and can cause conflicts and slowdowns. Prefer reserved domains like home.arpa (e.g., dev.home.arpa) or .test. This keeps local resolution predictable and avoids interfering with mDNS discovery.
How do I avoid a conflict with my router's DHCP?
Run dnsmasq's DHCP only on an isolated network (VLAN/lab) or disable the router's DHCP before enabling dnsmasq. Running two DHCP servers on the same segment causes inconsistent leases and intermittent connectivity for clients.
Can I make reservations by hostname instead of MAC?
Reliable DHCP reservations use the MAC address. In dnsmasq use dhcp-host with the device MAC and desired IP. For names, combine the reservation with the hostname parameter in dhcp-host or add static DNS records in the local zone.
Can dnsmasq deliver PXE/TFTP for VM booting?
Yes. dnsmasq supports PXE/TFTP options (for example, dhcp-boot and tftp-root). Enable the integrated TFTP server and point to the boot file. Do this only on controlled networks, since clients might unintentionally load boot images.
How can I limit dnsmasq to a specific interface?
Use bind-interfaces and listen-address in the config file, pointing to the server's IP on the desired subnet. This ensures dnsmasq won't answer on other interfaces, reducing risks and avoiding conflicts in multi-network hosts.
Can I apply different DNS policies for different teams?
Create separate subnets or VLANs, each with its own dnsmasq and local zone, or run isolated instances of the service. This separation avoids side effects and allows team-specific rules, such as DHCP ranges and custom records.
Standardize your development lab DNS/DHCP?
If you want to speed up testing with predictable names, MAC reservations and wildcard subdomains, we can discuss your setup and next steps.
Talk about the development environmentSee also
- Tutorial: set up mTLS between Traefik and Docker Compose services using smallstep CA and automatic certificates — step by step
- Tutorial: integrate Sentry into your GitHub Actions deploy pipeline — automatic source map upload & issue creation (PHP & JavaScript)
- Configure retention and compression for Docker container logs with journald + logrotate + rsyslog on a low-disk VPS
- Tutorial: Configure GitHub Actions for integration tests with PostgreSQL in ephemeral containers and automatic migration rollback — a practical guide