Summary
roles/infra/templates/dns/dnsmasq.conf ships bind-interfaces together with listen-address=127.0.0.1,{{ inventory_hostname }}.
When the node address lives on an interface that is not up yet at boot (an overlay/VPN interface such as WireGuard, Tailscale or ZeroTier, or a VIP managed by vip-manager), dnsmasq cannot bind, retries, and gives up permanently — taking the internal *.pigsty DNS down until someone restarts it by hand.
Switching to bind-dynamic fixes it, and dnsmasq itself recommends that option.
Environment
|
|
| Pigsty |
v4.4.0 (still present on main) |
| OS |
Ubuntu 24.04 LTS |
| dnsmasq |
2.90 |
| systemd |
255 |
| Node address |
on an interface brought up after basic.target |
Root cause
bind-interfaces makes dnsmasq bind each configured address explicitly at startup, which requires every interface to already exist. The generated config is:
listen-address=127.0.0.1,10.0.0.1 # 10.0.0.1 lives on a late-arriving interface
bind-interfaces
At boot that interface is not up yet, so:
dnsmasq: failed to create listening socket for 10.0.0.1: Cannot assign requested address
dnsmasq: FAILED to start up
systemd: dnsmasq.service: Scheduled restart job, restart counter is at 5.
systemd: dnsmasq.service: Start request repeated too quickly.
dnsmasq warns about this configuration itself:
dnsmasq: LOUD WARNING: use --bind-dynamic rather than --bind-interfaces to avoid DNS amplification
Why a drop-in in /etc/dnsmasq.d/ cannot fix it
bind-interfaces and bind-dynamic are mutually exclusive. A drop-in adding bind-dynamic conflicts with the bind-interfaces already present in the main config file, so the only possible fix is in the template itself — which ./infra.yml -t dns regenerates on every run.
Suggested fix
- bind-interfaces
+ bind-dynamic
bind-dynamic attaches to interfaces as they appear, and keeps the same anti-amplification property as bind-interfaces (it does not answer on addresses it was not configured for). libvirt adopted bind-dynamic for exactly this class of interface-timing issue.
Verification after the change
systemctl restart dnsmasq
journalctl -u dnsmasq -b | grep -c "LOUD WARNING" # -> 0
getent hosts <node-name> i.pigsty # resolves
# and after a full reboot:
systemctl show dnsmasq -p NRestarts --value # -> 0 (no failed start, no retry)
Impact
Any deployment where the node address is not on a physical interface present at boot: overlay networks, VIPs, or vip-manager setups. On a static datacenter network the current default is harmless — which is probably why this went unnoticed.
References
dnsmasq(8) — --bind-dynamic vs --bind-interfaces
- libvirt switched to
bind-dynamic for the same interface-timing problem
Summary
roles/infra/templates/dns/dnsmasq.confshipsbind-interfacestogether withlisten-address=127.0.0.1,{{ inventory_hostname }}.When the node address lives on an interface that is not up yet at boot (an overlay/VPN interface such as WireGuard, Tailscale or ZeroTier, or a VIP managed by
vip-manager), dnsmasq cannot bind, retries, and gives up permanently — taking the internal*.pigstyDNS down until someone restarts it by hand.Switching to
bind-dynamicfixes it, and dnsmasq itself recommends that option.Environment
main)basic.targetRoot cause
bind-interfacesmakes dnsmasq bind each configured address explicitly at startup, which requires every interface to already exist. The generated config is:At boot that interface is not up yet, so:
dnsmasq warns about this configuration itself:
Why a drop-in in /etc/dnsmasq.d/ cannot fix it
bind-interfacesandbind-dynamicare mutually exclusive. A drop-in addingbind-dynamicconflicts with thebind-interfacesalready present in the main config file, so the only possible fix is in the template itself — which./infra.yml -t dnsregenerates on every run.Suggested fix
bind-dynamicattaches to interfaces as they appear, and keeps the same anti-amplification property asbind-interfaces(it does not answer on addresses it was not configured for). libvirt adoptedbind-dynamicfor exactly this class of interface-timing issue.Verification after the change
Impact
Any deployment where the node address is not on a physical interface present at boot: overlay networks, VIPs, or
vip-managersetups. On a static datacenter network the current default is harmless — which is probably why this went unnoticed.References
dnsmasq(8)—--bind-dynamicvs--bind-interfacesbind-dynamicfor the same interface-timing problem