fix: advertise WireGuard endpoint by domain, and reach linked cells over HTTPS
Unit Tests / test (push) Successful in 9m50s
Unit Tests / test (push) Successful in 9m50s
Three related cell-link/peer-config fixes (the peer and cell endpoints were showing the raw external IP, which confused public-vs-internal addressing): 1. Peer WireGuard configs now embed the cell's effective domain (DDNS/ACME modes) instead of the detected external IP, via the new WireGuardManager.get_advertised_endpoint(). A name that resolves to the public IP survives IP changes and lets the datacenter forward each cell's WG port to the right host. LAN mode still falls back to the IP; an admin wireguard_endpoint override still wins. 2. Cell invites advertise <effective-domain>:<this cell's WG port> (was the external IP + a default/possibly-wrong port), so a remote cell pairs to the right host and port over the public path. 3. Cross-cell peer-sync no longer targets http://<ip>:3000 (the API binds 127.0.0.1 and is unreachable across cells). It targets the remote's Caddy on HTTPS/443 — which the WireGuard server already DNATs over the tunnel — and the initial pre-tunnel invite push goes to https://<endpoint-host>/... ; legacy http://<ip>:3000 link URLs migrate to https on load. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1054,6 +1054,38 @@ class WireGuardManager(BaseServiceManager):
|
||||
'vpn_network': self._get_configured_network(),
|
||||
}
|
||||
|
||||
# Domain modes whose effective domain is a publicly-resolvable FQDN that the
|
||||
# WireGuard endpoint should advertise instead of a raw IP. In these modes the
|
||||
# domain resolves (via DDNS/ACME) to the cell's public IP, so peers and linked
|
||||
# cells reach the cell by name — which survives IP changes and lets a NAT/router
|
||||
# forward each cell's WG port to the right host.
|
||||
PUBLIC_DOMAIN_MODES = ('pic_ngo', 'cloudflare', 'duckdns', 'http01')
|
||||
|
||||
def get_advertised_endpoint(self, config_manager=None) -> Optional[str]:
|
||||
"""Return the WireGuard endpoint (host:port) to advertise to peers/cells.
|
||||
|
||||
Preference order:
|
||||
1. an explicit admin override (`_identity.wireguard_endpoint`),
|
||||
2. the cell's public domain in a DDNS/ACME mode (`<domain>:<port>`),
|
||||
3. the detected external IP (`<ip>:<port>`) — LAN/fallback.
|
||||
|
||||
The port is always this cell's own configured WireGuard port, so a cell
|
||||
on a non-default port advertises it correctly (the router forwards that
|
||||
public port to this host).
|
||||
"""
|
||||
port = self._get_configured_port()
|
||||
identity = config_manager.get_identity() if config_manager is not None else {}
|
||||
override = (identity.get('wireguard_endpoint') or '').strip()
|
||||
if override:
|
||||
return override if ':' in override else f'{override}:{port}'
|
||||
mode = identity.get('domain_mode', 'lan')
|
||||
if mode in self.PUBLIC_DOMAIN_MODES and config_manager is not None:
|
||||
host = (config_manager.get_effective_domain() or '').strip()
|
||||
if host:
|
||||
return f'{host}:{port}'
|
||||
ext = self.get_external_ip()
|
||||
return f'{ext}:{port}' if ext else None
|
||||
|
||||
def get_peer_status(self, public_key: str) -> Dict[str, Any]:
|
||||
"""Return live handshake + transfer stats for a peer from `wg show`."""
|
||||
try:
|
||||
|
||||
Reference in New Issue
Block a user