@@ -43,7 +43,7 @@ makeEnable config "myModules.tailscale" true {
4343
4444 serviceConfig = {
4545 Type = "oneshot" ;
46- RemainAfterExit = true ;
46+ RemainAfterExit = false ;
4747 } ;
4848
4949 script = ''
@@ -57,13 +57,29 @@ makeEnable config "myModules.tailscale" true {
5757 exit 0
5858 fi
5959
60- state="$(${ pkgs . tailscale } /bin/tailscale status --json 2>/dev/null | ${ pkgs . jq } /bin/jq -r '.BackendState // empty' || true)"
61- if [ "$state" = "Running" ]; then
60+ status_json="$(${ pkgs . tailscale } /bin/tailscale status --json 2>/dev/null || true)"
61+ state="$(printf '%s' "$status_json" | ${ pkgs . jq } /bin/jq -r '.BackendState // empty' 2>/dev/null || true)"
62+ key_expiry="$(printf '%s' "$status_json" | ${ pkgs . jq } /bin/jq -r '.Self.KeyExpiry // empty' 2>/dev/null || true)"
63+ key_expired=false
64+ if [ -n "$key_expiry" ]; then
65+ expiry_epoch="$(${ pkgs . coreutils } /bin/date -d "$key_expiry" +%s 2>/dev/null || true)"
66+ now_epoch="$(${ pkgs . coreutils } /bin/date +%s)"
67+ if [ -n "$expiry_epoch" ] && [ "$expiry_epoch" -le "$now_epoch" ]; then
68+ key_expired=true
69+ fi
70+ fi
71+
72+ if [ "$state" = "Running" ] && [ "$key_expired" = false ]; then
6273 exit 0
6374 fi
6475
65- # First-time (or post-logout) login.
76+ reauth_args=()
77+ if [ "$key_expired" = true ]; then
78+ reauth_args+=(--force-reauth)
79+ fi
80+
6681 if ! ${ pkgs . tailscale } /bin/tailscale up \
82+ "'' ${reauth_args[@]}" \
6783 --auth-key "file:$key_file" \
6884 --accept-dns=true \
6985 --hostname=${ lib . escapeShellArg config . networking . hostName } \
@@ -74,4 +90,14 @@ makeEnable config "myModules.tailscale" true {
7490 fi
7591 '' ;
7692 } ;
93+
94+ systemd . timers . tailscale-autoconnect = {
95+ description = "Periodically repair Tailscale authentication" ;
96+ wantedBy = [ "timers.target" ] ;
97+ timerConfig = {
98+ OnBootSec = "2m" ;
99+ OnUnitActiveSec = "30m" ;
100+ Persistent = true ;
101+ } ;
102+ } ;
77103}
0 commit comments