deploy: ops canary defaults to the dev mesh (Helsinki), prod becomes the exception (#1265)
Paul, 2026-07-22: throwaway per-session canaries don't belong on the box real members live on. Default box/domain flip to elevendev-fi / fi.dev.11ch.at (amd64, matching build-linux.sh); LCHAT_CANARY_BOX=elevenbox LCHAT_CANARY_DOMAIN=11ch.at is the deliberate prod exception. Script header documents the ssh alias and the per-host-cert budget caveat (no wildcard on dev by design); CLAUDE.md prose updated to match.
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
3 files changed,
+30
−11
CLAUDE.md+12 −6deploy/ops+1 −1deploy/ops-canary.sh+17 −4
diff --git a/CLAUDE.md b/CLAUDE.md| index 61ddd6a..45abca0 100644 |
| --- a/CLAUDE.md |
| +++ b/CLAUDE.md |
| @@ -634,12 +634,18 @@ Principles that hold regardless of environment: |
| shell. Every operator SSH session gets a public why-entry in the status |
| ledger (`web/status/ssh/`). Recipe: `docs/instance-router.md ยง Hardening`. |
| -### ๐ค Per-session canaries (test-*.11ch.at) |
| - |
| -Instances are disposable โ wildcard DNS **and** a wildcard TLS cert cover |
| -`*.11ch.at`, so creating one needs no DNS step, no cert wait, and burns no |
| -rate limit. So instead of sharing one `test` instance across parallel |
| -sessions (they trample each other): |
| +### ๐ค Per-session canaries (test-*.fi.dev.11ch.at) |
| + |
| +Instances are disposable โ wildcard DNS covers the canary domains, so |
| +creating one needs no DNS step. **Canaries live on the dev mesh by default** |
| +(Paul, 2026-07-22): throwaway test instances don't belong on the box real |
| +members live on, and they'd eat its instance cap. The default is the |
| +Helsinki dev box (`fi.dev.11ch.at` โ amd64, matching `build-linux.sh`); |
| +targeting production (`LCHAT_CANARY_BOX=elevenbox LCHAT_CANARY_DOMAIN=11ch.at`) |
| +is a deliberate, stated exception. One dev caveat: no wildcard cert there by |
| +design, so each dev canary burns a per-host HTTP-01 cert from the shared |
| +50/week 11ch.at budget โ fine at canary cadence. So instead of sharing one |
| +`test` instance across parallel sessions (they trample each other): |
| The encoded path is `./deploy/ops canary create|deploy|destroy <slug>` โ |
| each verb enforces the rules below, so prefer it over hand-run `lchat` |
diff --git a/deploy/ops b/deploy/ops| index 85cf7f0..6edc882 100755 |
| --- a/deploy/ops |
| +++ b/deploy/ops |
| @@ -39,7 +39,7 @@ ledger; `ops ledger` drafts it. |
| Env overrides (defaults live in the verb scripts): |
| LCHAT_BOXES fleet box ssh aliases (doctor, ship) |
| - LCHAT_CANARY_BOX the router box canaries live on |
| + LCHAT_CANARY_BOX the box canaries live on (default: the dev mesh; prod is the deliberate exception) |
| LCHAT_RELEASES_REPO the public releases repo |
| No verb for your task? EXTEND ops โ a new verb or flag in a small PR |
diff --git a/deploy/ops-canary.sh b/deploy/ops-canary.sh| index 1ebbfe6..5f0ed03 100755 |
| --- a/deploy/ops-canary.sh |
| +++ b/deploy/ops-canary.sh |
| @@ -29,10 +29,23 @@ set -eu |
| here="$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)" |
| root="$(CDPATH= cd -- "$here/.." && pwd)" |
| -# The router box canaries live on โ an ssh alias; user/hostname come from |
| -# ~/.ssh/config over WireGuard (box specifics in CLAUDE.local.md). |
| -BOX="${LCHAT_CANARY_BOX:-${LCHAT_BOX:-elevenbox}}" |
| -DOMAIN="${LCHAT_CANARY_DOMAIN:-11ch.at}" |
| +# The box canaries live on โ an ssh alias; user/hostname come from |
| +# ~/.ssh/config (box specifics in CLAUDE.local.md). Canaries live on the DEV |
| +# MESH by default (Paul, 2026-07-22): throwaway test instances don't belong on |
| +# the box real members live on, and they'd eat its instance cap. Helsinki is |
| +# the dev default because build-linux.sh emits amd64 (Dublin is arm64). Alias |
| +# to add once per machine: |
| +# Host elevendev-fi |
| +# HostName 157.180.123.183 |
| +# User root |
| +# IdentityFile ~/.ssh/eleven-dev-box |
| +# Prod (LCHAT_CANARY_BOX=elevenbox LCHAT_CANARY_DOMAIN=11ch.at) is the |
| +# deliberate exception, not the default. |
| +# NB dev has no wildcard cert BY DESIGN (the DNSimple token never goes on a |
| +# dev box), so each dev canary host burns one per-host HTTP-01 cert from the |
| +# shared 50/week 11ch.at LE budget โ fine at canary cadence, not for bursts. |
| +BOX="${LCHAT_CANARY_BOX:-elevendev-fi}" |
| +DOMAIN="${LCHAT_CANARY_DOMAIN:-fi.dev.11ch.at}" |
| LCHAT=/opt/lchat/lchat |
| usage() { |