Postope Tailscale service restart

I switched nearly all of my devices to NixOS and it is getting a bit tedious to update all of the systems. I came across colmena, which enabled me to update multiple devices via one command. I wanted to extend this concept by executing a colmena command using GitHub actions and connecting to the devices via Tailscale, but there is one problem: if Tailscale has an update, it restarts the service and cuts the connection!

I came across this thread, which says to use systemd.services.<name>.restartIfChanged and disable the restart completely. This would work, but I would like to have the service up-to-date too, therefore a restart is needed. Is there any way to postpone the restart for a certain amount of time?

I was also thinking of create a new process to trigger the restart at a fixed time daily, but maybe there is a more elegant way :slight_smile:

1 Like

I tried feeding deepseek with the same question and it came up with a pretty convincing piece of config:

{ config, pkgs, ... }:

{
  # Disable automatic restart of Tailscale on package update
  systemd.services.tailscaled.restartIfChanged = false;

  # Activation script to schedule delayed restart if Tailscale is updated
  system.activationScripts.delayedTailscaleRestart = let
    newTailscale = config.services.tailscale.package;
  in ''
    current_tailscale="$(readlink -f /run/current-system/sw/bin/tailscale 2>/dev/null || echo "")"
    new_tailscale="$(readlink -f ${newTailscale}/bin/tailscale)"
    if [ "$current_tailscale" != "$new_tailscale" ]; then
      echo "Tailscale updated. Scheduling restart in 10 minutes..."
      systemd-run --on-active=10m --unit=delayed-tailscale-restart systemctl restart tailscaled
    fi
  '';
}

I just applied it and will be testing it, when a new tailscale update drops :slight_smile:

Activation scripts are definitely not the way to do this. Activation is a critical bootup component and should only be used as a last resort. When something goes wrong with activation, it can be catastrophic to the system. A longterm goal among many NixOS maintainers is to one day deprecate custom activation scripts.

Furthermore, at bootup, /run/current-system won’t be populated yet, and systemd-run won’t be operable yet, so this is going to result in some funky error logs during bootup, but probably nothing catastrophic would happen.

You could do the same with a systemd timer unit that’s wanted by the sysinit-reactivation.target unit. That target gets started on switch, so a timer unit with OnActiveSec=10m would be started on switch, and 10 minutes later it would fire.

systemd.timers.restart-tailscale = {
  wantedBy = [ "sysinit-reactivation.target" ];
  timerConfig.OnActiveSec = "10m";
  # Put timer in stopped state after it elapses,
  # so it starts again next time.
  timerConfig.RemainAfterElapse = false;
};
systemd.services.restart-tailscale = {
  # no wantedBy
  # no RemainAfterExit either
  serviceConfig.Type = "oneshot";
  script = ''
    # determine if tailscale needs to restart and do it
    ...
  '';
};
1 Like