docs(mistakes): the llamacasty.com deploy recipe, recorded

Deploying the site cost a session because the only documentation was a destination
('/var/www/linkstack/'), not a transport, and the failure modes looked like credential
problems rather than the two things they were: sshd offers publickey only on 2214, and
it appended a keyboard-interactive 2FA step that a non-interactive tool call cannot
answer (hang, then 'Permission denied (publickey)').

Records the whole shape: web root and owner, port 2214 key-only, password = sudo not
SSH, the 2026-10-30 removal of AuthenticationMethods/PAM 2FA, and the traps — the md
files must never be published (build-this.md now carries INTERNAL pricing), drvfs 777
needs the chmod pass, linkstack__2 is a different app, and 22/1319 are closed.
Recipe lives in llamacasty.web/deploy.sh.
This commit is contained in:
2026-10-30 16:49:33 -07:00
parent c72b61b61e
commit 90d5140906
+33
View File
@@ -35,6 +35,39 @@ max 200.
## 🔬 Recipes registry
### DEPLOYING llamacasty.com TO THE DROPLET (RECIPE, 2026-10-30)
**Problem:** "upload the site" burned a session: `ssh -p 2214 gramps@llamachile.tube` hung on a
prompt, then answered `Permission denied (publickey)` everywhere, and the two md files that document
the deploy only said *"copy this working tree into `/var/www/linkstack/`"* — a destination, not a
transport.
**What it actually is:** the static site lives in **`/var/www/linkstack/`** on the YunoHost droplet
(`llamachile.tube` = `llamacasty.com` = `143.244.176.131`), owned `linkstack:www-data`. The host
sshd is **port 2214** with **key-only auth** (`PasswordAuthentication no`; publickey is the only
method offered for every user). The `CREDENTIALS.md` password is the **sudo** password — it is not
an SSH auth method and never was.
**The hang was the second factor:** sshd had `AuthenticationMethods publickey,keyboard-interactive`
(PAM `pam_google_authenticator`), so a key got through and then the server asked for a verification
code that a non-interactive tool call cannot answer. Disabled permanently 2026-10-30 by commenting
that line and the PAM module in `/etc/pam.d/sshd`, then `sshd -t && systemctl restart ssh`.
**The recipe:** `llamacasty.web/deploy.sh` — tars the **public** files only (`index.html`,
`privacy.html`, `css/`, `js/`, `assets/`), `scp`s the tarball to `/tmp`, then one `sudo -S` shell
that backs up the live root to `/var/backups/linkstack-<stamp>.tgz`, extracts over it, restores
`linkstack:www-data` + `755/644`, deletes `build-this.md` from the root, and curls the site.
Password comes in on **stdin** (`SITE_SUDO_PW=... ./deploy.sh`), never on a command line.
- ⚠️ **Never publish the md files.** `build-this.md` shipped in the web root until 2026-10-30 and
now carries **INTERNAL** pricing notes. The deploy script's file list is explicit for that reason.
- ⚠️ **drvfs sets 777 on copied files** — the chmod pass in the script is not cosmetic; a world-
writable web root is a defacement waiting to happen.
- ⚠️ **`/var/www/linkstack__2` is a different app's directory** (the old LinkStack PHP install).
The static site is `linkstack`, without the suffix.
- ⚠️ Ports **22 and 1319 are closed**; 2214 is the only SSH door, and it is the *host*, not Gitea
(Gitea pushes go over **HTTPS** with the credential helper — see `docs/ai/environment.md`).
### CONVERTING A MEDIAPIPE .tflite (WITH CUSTOM OPS) TO ONNX — AND PROVING IT (RECIPE, TASK 51)
**Problem:** MediaPipe segmentation models end in the custom op `Convolution2DTransposeBias`;