Skip to content

fix(dashboard): detect dead tunnels as unhealthy#180

Merged
sleep3r merged 1 commit intomainfrom
fix/dashboard-tunnel-health
Apr 13, 2026
Merged

fix(dashboard): detect dead tunnels as unhealthy#180
sleep3r merged 1 commit intomainfrom
fix/dashboard-tunnel-health

Conversation

@sleep3r
Copy link
Copy Markdown
Owner

@sleep3r sleep3r commented Apr 13, 2026

Problem

The dashboard health check reported healthy: true for dead WireGuard tunnels. It only verified that an endpoint was configured and the link was UP — both are static kernel state that remain true even when the VPN server is completely unreachable.

This led to a false "healthy" indicator on the dashboard while the proxy was unable to reach any Telegram DC (all upstream connections stuck in SYN-SENT).

Root Cause

_detect_tunnel_interface() set active = True solely based on the presence of an endpoint field in awg show output. But endpoint is a static config value — it's always present regardless of whether the tunnel is actually passing traffic.

Fix

  • Added _parse_transfer_bytes() to parse WG transfer strings (5.69 KiB → bytes)
  • Added _has_valid_handshake() to check latest-handshake is not 0/none/idle
  • _detect_tunnel_interface() now requires a completed handshake before marking active = True
  • New handshake_ok field exposed in tunnel status
  • _routing_status() healthy check for tunnel mode now requires active and handshake_ok
  • Dead tunnels get a clear reason: endpoint configured, no handshake (VPN server unreachable)

Before / After

Scenario Before After
Dead VPN, no handshake, rx=0 healthy: true healthy: false
Working VPN, handshake OK, rx>0 healthy: true healthy: true
Interface down healthy: false healthy: false

Already deployed and verified on production.

The tunnel health check was reporting healthy=true for dead WireGuard
tunnels because it only checked if an endpoint was configured (static
config) and if the link was UP. It did not verify the tunnel was
actually passing traffic.

Added two helper functions:
- _parse_transfer_bytes: parses WG transfer strings (e.g. '5.69 KiB')
- _has_valid_handshake: checks latest-handshake is not 0/none/idle

_detect_tunnel_interface now requires a completed handshake (and
ideally rx > 0) before marking a tunnel as active. A new handshake_ok
field is exposed in the tunnel status dict.

_routing_status healthy check for tunnel mode now also requires
active=true and handshake_ok=true on the primary tunnel.

Before: dead tunnel with endpoint configured → healthy: true
After:  dead tunnel with no handshake/rx    → healthy: false
        with reason: 'endpoint configured, no handshake (VPN server unreachable)'
@sleep3r sleep3r merged commit b6e6b8c into main Apr 13, 2026
2 checks passed
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.

1 participant