When services like Nginx or NTPd attempt to start before DNS resolution is fully operational, you'll encounter errors like:
Aug 09 22:35:25 host.blah ntpd[3574]: restrict: ignoring line 21, address/host 'ntp.blah' unusable.
Aug 09 22:35:26 host.blah ntpd[3574]: restrict: ignoring line 23, address/host 'ntp.blah' unusable.
The common but incorrect approach is using WantedBy=pdns-recursor.service
, which doesn't actually guarantee DNS readiness.
Instead of WantedBy
, we need to use After=
and Requires=
directives in the [Unit] section. Here's a proper ntp.service example:
[Unit]
Description=Network Time Service
After=network.target pdns-recursor.service
Requires=pdns-recursor.service
Wants=network.target
[Service]
Type=simple
ExecStart=/usr/sbin/ntpd -n -u ntp:ntp -g
Restart=on-failure
[Install]
WantedBy=multi-user.target
For more complex cases, create a dedicated target that only activates after DNS verification:
# /etc/systemd/system/dns-ready.target
[Unit]
Description=DNS Resolution Available
After=pdns-recursor.service
Requires=pdns-recursor.service
# Verification script
OnFailure=network-online.target
Then modify your services to depend on this target:
[Unit]
After=dns-ready.target
Requires=dns-ready.target
For bulletproof startup, add a verification script that checks DNS resolution:
[Service]
ExecStartPre=/bin/bash -c 'until host example.com; do sleep 1; done'
ExecStart=/usr/sbin/nginx -g "daemon off;"
This will continuously attempt to resolve 'example.com' until successful.
For systems using systemd-networkd, leverage native network status tracking:
[Unit]
After=network-online.target
Wants=network-online.target
Enable network wait:
systemctl enable systemd-networkd-wait-online.service
When dealing with services like Nginx or NTPd that require functional DNS resolution, we often encounter startup failures during boot. The core issue stems from systemd starting these services before DNS becomes fully operational, especially when using local DNS resolvers like pdns-recursor.
The common solution of using WantedBy=pdns-recursor.service
in unit files often proves insufficient because:
[Unit]
WantedBy=pdns-recursor.service
This only establishes a weak dependency and doesn't guarantee DNS resolution capability at service startup.
Instead of WantedBy
, we should use After
and Requires
directives combined with a proper test for DNS functionality:
[Unit]
After=network-online.target pdns-recursor.service
Requires=network-online.target pdns-recursor.service
For more robust verification, we can create an ExecStartPre check:
[Service]
ExecStartPre=/bin/sh -c 'until host example.com; do sleep 1; done'
Or for a more sophisticated check:
[Service]
ExecStartPre=/usr/bin/systemd-run --property=After=network-online.target --property=Requires=network-online.target --property=Requires=pdns-recursor.service --wait /bin/true
Here's a complete working example for ntpd:
[Unit]
Description=Network Time Service
After=network-online.target pdns-recursor.service
Requires=network-online.target pdns-recursor.service
[Service]
Type=simple
ExecStartPre=/bin/sh -c 'until host pool.ntp.org; do echo "Waiting for DNS..."; sleep 1; done'
ExecStart=/usr/sbin/ntpd -n -u ntp:ntp -g
Restart=on-failure
[Install]
WantedBy=multi-user.target
For more complex scenarios, consider using path units to monitor DNS readiness:
[Unit]
Description=Monitor DNS resolution
[Path]
PathExists=/run/dns-ready
Unit=dns-ready.target
[Install]
WantedBy=multi-user.target
Then have your resolver create the trigger file when ready.
To verify your configuration works, use:
systemd-analyze verify ntp.service
systemd-analyze critical-chain ntp.service
journalctl -u ntp.service -b