On my NixOS servers, I set up services (here, nginx) listening on the tailscale IP. However, during deployment the service sometimes fails to start, despite specifying the service to start once tailscale is online:
systemd.services.nginx = {
after = [ "tailscaled.service" ];
requires = [ "tailscaled.service" ];
};
For instance:
déc. 21 14:30:52 garmr nginx-pre-start[347563]: nginx: [emerg] bind() to 100.65.1.5:443 failed (99: Cannot assign requested address)
This suggests the service is considered active by systemd before the interface is ready. A GitHub Issue confirms this behaviour: Tailscaled tells systemd that it is ready before its ip address is bindable #11504, where the comments suggest to use approaches relying on a sleep as a workaround. Alternatively, we can rely on the systemd-networkd-wait-online.service service. By providing an interface name using -i interface_name it will wait for the specified interface to be configured by systemd-networkd and online. This is a oneshot service, meaning that once the main program exits, the service will be considered as active. Hence, it can be used as a dependency for units requiring specific interfaces to be online.
This can be done declaratively using the following configuration for the IPv4 interface named tailscale0 as follows:
systemd.services.tailscale-online = {
description = "Wait for Tailscale to have an IPv4 address";
requires = [ "systemd-networkd.service" ];
after = [ "systemd-networkd.service" ];
serviceConfig = {
Type = "oneshot";
RemainAfterExit = true;
ExecStart = "${pkgs.systemd}/lib/systemd/systemd-networkd-wait-online -i tailscale0 -4";
};
};
It creates a custom service named tailscale-online, started once systemd-networkd is up. The service is declared as a oneshot and RemainAfterExit is set to true, it remains in the “active” state after systemd-networkd-wait-online exits. Now, the nginx service can depend on tailscale-online as follows:
systemd.services.nginx = {
after = [ "tailscale-online.service" ];
requires = [ "tailscale-online.service" ];
};
Banner image: John Singer Sargent (1878). Capri Girl on a Rooftop. Crystal Bridges Museum of American Art, Bentonville, Arkansas.