Skip to content

Recover from a failed wireguard server start - #434

Merged
george-angel merged 1 commit into
masterfrom
wiresteward-startup-recovery
Oct 21, 2026
Merged

george-angel merged 1 commit into
masterfrom
wiresteward-startup-recovery

Conversation

@george-angel

@george-angel george-angel commented Oct 21, 2026 •

Copy link
Copy Markdown
Member

wiresteward now recovers from a failed start instead of staying down until
someone logs in to the node.

A node that boots before its network is ready loses the race: oauth discovery
times out, the process exits, and its wireguard device stays behind.
wiresteward runs with --net=host, so wg0 belongs to the host rather than the
container, and the cleanup that would have removed it never ran. Every later
start hit file exists, and systemd gave up after 5 starts in 10s. The only way
back was deleting wg0 by hand.

What changed

  • Startup failures return an error instead of calling os.Exit, so the device
    and its nat rule always get cleaned up.
  • The metrics and lease servers report a port they cannot bind instead of
    exiting, which leaked the device the same way.
  • Signals are trapped before the device exists, so a stop during startup still
    cleans up.
  • A start that finds wg0 already there replaces it rather than refusing, which
    covers a crash or a SIGKILL.
  • The unit retries forever (StartLimitIntervalSec=0, RestartSec=15s), so a
    slow network costs time instead of the tunnel.

The alert in utilitywarehouse/system-alerts#276 asks for
state="active" == 0 instead of state="failed" == 1 for the same reason: after
this change the unit never reaches failed, so the old rule would go quiet on a
tunnel that is down.

govulncheck is red here for GO-2026-6809 in Go 1.26's crypto/x509; master
fails the same job. The Go version change is being done separately, so this PR
stays on the current toolchain.

@george-angel
george-angel force-pushed the wiresteward-startup-recovery branch 3 times, most recently from a92d18f to 87b2e84 Compare October 21, 2026 04:24
During boot the server can lose the race with the network: oauth discovery
fails and the process exits before it removes the wireguard device it created.
The device lives in the host network namespace rather than in the container, so
the leftover device and nat rule made every later start fail, and systemd's
default start rate limit turned that into a unit that stayed down until someone
logged in to the node.

Startup failures now return through Run so the deferred cleanup runs, and the
servers that run in their own goroutines report a listener they cannot bind
instead of exiting, which would leave the device behind the same way. Signals
are trapped before the device is created, so a stop request during startup still
cleans up. A start that finds its device already in place replaces it rather
than refusing, which covers a crash or a kill that skipped cleanup.

The unit keeps retrying without a start limit, so a late network costs time
instead of the tunnel.
@george-angel
george-angel force-pushed the wiresteward-startup-recovery branch from 87b2e84 to 2211f78 Compare October 21, 2026 06:54
@george-angel
george-angel merged commit f089bd7 into master Oct 21, 2026
9 of 10 checks passed
@george-angel
george-angel deleted the wiresteward-startup-recovery branch October 21, 2026 07:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants