|
tests / pest (push) Successful in 10m12s
Details
tests / assets (push) Successful in 21s
Details
tests / release (push) Successful in 5s
Details
The owner's phone shows a blank page on the VPN. That page is the reverse proxy refusing the request, and it refuses because the phone is not on the tunnel: the client config routes only the management subnet, so a request to the console's public hostname leaves over the mobile network and arrives from a carrier address. It is also why the peer reads "last contact: never" — WireGuard only handshakes when it has traffic to send, and nothing is ever routed in. The obvious fixes are both wrong. Adding the server's public address to AllowedIPs routes the WireGuard endpoint into the tunnel it is trying to establish. A public DNS record pointing at 10.66.0.1 publishes the internal subnet to anyone enumerating the domain — the owner raised that himself, and he was right. So the console is served INSIDE the tunnel instead. A small resolver and a small gateway share the hub container's network namespace, which is where wg0 lives, and answer on 10.66.0.1 directly. A client therefore needs no route beyond the subnet it already has, the host's docker bridge is never exposed, and the request reaches the application with its real 10.66.0.x source — which is what the console's own allowlist checks. The gateway reuses the certificate the public Caddy already renews: a certificate is bound to the name, not to the address serving it, so nothing new is issued and nothing internal reaches a public zone. Most of this commit is the arithmetic of not lying about it. Review found fourteen ways the arrangement could report itself working while it was not: enabling the compose profile after the services were started rather than before; starting a gateway with empty certificate paths, which can only crash; treating "container created" as "container running"; carrying a stale readiness marker through a failed restart; reusing the previous hostname's certificate after a rename; leaving the profile enabled when the hostname was cleared, in a script that exits early precisely when nothing else would fix it; reading the renewal timestamp as a user who cannot traverse Caddy's storage; and a `find | head` that aborts the whole installer under pipefail the moment two issuers hold a certificate for the same name. One of them was mine and worth naming: to let the container read the certificate, I had made the TLS private key world-readable. On a multi-user host that hands the console's identity to every local account. The client is told about the resolver only when both services are confirmed running, because a config naming a resolver that does not exist takes the device's entire name resolution with it for as long as the tunnel is up. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|---|---|---|
| .. | ||
| Actions | ||
| Console | ||
| Http | ||
| Livewire | ||
| Models | ||
| Notifications | ||
| Policies | ||
| Providers | ||
| Provisioning | ||
| Services | ||
| Support | ||