Some services in Debian/Ubuntu need to start after the Tailscale service is not only started/active, but has fully come up (in so much that it passes network traffic, which can take 5-10 seconds after the service starts). This is crucial when binding services solely to the Tailscale interface such that they require it to be fully operational before binding can successfully complete. Some services like the Zabbix agent may initially fail but will retry and start successfully once Tailscale is fully operational, but other services like netatalk (used for Apple file sharing) will generally fail to start or bind and will not reattempt, forcing a manual intervention of restarting that service.
To account for this, a "ExecStartPost" within the Tailscale systemd config monitors when the host can successfully ping 100.100.100.100 (the "localhost" IP within Tailscale) such that other services that depend on Tailscale won't attempt to start until the ping is successful. From there, the dependent services (zabbix-agent2, netatalk, etc.) only need the "After" and "Requires" sections to have tailscaled.service listed.
Create the directory for each of the systemd service overrides : (supports multiple services)
DEPENDENT_SERVICES=(netatalk zabbix-agent2);
mkdir -p /etc/systemd/system/tailscaled.service.d;
for SERVICE in ${DEPENDENT_SERVICES[@]}; do
mkdir -p /etc/systemd/system/$SERVICE.service.d;
done;
Create the tailscaled override :
#DROP_IN=/etc/systemd/system/tailscaled.service.d/wait-for-tailnet-up.conf; ## isn't working
DROP_IN=/etc/systemd/system/tailscaled.service.d/override.conf;
rm $DROP_IN 2> /dev/null;
echo "[Service]" | tee -a $DROP_IN >/dev/null;
echo "ExecStartPost=/bin/bash -c '(while ! ping -c1 100.100.100.100 >/dev/null; do sleep 1; done);'" | tee -a $DROP_IN >/dev/null;
Create the dependent app overrides:
for SERVICE in ${DEPENDENT_SERVICES[@]}; do
#DROP_IN=/etc/systemd/system/$SERVICE.service.d/wait-for-tailscaled.conf; ## isn't working
DROP_IN=/etc/systemd/system/$SERVICE.service.d/override.conf;
rm $DROP_IN 2> /dev/null;
echo "[Unit]" | tee -a $DROP_IN >/dev/null;
echo "After=tailscaled.service" | tee -a $DROP_IN >/dev/null;
echo "Requires=tailscaled.service" | tee -a $DROP_IN >/dev/null;
done;
To verify that the config files were created, run :
(this creates a temporary override.conf
file which is a copy of the original all commented out with the override config within)
systemctl edit tailscaled ## --drop-in=wait-for-tailnet-up
systemctl edit netatalk ## --drop-in=wait-for-tailscaled
systemctl edit zabbix-agent2 ## --drop-in=wait-for-tailscaled
To have these changes take effect, run the command :
systemctl daemon-reload
By performing these steps, it should ensure that the service(s) start after the tailscaled service starts and also waits for Tailscale to be ready to handle network traffic.
- @shladek - idea to decouple the extra config from the installed one from package
Thank you for this suggestion! I have updated the guide in such a way that works but relies on
override.conf
when usingsystemctl edit tailscaled
with no options.For some reason, when I run
systemctl edit tailscaled --drop-in=wait-for-tailnet-up
, I getsystemctl: unrecognized option '--drop-in=wait-for-tailnet-up'
, so I worked around by implementing withoverride.conf
by usingsystemctl edit tailscaled
as is.Despite the file being named
override.conf
, it acts more as an appending operation, the same as a drop-in.