Subdomain routing rules

  1. Reserve the apex and home.00000041.xyz for Home Assistant. Both live in the shared homelab ingress and are served by either replica, so HA at the apex survives joe-host being off. Never put them on a second tunnel.

  2. Route every other service through homelab, using only joe-host’s cloudflared container. One lowercase service label: <service>.00000041.xyz.

  3. One file, two replicas, deployed together. The canonical ingress is ~/.hermes/cloudflared/ingress.yml (mode 600, not in git). It is copied to the cloudflared-config volume on joe-host and to /share/cloudflared/config.yml on the HA box by cf-deploy-ingress.py, which validates the file and verifies both hashes match. Never hand-edit a live config; a mismatch between replicas is how a working route becomes a 404.

  4. Establish authentication before publishing. Give ordinary sites explicit Access coverage. Record any exception that relies on the application’s own auth. Keep secret paths secret: a hostname adds no authentication of its own.

  5. Scope an exception to its path. A hostname that exists only to replace an old apex path should carry a matching path: rule (^/ringbearer/, ^/nextchat-sync, the exact secret prefix), so the rest of that service is not published by accident. Everything unmatched falls to the final http_status:404.

  6. Stage and validate ingress before changing DNS. Keep homelab’s http_status:404 catch-all last. Ingress does not rewrite paths — preserve any path the origin needs. Prefer verified loopback origins (127.0.0.1:<port>) for services on joe-host.

  7. Check both halves of routing. Ingress must select the intended origin; DNS must select the intended tunnel. The wildcard *.00000041.xyz covers new homelab labels unless an explicit record overrides it. Keep the apex and home as explicit records.

  8. One hostname, one owner, one writer. Never mirror the homelab config onto the HA add-on, never restart a legacy connector to “help”, and never point DNS at a target before that target’s config exists.

  9. Back up, validate, activate, read back, probe. Verify application fingerprints and real client behaviour. An Access redirect proves only the gate, never the application. Test the rejected path as well as the accepted one. Update the ownership inventory, the probes and any watchdog that hard-codes a URL.

Worked example — adding notes.00000041.xyz on port 8765

  1. Confirm the origin answers on 127.0.0.1:8765 and note a fingerprint from its body.
  2. Create its Access application, reusing an existing policy.
  3. Stage this rule above the final catch-all in the homelab config:
    - hostname: notes.00000041.xyz
      service: http://127.0.0.1:8765
  4. Validate the candidate config, install it into the cloudflared-config volume, restart cloudflared, and confirm the connector re-registers.
  5. Confirm the wildcard sends notes to homelab (no conflicting explicit record).
  6. Probe anonymously (expect the Access gate), then authenticate and check the app itself.
  7. Add notes to the ownership inventory and to cf-route-probe.py.
  8. Roll back by restoring the previous ingress file and restarting.

Adding a service that must survive joe-host

That is the exception, not the norm: it belongs on the HA box itself and on the homeassistant tunnel, as an additional_hosts entry in the add-on options. Anything that runs on joe-host cannot survive joe-host, whatever the tunnel does.