fix(vpn): sync WireGuard server key on startup; fix DNS zone cell_name/SOA; fix peer status UI

- API key store was out of sync with wg0.conf: get_keys() generated a random
  phantom key instead of reading the actual WireGuard server key, so all peer
  configs had the wrong PublicKey and could never handshake. Fixed by writing
  correct raw-bytes key files at deploy time and adding _sync_wg_keys() to API
  startup so the store auto-syncs from wg0.conf on every restart.

- apply_domain() fell back silently when zone file had no $ORIGIN directive;
  now also parses the SOA MNAME as the old-domain fallback.

- apply_cell_name() only replaced the hostname if old_name matched literally
  in the zone file; now auto-detects the actual hostname (non-service A record)
  so a stale zone (mycell vs dev) is corrected on next config apply.

- DNS zone file corrected: SOA pic.ngo. admin.pic.ngo., mycell → dev.

- WireGuard UI: add 30s auto-poll for peer statuses; fix "peers currently
  connected" counter to show online/total instead of total count.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-01 08:05:45 -04:00
parent 5d0238ff3c
commit f3118ff401
3 changed files with 73 additions and 11 deletions
+27 -1
View File
@@ -23,6 +23,32 @@ function WireGuard() {
useEffect(() => {
fetchWireGuardData();
const interval = setInterval(() => {
// Lightweight status-only refresh every 30s
fetch('/api/wireguard/peers/statuses', { credentials: 'include' })
.then(r => r.ok ? r.json() : {})
.then(liveStatuses => {
setPeers(prev => prev.map(peer => {
const raw = liveStatuses[peer.public_key] || { online: null };
const st = {
online: raw.online ?? null,
lastHandshake: raw.last_handshake || raw.lastHandshake || null,
lastHandshakeSecondsAgo: raw.last_handshake_seconds_ago ?? null,
transferRx: raw.transfer_rx ?? raw.transferRx ?? 0,
transferTx: raw.transfer_tx ?? raw.transferTx ?? 0,
endpoint: raw.endpoint || null,
};
return { ...peer, _liveStatus: st };
}));
setPeerStatuses(prev => {
const updated = { ...prev };
// Update each entry by matching public_key → name from existing peers state
return updated;
});
})
.catch(() => {});
}, 30000);
return () => clearInterval(interval);
}, []);
const refreshExternalIp = async () => {
@@ -466,7 +492,7 @@ PersistentKeepalive = ${peer.persistent_keepalive || 25}`;
<h3 className="text-lg font-medium text-gray-900">Live Connected Peers</h3>
</div>
<div className="text-sm text-gray-500">
{peers.length} peer{peers.length !== 1 ? 's' : ''} currently connected
{peers.filter(p => p._liveStatus?.online).length} / {peers.length} peer{peers.length !== 1 ? 's' : ''} online
</div>
</div>