Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,28 @@
## Unreleased

### Ops
- Add `ecosystem.config.cjs.example` template — the real `ecosystem.config.cjs`
remains gitignored, but the template documents the canonical shape and the
locally-managed-tunnel trap.

### Notes for future ops debugging

If `api.thehumanpatternlab.com` ever returns Cloudflare **error 1033 / HTTP 530**
("Argo Tunnel error / no available origin"), `pm2 logs cf-tunnel --err` will
usually show one of two things:

1. **`Provided Tunnel token is not valid.`** — the cf-tunnel `args` block in
`ecosystem.config.cjs` is using the `--token <jwt>` form, but the tunnel was
created locally (`cloudflared tunnel create`). Locally-managed tunnels
authenticate via the cred file at `~/.cloudflared/<uuid>.json`, not a JWT.
Fix: change the args to `["tunnel", "run", "<tunnel-name>"]`. See the
`ecosystem.config.cjs.example` header comment for the full picture.

2. **PM2 process listed but with `▒▒` status / 0b memory / hundreds of restarts**
— half-zombie entry. Underlying cloudflared process is gone or detached but
PM2 still has the registry entry. Fix: `pm2 delete cf-tunnel && pm2 start
ecosystem.config.cjs --only cf-tunnel && pm2 save`.

## v0.2.0 — Ledger Era + Canonical API Base

### Breaking
Expand Down
76 changes: 76 additions & 0 deletions ecosystem.config.cjs.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/**
* PM2 Ecosystem — Human Pattern Lab (TEMPLATE)
*
* Copy this file to `ecosystem.config.cjs` on the production server and
* fill in the placeholder values. The real `ecosystem.config.cjs` is
* gitignored because it contains secrets — keep it that way.
*
* Topology:
* - lab-api runs on localhost:8001
* - cf-tunnel exposes it via a Cloudflare Tunnel managed *locally*
* (cred file at ~/.cloudflared/<tunnel-uuid>.json + ~/.cloudflared/config.yml)
*
* IMPORTANT — locally-managed vs remote-managed tunnel auth:
* - Locally-managed tunnels authenticate via the cred JSON file. Run
* them with: `cloudflared tunnel run <tunnel-name>`
* - Remote-managed tunnels (created in the Cloudflare Zero Trust
* dashboard) authenticate via a JWT-shaped `--token <...>` arg.
* - The two formats are MUTUALLY EXCLUSIVE. Feeding a remote-management
* token to a locally-managed tunnel produces an endless loop of:
* "Provided Tunnel token is not valid."
* If you see that error in `pm2 logs cf-tunnel --err`, this is the
* mismatch — confirm `~/.cloudflared/<uuid>.json` exists and use the
* `args: ["tunnel", "run", "<tunnel-name>"]` form below.
*/

module.exports = {
apps: [
{
name: "lab-api",
cwd: "/home/<user>/lab-api",
script: "dist/index.js",
interpreter: "/home/<user>/.nvm/versions/node/v20.19.6/bin/node",
exec_mode: "fork",
time: true,
env: {
NODE_ENV: "production",
PORT: "8001",

// Generate with: node -e "console.log(require('crypto').randomBytes(32).toString('base64url'))"
SESSION_SECRET: "REPLACE_ME_WITH_A_RANDOM_SECRET",

UI_BASE_URL: "https://thehumanpatternlab.com",

// TOKEN_PEPPER and other secrets are loaded from `.env`
// by dotenv at app startup (see src/env.ts). Don't put
// them here unless you also remove them from `.env` —
// having them in both can produce subtle override bugs.
},
max_restarts: 10,
restart_delay: 2000,
},

{
name: "cf-tunnel",
script: "/home/<user>/bin/cloudflared",

// Locally-managed tunnel — references the tunnel by name as
// defined in ~/.cloudflared/config.yml. cloudflared loads
// ~/.cloudflared/<tunnel-uuid>.json automatically for auth.
args: ["tunnel", "run", "lab-api"],

// ⚠️ Do NOT use the "--token <jwt>" form here for a tunnel
// that was created with `cloudflared tunnel create`. See the
// header comment for why.

auto_restart: true,
restart_delay: 5000,
time: true,
max_restarts: 20,

out_file: "/home/<user>/lab-api/logs/cloudflared.out.log",
error_file: "/home/<user>/lab-api/logs/cloudflared.err.log",
merge_logs: true,
},
],
};
Loading