Skip to content

Runbook: tunnel-recovery

When https://warehouse.caseymanos.com is down or misbehaving.

Quick triage

# Is the tunnel up at all?
curl -I https://warehouse.caseymanos.com
# Expected: 302 redirect to Cloudflare Access challenge

# Is uvicorn running locally?
lsof -i :8765
# If nothing: uvicorn isn't up. kbui hasn't been run yet, or run_ui.sh died.

# Is cloudflared running?
ps aux | grep -i cloudflared | grep -v grep

# Is the tunnel registered with Cloudflare?
cloudflared tunnel list
# Should show "warehouse" with id edae87c6-61b1-4f84-a776-87d8732693ea

Common scenarios

Browser shows Cloudflare Access challenge but PIN never arrives

PIN delivery to email can be slow (up to 1min) or land in spam. Check spam. If still nothing after 2min:

  1. Browser → click "Resend code"
  2. Check Cloudflare Access policy in dashboard:
  3. Zero Trust → Access → Applications → warehouse
  4. Policy: email auth, allow only manoscasey@gmail.com
  5. Verify the email address matches what's in the policy

Browser shows "Tunnel offline"

cloudflared isn't running. The tunnel is kbui-driven — uvicorn + cloudflared start together via ~/garmin-warehouse/scripts/run_ui.sh.

# Just restart:
kbui
# Or:
~/garmin-warehouse/scripts/run_ui.sh

If kbui exits immediately with an error:

# Run pieces separately:
# Terminal 1:
cd ~/garmin-warehouse && uv run uvicorn ui.app:app --reload --port 8765 --host 127.0.0.1

# Terminal 2:
cloudflared tunnel --config ~/.cloudflared/config.yml run warehouse

Watch each for errors.

Browser shows 502 / 504 from Cloudflare

cloudflared is up but uvicorn isn't responding. Check:

curl http://localhost:8765/
# If timeout/refused: uvicorn died.
# If responds: cloudflared can't reach localhost:8765.

If cloudflared can't reach uvicorn while both are running: - Check ~/.cloudflared/config.yml ingress rule points at correct port (http://localhost:8765) - Check no firewall is blocking localhost (rare on Mac)

cloudflared won't start: cert.pem missing or invalid

ls -la ~/.cloudflared/cert.pem
# If missing or 0 bytes:
cloudflared tunnel login
# Browser opens, log in to CF account, cert.pem gets written.

cloudflared won't start: tunnel JWT missing

ls ~/.cloudflared/
# Expected: cert.pem + edae87c6-61b1-4f84-a776-87d8732693ea.json (the JWT)
# If JWT missing:
cloudflared tunnel token --cred-file ~/.cloudflared/edae87c6-61b1-4f84-a776-87d8732693ea.json warehouse

DNS not resolving

dig warehouse.caseymanos.com
# Expected: CNAME to <tunnel-id>.cfargotunnel.com

If wrong CNAME or none:

cloudflared tunnel route dns warehouse warehouse.caseymanos.com
# Re-creates the CNAME automatically in caseymanos.com zone.

Tunnel JSON revoked / lost

If the tunnel's JWT is gone and you can't recover:

# Delete and recreate (loses tunnel ID, requires DNS update):
cloudflared tunnel delete warehouse
cloudflared tunnel create warehouse
# Note the new tunnel ID, update ~/.cloudflared/config.yml
cloudflared tunnel route dns warehouse warehouse.caseymanos.com
# Restart tunnel

Tunnel-as-service (NOT enabled)

You'd think running cloudflared as a launchd service would be a win, but:

  • It would need uvicorn to also be always-on (otherwise the tunnel serves a dead port)
  • uvicorn-as-service is the harder problem (can't reload from filesystem watches; needs gunicorn-style management)

So tunnel stays kbui-driven until that changes.

Cloudflare Access policy quirks

  • Policy changes can take ~30s to propagate
  • "Service tokens" exist for non-browser access but aren't configured here — only Casey's email gets through
  • If you need to allow another email temporarily: dashboard → Zero Trust → Access → Applications → warehouse → Policies → edit

cloudflared doesn't hot-reload config.yml

Symptom: You edited ~/.cloudflared/config.yml (e.g. added a new ingress rule) but the new behavior isn't live.

Cause: cloudflared reads config only at process startup. Config-file edits are silently ignored until you restart the process.

Fix: Kill + restart cloudflared.

# Find the pid:
ps aux | grep cloudflared | grep -v grep
# Or just pkill:
pkill -f "cloudflared tunnel"
sleep 2

# Restart (foreground; or via run_ui.sh / kbui):
cloudflared tunnel --config ~/.cloudflared/config.yml run warehouse

If kbui is running, killing cloudflared makes its trap fire and uvicorn also exits. Just re-run kbui.

Note: as of 2026-05-04, the tunnel only routes one thing — warehouse.caseymanos.comlocalhost:8765. The docs site is on Cloudflare Pages, not the tunnel — see ADR 006. If you find yourself adding ingress rules to expose more local services, ask whether they should actually live on Pages / Workers instead.