diff --git a/nixos/modules/services/networking/tailscale.nix b/nixos/modules/services/networking/tailscale.nix index 731b5c2138f7..0b6e110d2caa 100644 --- a/nixos/modules/services/networking/tailscale.nix +++ b/nixos/modules/services/networking/tailscale.nix @@ -84,6 +84,8 @@ in description = '' A file containing the auth key. Tailscale will be automatically started if provided. + + Services that bind to Tailscale IPs should order using {option}`systemd.services..after` `tailscaled-autoconnect.service`. ''; }; @@ -116,7 +118,7 @@ in extraUpFlags = mkOption { description = '' - Extra flags to pass to {command}`tailscale up`. Only applied if `authKeyFile` is specified."; + Extra flags to pass to {command}`tailscale up`. Only applied if {option}`services.tailscale.authKeyFile` is specified. ''; type = types.listOf types.str; default = [ ]; @@ -183,12 +185,15 @@ in wants = [ "tailscaled.service" ]; wantedBy = [ "multi-user.target" ]; serviceConfig = { - Type = "oneshot"; + Type = "notify"; }; - # https://github.com/tailscale/tailscale/blob/v1.72.1/ipn/backend.go#L24-L32 + path = [ + cfg.package + pkgs.jq + ]; + enableStrictShellChecks = true; script = let - statusCommand = "${lib.getExe cfg.package} status --json --peers=false | ${lib.getExe pkgs.jq} -r '.BackendState'"; paramToString = v: if (builtins.isBool v) then (lib.boolToString v) else (toString v); params = lib.pipe cfg.authKeyParameters [ (lib.filterAttrs (_: v: v != null)) @@ -197,14 +202,35 @@ in (params: if params != "" then "?${params}" else "") ]; in + # bash '' - while [[ "$(${statusCommand})" == "NoState" ]]; do - sleep 0.5 + getState() { + tailscale status --json --peers=false | jq -r '.BackendState' + } + + lastState="" + while state="$(getState)"; do + if [[ "$state" != "$lastState" ]]; then + # https://github.com/tailscale/tailscale/blob/v1.72.1/ipn/backend.go#L24-L32 + case "$state" in + NeedsLogin) + echo "Server needs authentication, sending auth key" + tailscale up --auth-key "$(cat ${cfg.authKeyFile})${params}" ${escapeShellArgs cfg.extraUpFlags} + ;; + Running) + echo "Tailscale is running" + systemd-notify --ready + exit 0 + ;; + *) + echo "Waiting for Tailscale State = Running or systemd timeout" + ;; + esac + fi + echo "State = $state" + lastState="$state" + sleep .5 done - status=$(${statusCommand}) - if [[ "$status" == "NeedsLogin" || "$status" == "NeedsMachineAuth" ]]; then - ${lib.getExe cfg.package} up --auth-key "$(cat ${cfg.authKeyFile})${params}" ${escapeShellArgs cfg.extraUpFlags} - fi ''; };