Skip to content

Commit 0d27ed8

Browse files
deploy: unified-on-melvin.me upgrade runbook + sample plugin config
Chosen path: load forge/gallery/dashboard onto the existing melvin.me pod. Adds UPGRADE-melvin.md (staged procedure: own 0.0.219 install to spare losos.org, backup+rollback, collision map — core --activitypub/ --nostr already own /ap //.well-known/{webfinger,nostr.json} so those plugins are skipped, only unique-prefix ones go on) and a --config sample (the --plugin flag can't pass config; forge needs its loopback Host=melvin.me behind haproxy). Prod cutover gated on staging + go-ahead.
1 parent 3ac7e95 commit 0d27ed8

2 files changed

Lines changed: 165 additions & 0 deletions

File tree

deploy/UPGRADE-melvin.md

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
# Unified deploy: add the plugins to the existing melvin.me pod
2+
3+
You chose to run the forge/plugins **on the melvin.me pod itself** (not a
4+
separate instance). That's the best end state — one identity, one origin — but
5+
it changes a live, single-user pod with real data, so this is a **staged**
6+
procedure with a backup and a rollback, not a one-shot. Nothing here should run
7+
against production until the staging step passes.
8+
9+
## What we're changing, and the blast radius
10+
11+
- melvin.me runs as its own pm2 app (`jss start --port 5420 --root
12+
/home/ubuntu/www/melvin.me --single-user … --idp-issuer https://melvin.me/
13+
--git --activitypub --nostr --notifications --webrtc --tunnel --pay`), using
14+
the **shared `/home/ubuntu/jss` install (JSS 0.0.204)** — which **also serves
15+
losos.org**.
16+
- The plugins need **JSS ≥ 0.0.219**.
17+
18+
**Blast-radius choice (decide first):**
19+
- **(recommended) Give melvin.me its own install at 0.0.219**, leaving
20+
`/home/ubuntu/jss` (and losos.org) on 0.0.204. Smallest blast radius.
21+
- Or upgrade the shared install — then losos.org moves to 0.0.219 too and must
22+
be re-verified. Only if you want both upgraded.
23+
24+
## Is 0.0.204 → 0.0.219 safe? (mostly yes)
25+
26+
The span is **almost entirely additive**: the #206 plugin loader, `appPaths`,
27+
`getAgent`, the four seams (serverInfo/reservePath/mountApp/api.plugins), the
28+
`--plugin` flag, the id-from-parent-dir fix. Two behavior tightenings to note,
29+
both security fixes, both low-risk for a normal pod:
30+
- #580 — POST-created `.acl`/`.meta` sidecars now require `Control` on the
31+
protected resource.
32+
- #571 — nostr JWK key path reconciled to accept both Y-parities.
33+
34+
Verify your pod's data loads and its features still work in **staging** anyway.
35+
36+
## Collision map (why only three plugins go on)
37+
38+
`reservePath` fails boot **loudly** on a route collision, and this pod already
39+
runs core features that own roots the plugins want:
40+
41+
| Plugin | Wants | Core already owns it here? | Verdict |
42+
|---|---|---|---|
43+
| forge | `/forge` | no | **add** |
44+
| gallery | `/gallery` | no | **add** |
45+
| dashboard | `/dashboard` | no | **add** |
46+
| activitypub | `/ap` | yes (`--activitypub`) | skip |
47+
| webfinger | `/.well-known/webfinger` | yes (`--activitypub`) | skip |
48+
| nip05 | `/.well-known/nostr.json` | yes (`--nostr`) | skip |
49+
| mastodon | `/api`, `/oauth` | verify free, then optional | verify |
50+
| bluesky/matrix | `/xrpc`, `/_matrix` | verify free, then optional | verify |
51+
52+
So the initial unified set is **forge + gallery + dashboard** — additive, no
53+
collisions. (mastodon is temptingly nice — Phanpy against melvin.me — but only
54+
if `/api`/`/oauth` are unused by the pod; check with `--print-config` /
55+
a route probe in staging before adding it.)
56+
57+
## How they get loaded (config file, not just --plugin)
58+
59+
The `--plugin module[@prefix]` flag can't pass config, and forge needs its
60+
loopback origin set correctly behind haproxy. So keep every current flag and
61+
add a config file:
62+
63+
```
64+
jss start … (all existing flags) … --config /home/ubuntu/melvin.me.plugins.json
65+
```
66+
67+
Use `deploy/melvin.me.plugins.sample.json` as the template (copy to
68+
`/home/ubuntu/melvin.me.plugins.json`, adjust paths). The plugin files live in
69+
the plugins checkout and `import 'javascript-solid-server/auth.js'` — that
70+
resolves from the checkout's own `node_modules` (0.0.219), so keep
71+
`/home/ubuntu/plugins` installed with `npm ci`.
72+
73+
**Host consistency (the one integration risk to prove in staging):** behind
74+
haproxy, `api.serverInfo()` sees the internal bind, not `melvin.me`. forge's
75+
pod-owning writes must present `Host: melvin.me` or WAC 403s them. The sample
76+
config sets `loopbackUrl/baseUrl: https://melvin.me`; pair it with
77+
`127.0.0.1 melvin.me` in `/etc/hosts` so the self-call stays local. **Confirm a
78+
signed-in issue write returns 200 in staging** before cutover — this is the
79+
exact failure we hit and fixed once already.
80+
81+
## The staged procedure
82+
83+
```bash
84+
# 0. plugins checkout with its own 0.0.219
85+
cd /home/ubuntu && git clone https://github.com/JavaScriptSolidServer/plugins.git
86+
cd plugins && git checkout gh-pages && npm ci
87+
88+
# 1. BACK UP the pod data (reversible) and note the current install version
89+
tar czf ~/melvin.me-poddata-$(date +%F).tgz -C /home/ubuntu/www melvin.me
90+
node -e "console.log(require('/home/ubuntu/jss/node_modules/javascript-solid-server/package.json').version)" # 0.0.204
91+
92+
# 2. STAGING: copy the pod data to scratch, run 0.0.219 + plugins on a temp port
93+
cp -a /home/ubuntu/www/melvin.me /tmp/melvin-stage
94+
mkdir -p /home/ubuntu/jss-0219 && cd /home/ubuntu/jss-0219 \
95+
&& npm init -y >/dev/null && npm i javascript-solid-server@0.0.219
96+
cp /home/ubuntu/plugins/deploy/melvin.me.plugins.sample.json /tmp/melvin-stage.plugins.json
97+
# edit the temp config's module paths if needed, then:
98+
PUBLIC_URL=https://melvin.me node /home/ubuntu/jss-0219/node_modules/.bin/jss start \
99+
--port 5999 --root /tmp/melvin-stage --single-user --single-user-name melvin \
100+
--idp --idp-issuer https://melvin.me/ --git --activitypub --nostr --notifications \
101+
--config /tmp/melvin-stage.plugins.json
102+
# (mirror the REST of the real flags: --webrtc --tunnel --pay --pay-* --mongo …)
103+
104+
# 3. VERIFY against :5999 (add a temp haproxy backend or curl with Host header):
105+
# - existing features still work (AP actor, nostr.json, notifications, pay)
106+
# - /forge/ and /gallery/ and /dashboard/ answer 200
107+
# - sign in, open a forge issue → 200 (the Host/loopback check)
108+
# - the pod's real data is intact (browse it)
109+
110+
# 4. CUTOVER only if staging is clean: point the melvin.me pm2 app at the
111+
# 0.0.219 install + the config file, reload, and add a haproxy note if any.
112+
# pm2 restart melvin.me (after editing its start command/ecosystem)
113+
# pm2 save
114+
115+
# 5. VERIFY prod the same way. Keep the backup + the 0.0.204 install until happy.
116+
```
117+
118+
## Rollback
119+
120+
Point the melvin.me pm2 app back at the 0.0.204 install and its original start
121+
command; restore the pod data tarball if anything wrote badly. Because the
122+
plugins only add `/forge` `/gallery` `/dashboard` and don't migrate existing
123+
data, rollback is: drop the `--config` flag and revert the JSS binary.
124+
125+
## What I can do vs. what needs you
126+
127+
I can prepare every file here and drive the **staging** run (read-mostly, on a
128+
copy). The **production cutover** — upgrading the binary, editing the live pm2
129+
app, reloading haproxy — changes your running sites, so I'll only do those with
130+
your explicit go-ahead, step by step, or hand you the exact commands to run.
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
{
2+
"//": "Sample --config file to add plugins to the EXISTING melvin.me pod.",
3+
"//1": "Usage: keep all the current `jss start` flags AND add",
4+
"//2": " --config /home/ubuntu/melvin.me.plugins.json",
5+
"//3": "The --plugin CLI flag can't pass config; a config file can. These",
6+
"//4": "entries append to whatever the flags already configure.",
7+
"//5": "ONLY unique-prefix plugins are listed — core --activitypub/--nostr",
8+
"//6": "already own /ap, /.well-known/webfinger, /.well-known/nostr.json, so",
9+
"//7": "activitypub/webfinger/nip05 plugins are DELIBERATELY absent (they'd",
10+
"//8": "collide and fail boot). forge/gallery/dashboard own fresh prefixes.",
11+
12+
"plugins": [
13+
{
14+
"module": "/home/ubuntu/plugins/forge/plugin.js",
15+
"prefix": "/forge",
16+
"config": {
17+
"//": "Behind haproxy, forge's loopback must present Host: melvin.me",
18+
"//loopback": "verify forge honors this in staging; pair with an",
19+
"//hosts": " `127.0.0.1 melvin.me` /etc/hosts entry so it stays local",
20+
"loopbackUrl": "https://melvin.me",
21+
"baseUrl": "https://melvin.me"
22+
}
23+
},
24+
{
25+
"module": "/home/ubuntu/plugins/gallery/plugin.js",
26+
"prefix": "/gallery",
27+
"config": { "loopbackUrl": "https://melvin.me", "baseUrl": "https://melvin.me" }
28+
},
29+
{
30+
"module": "/home/ubuntu/plugins/dashboard/plugin.js",
31+
"prefix": "/dashboard",
32+
"config": {}
33+
}
34+
]
35+
}

0 commit comments

Comments
 (0)