diff --git a/.hermes/skills/devops/nix-ci-deploy/references/bun-source-ssh-deploy.md b/.hermes/skills/devops/nix-ci-deploy/references/bun-source-ssh-deploy.md new file mode 100644 index 0000000..a904165 --- /dev/null +++ b/.hermes/skills/devops/nix-ci-deploy/references/bun-source-ssh-deploy.md @@ -0,0 +1,254 @@ +# SSH deploy to bun-source services (not Nix): gotchas + +This repo (`asepharyana/mcpedia`) deploys **bun source** via systemd — NOT via +Nix like GMW. The pattern is: CI builds in GitHub Actions → upload artifact → +deploy job downloads artifact → SCP tarball to VPS → SSH → git pull + unpack + +index + `systemctl restart`. The VPS does NOT build. + +## Gotchas (learned during mcpedia deploy setup, 2026-08-20/21) + +### 1. SSH host = public IP, NOT Tailscale IP + +The VPS appears in `~/.ssh/config` as `Host orange → HostName 100.79.111.61`. +That IP is a **Tailscale `tailscale0` interface address** in the CGNAT range +(`100.64.0.0/10`). GitHub Actions runners are NOT on the Tailscale network, so +they get `Connection timed out` (dropped at the network layer, not refused). + +**Fix:** Use the VPS's real public IP (`45.127.35.244`, discovered via +`curl https://api.ipify.org` from the VPS). Port 22 is open in iptables +(`ACCEPT tcp dpt:22` from `0.0.0.0/0`). + +### 2. SSH key MUST be stored directly from file (not shell variable) + +Storing the deploy key via a shell variable corrupts it: + +```bash +# ❌ WRONG — newlines get mangled by the shell → "ssh: no key found" +PRIV_KEY=$(cat keyfile) +gh secret set SSH_DEPLOY_KEY --body "$PRIV_KEY" + +# ✅ CORRECT — pipe the file directly so GitHub preserves all bytes +cat keyfile | gh secret set SSH_DEPLOY_KEY --repo asepharyana/mcpedia +``` + +Symptom: `appleboy/ssh-action` fails with +`ssh.ParsePrivateKey: ssh: no key found`. + +### 3. Use `appleboy/ssh-action@v1` (not `@v1.1.0`) + +- `@v1.1.0` (very old) has a key-parsing bug that rejects valid keys + (`ssh.ParsePrivateKey: ssh: no key found`). +- `@v1` (latest) handles OpenSSH ed25519 keys correctly. + +### 4. `appleboy/ssh-action` needs explicit `envs` to pass through secret-derived vars + +The `envs` parameter passes environment variables to the remote script. +Include any secret you reference in the script: +```yaml +envs: SSH_DEPLOY_HOST # passes SSH_DEPLOY_HOST into the remote script +``` +Without it, `echo $SSH_DEPLOY_HOST` on the VPS returns empty even though the +action connected. + +### 5. Always pass `-o IdentitiesOnly=yes` + +Without it, SSH offers ALL loaded identities (deploy key + default keys) and the +server may reject after "Too many authentication failures". `appleboy/ssh-action` +handles this internally via the `key` input, but if you use raw `ssh` add +`-o IdentitiesOnly=yes`. + +### 6. GitHub `workflow_run` does NOT carry the push commit SHA + +`workflow_run` events fire after CI completes, but `actions/checkout` checks out +the **default branch tip**, not the specific commit. This is fine for deploy +(the script does `git pull origin main` anyway), but verify the checkout ref +matches what CI built if you rely on it. + +### 7. DB migrations: `db:push` prompt is non-interactive-unfriendly in SSH deploy + +When the schema includes a new column (e.g. adding `extra_fields JSONB`), +`drizzle-kit push` in the SSH deploy script needs to be run. Two issues: + +- **`--strict` mode (config default)**: `drizzle.config.ts` has `strict: true`, + which makes `drizzle-kit push` prompt `No, abort / Yes, I want to execute all + statements`. In a non-interactive SSH script (no TTY), the prompt never receives + input and the command times out → SIGTERM → exit code 124 → deploy fails. + `set -e` then kills the whole deploy. +- **`bun run