Project

General

Profile

Bug #16342 » install_tailscale_fix.sh

Tailscale_fix - Per Otto Opstad, 04/27/2026 06:59 AM

 
1
#!/bin/sh
2
# -----------------------------------------------------------------------------
3
# FishMon365 Tailscale Fix – Production Installer
4
# -----------------------------------------------------------------------------
5
#
6
# Author:      Per Otto Opstad
7
# Company:     ITVakta AS / FishMon365
8
# Website:     https://www.fishmon365.com
9
# Contact:     per@itvakta.no
10
#
11
# Created:     2026-04
12
# Version:     1.0
13
#
14
# Purpose:
15
#   Workaround for Tailscale instability on pfSense where auth-key is reused
16
#   on every service start, causing nodes to enter a broken state
17
#   (e.g. "invalid key", "logged out", "NoState").
18
#
19
#   This installer:
20
#     - Deploys a watchdog script for automatic recovery
21
#     - Disables repeated use of auth-key in pfSense rc script
22
#     - Ensures persistent and self-healing Tailscale operation
23
#
24
# Usage:
25
#   cd /tmp && rm -f install_tailscale_fix.sh && \
26
#   fetch -qo install_tailscale_fix.sh \
27
#   https://your.domain.xxx/tailscale/install_tailscale_fix.sh && \
28
#   chmod 700 install_tailscale_fix.sh && \
29
#   sh ./install_tailscale_fix.sh
30
#
31
# Notes:
32
#   - Safe to run multiple times (idempotent)
33
#   - Designed specifically for pfSense environments
34
#   - Requires Tailscale package to be installed
35
#
36
# Changelog:
37
#   1.0 (2026-04)
38
#     - Initial production version
39
#     - Added watchdog-based recovery
40
#     - Added automatic rc-script patching
41
#
42
# -----------------------------------------------------------------------------
43
#
44
set -eu
45

    
46
# === Variabler ===
47
WATCHDOG_SCRIPT="/root/tailscale_watchdog.sh"
48
RCFILE="/usr/local/etc/rc.d/pfsense_tailscaled"
49
CRON_SCHEDULE="*/5 * * * *"
50
CRON_LINE="${CRON_SCHEDULE} ${WATCHDOG_SCRIPT}"
51
TMP_CRON="/tmp/tailscale_watchdog.cron.$$"
52
LOCKFILE="/tmp/tailscale_watchdog.lock"
53

    
54
cleanup() {
55
  rm -f "$TMP_CRON" 2>/dev/null || true
56
}
57
trap cleanup EXIT INT TERM
58

    
59
require_root() {
60
  if [ "$(id -u)" -ne 0 ]; then
61
    echo "ERROR: Dette skriptet må kjøres som root." >&2
62
    exit 1
63
  fi
64
}
65

    
66
check_environment() {
67
  echo "[1/6] Sjekker miljø..."
68

    
69
  if [ ! -f "$RCFILE" ]; then
70
    echo "ERROR: Fant ikke rc-script: $RCFILE" >&2
71
    echo "Er dette riktig pfSense-boks med Tailscale installert?" >&2
72
    exit 1
73
  fi
74

    
75
  if [ ! -x /usr/local/bin/tailscale ]; then
76
    echo "ERROR: Fant ikke /usr/local/bin/tailscale" >&2
77
    echo "Sørg for at Tailscale-pakken er installert først." >&2
78
    exit 1
79
  fi
80

    
81
  if [ ! -x /usr/sbin/service ]; then
82
    echo "ERROR: Fant ikke /usr/sbin/service" >&2
83
    exit 1
84
  fi
85

    
86
  if ! command -v crontab >/dev/null 2>&1; then
87
    echo "ERROR: Fant ikke crontab-kommandoen." >&2
88
    exit 1
89
  fi
90
}
91

    
92
write_watchdog_script() {
93
  echo "[2/6] Oppretter/oppdaterer watchdog-script..."
94

    
95
  cat > "$WATCHDOG_SCRIPT" <<'EOF'
96
#!/bin/sh
97

    
98
LOCKFILE="/tmp/tailscale_watchdog.lock"
99
RCFILE="/usr/local/etc/rc.d/pfsense_tailscaled"
100
TS="/usr/local/bin/tailscale"
101
SERVICE="/usr/sbin/service"
102
RC_SERVICE="pfsense_tailscaled"
103
LOGTAG="tailscale-watchdog"
104

    
105
log() {
106
  logger -t "$LOGTAG" "$1"
107
}
108

    
109
cleanup() {
110
  rm -f "$LOCKFILE"
111
}
112
trap cleanup EXIT INT TERM
113

    
114
[ -e "$LOCKFILE" ] && exit 0
115
touch "$LOCKFILE"
116

    
117
get_status() {
118
  "$TS" status 2>&1 || true
119
}
120

    
121
is_known_error() {
122
  echo "$1" | grep -Eiq 'logged out|invalid key|API key does not exist|NoState'
123
}
124

    
125
is_healthy() {
126
  "$TS" ip -4 >/dev/null 2>&1
127
}
128

    
129
patch_rcfile_if_needed() {
130
  if grep -q '^pfsense_tailscaled_up_flags="--auth-key=' "$RCFILE"; then
131
    cp "$RCFILE" "${RCFILE}.bak_watchdog" 2>/dev/null || true
132
    sed -i '' 's/^pfsense_tailscaled_up_flags="--auth-key=/#pfsense_tailscaled_up_flags="--auth-key=/' "$RCFILE"
133
    log "Patched rc file (disabled auth-key)"
134
  fi
135
}
136

    
137
# Enforce patch every run
138
patch_rcfile_if_needed
139

    
140
STATUS="$(get_status)"
141

    
142
if is_healthy && ! is_known_error "$STATUS"; then
143
  exit 0
144
fi
145

    
146
if ! is_known_error "$STATUS"; then
147
  exit 0
148
fi
149

    
150
log "Detected known Tailscale error"
151
log "Restarting $RC_SERVICE"
152
$SERVICE "$RC_SERVICE" restart >/dev/null 2>&1
153
sleep 15
154

    
155
STATUS="$(get_status)"
156

    
157
if is_healthy && ! is_known_error "$STATUS"; then
158
  log "Recovered after restart"
159
  exit 0
160
fi
161

    
162
log "Still failing after restart"
163
exit 1
164
EOF
165

    
166
  chmod 700 "$WATCHDOG_SCRIPT"
167
  chown root:wheel "$WATCHDOG_SCRIPT" 2>/dev/null || true
168
}
169

    
170
install_or_update_cron() {
171
  echo "[3/6] Oppretter/oppdaterer cron..."
172

    
173
  {
174
    crontab -l 2>/dev/null | grep -v "$WATCHDOG_SCRIPT" || true
175
    echo "$CRON_LINE"
176
  } > "$TMP_CRON"
177

    
178
  crontab "$TMP_CRON"
179
}
180

    
181
run_fix_now() {
182
  echo "[4/6] Kjører fix nå..."
183
  rm -f "$LOCKFILE" 2>/dev/null || true
184
  "$WATCHDOG_SCRIPT" || true
185
}
186

    
187
verify_installation() {
188
  echo "[5/6] Verifiserer..."
189

    
190
  CRON_MATCH="$(crontab -l 2>/dev/null | grep -F "$WATCHDOG_SCRIPT" || true)"
191

    
192
  if [ -n "$CRON_MATCH" ]; then
193
    echo "OK: Cron-linje funnet:"
194
    echo "  $CRON_MATCH"
195
  else
196
    echo "WARNING: Fant ikke cron-linje for watchdog."
197
  fi
198

    
199
  echo
200
  echo "Auth-key linjer i rc-script:"
201
  grep -n 'auth-key' "$RCFILE" || true
202

    
203
  echo
204
  echo "Tailscale status (kort):"
205
  if /usr/local/bin/tailscale ip -4 >/dev/null 2>&1; then
206
    TSIP="$(/usr/local/bin/tailscale ip -4 | head -n 1)"
207
    echo "  IPv4: $TSIP"
208
  else
209
    echo "  IPv4: utilgjengelig"
210
  fi
211
  /usr/local/bin/tailscale status 2>/dev/null | head -n 5 || true
212

    
213
  echo
214
  echo "Siste watchdog-linjer i system.log:"
215
  grep 'tailscale-watchdog' /var/log/system.log 2>/dev/null | tail -n 10 || true
216
}
217

    
218
print_summary() {
219
  echo "--------------------------------------"
220
  echo "Installasjon fullført"
221
  echo "Watchdog:     $WATCHDOG_SCRIPT"
222
  echo "RC-script:    $RCFILE"
223
  echo "Cron:         $CRON_SCHEDULE"
224
  echo
225
  echo "Nyttige kommandoer:"
226
  echo "  Sjekk cron:      crontab -l"
227
  echo "  Kjør manuelt:    $WATCHDOG_SCRIPT"
228
  echo "  Sjekk status:    tailscale status"
229
  echo "  Sjekk IP:        tailscale ip -4"
230
  echo "  Sjekk logg:      grep tailscale-watchdog /var/log/system.log | tail -n 50"
231
  echo "  Restart TS:      service pfsense_tailscaled restart"
232
  echo "  Sjekk auth-key:  grep -n auth-key $RCFILE"
233
}
234

    
235
echo "=== FishMon365 Tailscale Fix Installer ==="
236

    
237
require_root
238
check_environment
239
write_watchdog_script
240
install_or_update_cron
241
run_fix_now
242
verify_installation
243
print_summary
(4-4/4)