DNS Server reports "started successfully" and systemd shows the service healthy when all DNS endpoint binds have failed
Hello,
Today I stumbled across a bit of a weird error. I appreciate that I'm reporting this against v14.3, but if the architecture is the same for the 15.x branch, this might benefit from a look. A couple of bits of relevant context for what follows:-
I wanted to run a "UAT" upgrade from 14.3 to 15.4, so I just created a pair of clean installations [Primary/Secondary] with the intent of giving them test configurations and then running the update process. I sat down to do the setup this afternoon and decided to start with a "sudo apt-get update"/"sudo apt-get upgrade" on each host. This failed - and it turns out that it failed because I had Technitium configured incorrectly.
I've now fixed that error - but in the process of working through that with Claude Opus, we spotted another possibly significant issue with the configuration of the systemd service files for the DNS. When we got to the end of the triage process and tested a working fix, I asked Claude to draft up an Issue Report - that's what you'll find below.
I think Claude's report is likely a lot more direct than anything I could produce!
Version: 14.3.0.0 Platform: Raspberry Pi 4B (arm64), Raspberry Pi OS / Debian trixie Install method: official Linux installer script
Summary
When DNS Server Local End Points is configured with a specific IP address that is not yet present on an interface at service start, the UDP and TCP binds for port 53 both fail. The failure is logged, but the server then logs DNS Server was started successfully. and continues running. systemd reports the unit as active (running).
The result is a DNS server that is up, healthy by every normal check, and serving nothing at all — indefinitely, and across reboots.
Environment / configuration
The host uses a virtual IP for the DNS service, configured as a secondary address on eth0, so that the service can be moved between hosts without reconfiguring clients:
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500
inet 172.16.120.1/16 brd 172.16.255.255 scope global noprefixroute eth0
inet 172.16.220.1/16 brd 172.16.255.255 scope global secondary noprefixroute eth0DNS Server Local End Points is set to 172.16.220.1:53.
Steps to reproduce
- Configure a secondary IPv4 address on an interface, managed by NetworkManager.
- Set DNS Server Local End Points to that secondary address.
- Reboot.
Actual behaviour
From /etc/dns/logs/:
[2026-09-15 14:31:29 UTC] [[::]:5380] [HTTP] Web Service was bound successfully.
[2026-09-15 14:31:34 UTC] [172.16.220.1:53] [UDP] DNS Server failed to bind.
System.Net.Sockets.SocketException (99): Cannot assign requested address
at System.Net.Sockets.Socket.DoBind(EndPoint endPointSnapshot, SocketAddress socketAddress)
at System.Net.Sockets.Socket.Bind(EndPoint localEP)
at DnsServerCore.Dns.DnsServer.StartAsync(Boolean throwIfBindFails) in DnsServerCore/Dns/DnsServer.cs:line 6172
[2026-09-15 14:31:34 UTC] [172.16.220.1:53] [TCP] DNS Server failed to bind.
System.Net.Sockets.SocketException (99): Cannot assign requested address
...DnsServerCore/Dns/DnsServer.cs:line 6248
[2026-09-15 14:31:34 UTC] DNS Server (v14.3.0.0) was started successfully.systemctl status dns.service afterwards:
Active: active (running) since Tue 2026-09-15 15:31:27 BST
Sep 15 15:31:34 abbott dns-server[635]: Technitium DNS Server was started successfully.ss -lntup | grep ':53' returns nothing for the DNS server. The address is present on the interface by the time the system is up — only the bind attempt was too early. Nothing retries it, so the server stays in this state until manually restarted.
The bind is not a race that is sometimes won: the shipped dns.service unit has no After= or Wants= ordering with respect to the network, so it starts before addresses are configured on every boot.
Why this is easy to miss
Three things combine to hide it:
- The server logs
started successfullyimmediately after logging that every DNS endpoint failed to bind. - systemd shows the unit as healthy, because the process does not exit — so
Restart=alwaysin the shipped unit never fires. - The web service behaves differently from the DNS service: when its configured bind fails it falls back to the default
[::]:5380, so the admin console remains reachable and the server looks fine from the UI.
The presenting symptom was Temporary failure resolving from apt-get update on the host itself, which points a user toward client-side DNS configuration rather than toward the server.
Expected behaviour
Any of the following would be a significant improvement:
- Exit non-zero when all configured DNS endpoints fail to bind. The shipped unit already has
Restart=alwaysandRestartSec=10, so the service would recover automatically once the address appears, with no user action required. This looks like the smallest change with the largest benefit. - Retry failed endpoint binds periodically in the background, rather than attempting once at startup only.
- Do not log
started successfullywhen no DNS endpoint bound, and surface a persistent warning on the dashboard while any configured endpoint is unbound. - Add
After=network-online.target/Wants=network-online.targetto the shipped unit file. Worth doing, though on its own it is not sufficient — that target can be reached before a secondary address has been attached to an interface.
Current workaround
A systemd drop-in that waits for the address before starting the service:
# /etc/systemd/system/dns.service.d/override.conf
[Unit]
After=network-online.target
Wants=network-online.target
[Service]
ExecStartPre=/usr/bin/timeout 30 /bin/bash -c 'until ip -4 -o addr show | grep -q "inet 172.16.220.1/"; do sleep 1; done'Source: TechnitiumSoftware/DnsServer