1cd1d3bbba
One Caddy block, both names, same root. The prerendered HTML already carries <link rel="canonical"> and og:url pointing at the primeintellectgrowth name on every route, so the alias does not split search ranking or leave a shared link ambiguous about which site it belongs to. Verified byte-identical: both hostnames return the same sha256 for /demos/wordle. Worth recording why the alias failed before this rather than 404ing. lumbridgecorp.com resolves on a WILDCARD, so every subdomain of it points at cloud-2 whether or not Caddy knows the name. DNS completes, TLS opens, Caddy finds no certificate for that SNI and aborts the handshake — the browser reports ERR_SSL_PROTOCOL_ERROR, which reads as "the site is down" rather than "wrong hostname". primeintellectgrowth.com has no wildcard, which is why the canonical name needed an explicit A record. deploy.sh now smoke-tests the alias too: if the block is ever edited to drop the second name, the failure mode is a TLS error, and nothing else would catch it. The live block is mirrored into deploy/Caddyfile.demo so the config is reviewable in the repo rather than only on the host. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019mt6sHQHEnEYrJZvoMCJSB
68 lines
2.7 KiB
Markdown
68 lines
2.7 KiB
Markdown
# Deploying
|
|
|
|
Static build, rsynced to cloud-2, served by Caddy.
|
|
|
|
```bash
|
|
pnpm build && bash deploy/deploy.sh
|
|
```
|
|
|
|
## The pieces
|
|
|
|
| | |
|
|
|---|---|
|
|
| Hostnames | `demo.primeintellectgrowth.com` (canonical) and `demo.lumbridgecorp.com` (alias) |
|
|
| Host | cloud-2, `ubuntu@100.92.185.76` (tailnet only) |
|
|
| Root | `/var/www/demo.primeintellectgrowth.com` |
|
|
| Snapshots | `…-rollbacks/`, last 10, hard-linked |
|
|
| DNS | OCI zone `primeintellectgrowth.com` → `170.9.14.61`, explicit A record, no wildcard. The alias needs no record: `lumbridgecorp.com` has a wildcard |
|
|
| Caddy | one block for both names, mirrored in `Caddyfile.demo` |
|
|
|
|
## Two hostnames, one root
|
|
|
|
Both names serve the same build. The prerendered HTML carries
|
|
`<link rel="canonical">` and `og:url` pointing at the **primeintellectgrowth**
|
|
name on every route, so the alias does not split search ranking or make a shared
|
|
link ambiguous about which site it belongs to.
|
|
|
|
⚠️ **`lumbridgecorp.com` resolves on a wildcard.** Every subdomain of it points
|
|
at cloud-2 whether or not Caddy has a block for it — so an unconfigured or
|
|
mistyped name completes DNS, opens TLS, finds no certificate for that SNI, and
|
|
fails the handshake with `ERR_SSL_PROTOCOL_ERROR`. That reads as "the site is
|
|
broken" when it means "that is not a site". `primeintellectgrowth.com` has no
|
|
wildcard, which is why the canonical name needed an explicit A record.
|
|
|
|
`deploy.sh` smoke-tests the alias for exactly this reason: if the block is ever
|
|
edited to drop the second name, the failure is a TLS error rather than a 404,
|
|
and nothing else would notice.
|
|
|
|
## The trap that costs an afternoon
|
|
|
|
**`bind 10.0.0.2` is mandatory in the Caddy block, and its absence is silent.**
|
|
Without it Caddy builds a second server on `*:443` that has never heard of this
|
|
hostname. Public traffic — which NATs to `10.0.0.2` — falls through to an empty
|
|
`200` behind a perfectly valid certificate. Worse, a
|
|
`curl --resolve demo.primeintellectgrowth.com:443:127.0.0.1` from cloud-2 itself
|
|
still passes.
|
|
|
|
`deploy.sh` therefore smoke-tests the real public hostname from the deploying
|
|
machine and fails on a response under 1 kB.
|
|
|
|
Do not use PIG's `deploy/Caddyfile.example` as a template — it omits the bind.
|
|
|
|
## Rolling back
|
|
|
|
```bash
|
|
ssh ubuntu@100.92.185.76
|
|
ls -1dt /var/www/demo.primeintellectgrowth.com-rollbacks/*/
|
|
sudo rsync -a --delete <that-dir>/ /var/www/demo.primeintellectgrowth.com/
|
|
```
|
|
|
|
No Caddy reload needed; the root path does not change.
|
|
|
|
## Editing the live Caddyfile
|
|
|
|
Scope the edit to this site's block. Several sites on cloud-2 carry
|
|
byte-identical header strings, so a naive global replace hits two of them. Slice
|
|
between `demo.primeintellectgrowth.com {` and the next hostname, and assert the
|
|
match is unique inside that slice.
|