Cloudflare tunnels — one tunnel, two replicas

homelab (e938d2cb) is the only tunnel. It has two connectors running the same ingress:

ReplicaHostReadsReaches
linux_amd64joe-hostDocker volume cloudflared-config → /etc/cloudflared/config.ymlservices on 192.168.0.182; HA on 192.168.0.155
linux_arm64HA box (container cloudflared-ha)/share/cloudflared/config.ymlthe same, over the LAN

Cloudflare picks a connector per request; both are configured identically, so either one returns the same application. That is the whole trick: the apex survives joe-host because the HA box runs its own replica, not because HA lives on a different tunnel.

homeassistant (076a3313) and its add-on are deleted — tunnel gone, add-on uninstalled. Do not recreate them; a second tunnel is a second writer.

The apex keeps its path rules — ^/vault, ^/ringbearer/webhook$, ^/nextchat-sync, the two ^/private_<token> routes — ahead of the bare-apex rule that lands on Home Assistant. No client URL had to change.

Single source of truth

~/.hermes/cloudflared/ingress.yml (mode 600, never in git — it carries secret paths) is the only ingress definition. RELEASE.json records its SHA-256. Deploy with ~/.hermes/scripts/cf-deploy-ingress.py, which validates, writes both copies, restarts both connectors and verifies the hashes match. Never edit a live config by hand.

Origins are absolute LAN addresses (192.168.0.182, 192.168.0.155) so the file is host-independent. No loopback, no container names.

What each failure costs

FailureStill reachable
joe-host VM downHA at the apex and home; anything hosted on the HA box
joe-host connector downeverything, through the HA replica (verified 5 Nov: apex 200, /vault 200, webhook 401)
HA box downevery joe-host service; the apex goes with it
HA add-on down/updatednothing — it is retired
Cloudflare / ISP / router downnothing public; the LAN keeps working

The apex has two connectors but one origin: HA on one box. A second HA instance would be the next step for availability, not another tunnel.

Health check

~/.hermes/scripts/cf-route-probe.py, daily 06:15 (no_agent=True). It asserts DNS ownership (every hostname → homelab), that both replicas are present (amd64 + arm64), that the two config files hash identically, and that real URLs fingerprint the applications. Silent when healthy; a missing replica or a hash drift fails loudly with the hashes and CF-Ray.

Rules

  • One tunnel, two replicas, one config file. Never introduce a second tunnel or a second writer.
  • home is an alias for HA inside the shared ingress; it is not a separate deployment.
  • Path rules stay valid — the apex block is unchanged, so no client URL needs to move.
  • The HA replica must never depend on joe-host to boot: it reads local files and starts from its Docker restart policy (unless-stopped).
  • Access policies attach to hostnames, so nothing here changes the login gate.