|
| 1 | +# caddy-proxy |
| 2 | + |
| 3 | +A name in front of something that is already running. No app, no database, no |
| 4 | +runtime to keep alive — Caddy answers the Moshpit name and hands every request |
| 5 | +to a local service on `127.0.0.1:8080` (or wherever `APP_ADDR` says). |
| 6 | + |
| 7 | +This is the template for "I have a thing on this box, put a name on it": a |
| 8 | +dev server, a dashboard, grafana, a game panel, anything that already listens |
| 9 | +on loopback. |
| 10 | + |
| 11 | +## The part that surprises people |
| 12 | + |
| 13 | +Three machines' worth of concerns, and they fail independently: |
| 14 | + |
| 15 | +| | needs the resolver? | what it does | |
| 16 | +|---|---|---| |
| 17 | +| the box serving the name | **no** | Caddy matches a `Host` header, nothing more | |
| 18 | +| the registry | — | holds the address the name points at | |
| 19 | +| every visitor | **yes** | `sudo moshcode dns enable`, or the name resolves to nothing | |
| 20 | + |
| 21 | +Nothing on the server ever resolves its own name. That is why there is no DNS |
| 22 | +software in this template. |
| 23 | + |
| 24 | +## Deploying |
| 25 | + |
| 26 | +1. **Point the name at the box.** In the Pit, set `points at` to its public |
| 27 | + IPv6 address — bare, no scheme, no brackets, no port: |
| 28 | + |
| 29 | + ```sh |
| 30 | + ip -6 addr show scope global | grep inet6 |
| 31 | + ``` |
| 32 | + |
| 33 | + Pick the globally routable one. An `fd..`/`fc..` address is unique-local |
| 34 | + (Tailscale and friends live there) and the registry refuses it, because a |
| 35 | + name pointed at one resolves somewhere only you can reach. |
| 36 | + |
| 37 | +2. **Serve it.** The service stays bound to loopback — Caddy is its only |
| 38 | + client, and binding it publicly publishes it on a port nothing |
| 39 | + virtual-hosts. |
| 40 | + |
| 41 | + ```sh |
| 42 | + export MOSHPIT_NAME=foo.whatever |
| 43 | + export APP_ADDR=127.0.0.1:8080 # the default; change only if the service differs |
| 44 | + sudo cp Caddyfile /etc/caddy/Caddyfile |
| 45 | + sudo systemctl reload caddy |
| 46 | + sudo ufw allow 80/tcp |
| 47 | + ``` |
| 48 | + |
| 49 | +3. **Reach it,** on any machine that should see the name: |
| 50 | + |
| 51 | + ```sh |
| 52 | + sudo moshcode dns enable |
| 53 | + sudo cp deploy/moshcode-dns.service /etc/systemd/system/ # survives reboot |
| 54 | + sudo systemctl enable --now moshcode-dns |
| 55 | + ``` |
| 56 | + |
| 57 | +## Every subdomain at once |
| 58 | + |
| 59 | +One name covers one hostname. To answer `anything.foo.whatever` too — one |
| 60 | +service per subdomain, or a wildcard tenant app — do both halves, in either |
| 61 | +order, because neither works without the other: |
| 62 | + |
| 63 | +1. In the Pit's **DNS Records** tab, publish an **AAAA** record on the |
| 64 | + `*.foo.whatever` option pointing at the same box. Until that exists the |
| 65 | + subdomains resolve to nothing and no request ever reaches Caddy. |
| 66 | +2. Uncomment the wildcard block at the bottom of the Caddyfile and reload. |
| 67 | + Caddy matches exactly one label deep, and the app reads which subdomain was |
| 68 | + asked for from the `Host` header. |
| 69 | + |
| 70 | +`foo.whatever` itself is not covered by a wildcard — keep the apex block (and |
| 71 | +its own AAAA or `points at`) for that. This is how DNS wildcards work, not a |
| 72 | +choice Caddy made. |
| 73 | + |
| 74 | +## Verifying, one layer at a time |
| 75 | + |
| 76 | +A failure at any layer looks identical in a browser, so do not start there. |
| 77 | + |
| 78 | +```sh |
| 79 | +# Server only — no DNS involved. Proves Caddy, the firewall, and the service. |
| 80 | +curl -6 -H "Host: foo.whatever" http://[YOUR:V6:ADDR]/ |
| 81 | + |
| 82 | +# Resolver only. Proves the registry and the bridge. |
| 83 | +moshcode dns resolve foo.whatever |
| 84 | + |
| 85 | +# Both. |
| 86 | +curl -6 http://foo.whatever/ |
| 87 | +``` |
| 88 | + |
| 89 | +If the first works and the last does not, it is DNS. If the first fails, stop |
| 90 | +looking at DNS. |
| 91 | + |
| 92 | +## Known limits |
| 93 | + |
| 94 | +- **No HTTPS, ever.** No CA will issue for an ending outside the DNS root. That |
| 95 | + rules out secure cookies, service workers, and WebCrypto in the browser. The |
| 96 | + `http://` in the Caddyfile is what stops Caddy trying and failing. |
| 97 | +- **Only machines running the resolver can reach the name.** Not phones, not a |
| 98 | + colleague who has not installed it, not webhooks. |
| 99 | + `pit.moshcode.sh/n/foo.whatever` is the URL for people who installed nothing. |
| 100 | +- **Subdomains are opt-in.** `foo.whatever` works out of the box; |
| 101 | + `www.foo.whatever` works only with the wildcard record described above. |
| 102 | +- **Port 80 only** on the resolver path. A DNS record carries an address and |
| 103 | + has nowhere to put a port, which is why Caddy listens on 80 and the |
| 104 | + `host:port` part lives here, not in the registry. |
0 commit comments