mirror of
https://gitverse.ru/kpa39l/xmpp-server-prosody.git
synced 2026-09-29 09:45:02 +00:00
80 lines
5.1 KiB
Markdown
80 lines
5.1 KiB
Markdown
# Production migration 0.11.9 → 13.0 (verified 2026-08-30, chat.nixg.ru / /opt/icq)
|
|
|
|
Live migration of the production XMPP server from Prosody 0.11.9 to 13.0
|
|
(image `gitea.nixg.ru/hermes/icq-prosody:13.0`). Complements the parallel-stand
|
|
recipe (`prosody-13-parallel-stand.md`) with the PROD-only steps and two
|
|
regressions that only surface with real bridges/users.
|
|
|
|
## Steps
|
|
1. **Backup first**: `cd /opt/icq && tar czf backups/pre-migration-13-$(date +%Y%m%d_%H%M%S).tar.gz config data certs modules webchat`
|
|
2. **Swap image** in docker-compose.yml: `prosody/prosody:latest` → `gitea.nixg.ru/hermes/icq-prosody:13.0`
|
|
(also remove obsolete top-level `version: "3.9"` — Compose v2 warns).
|
|
3. `docker compose up -d prosody` then `docker exec icq-prosody prosodyctl check config`.
|
|
|
|
## Config changes 0.11.9 → 13.0 (prod)
|
|
1. `component_ports = { 5347 }` — **REMOVED** in 13.0 (listener hardcoded on 5347; delete the line).
|
|
The module-less `Component "telegram.nixg.ru"` block already raises the listener.
|
|
2. **`"pubsub"` out of `modules_enabled`** on the VirtualHost → must be a separate
|
|
`Component "pubsub.<domain>" "pubsub"`. Without this, startup fails:
|
|
`Error initializing module 'pubsub' on '<host>': Pubsub should be loaded as a component`.
|
|
3. **HTTP Upload regression — Slidge gets "No upload slot"**:
|
|
- Symptom: slidge logs floods of `No upload slot in this IQ: <iq xmlns="jabber:client" id="0" />`
|
|
(~180 / 10 min on a busy bridge). Attachments (images/videos) silently fail.
|
|
- Cause: the 13.0-era community mod_http_upload only hands out slots to
|
|
`origin.type == "c2s"` **or** JIDs in `http_upload_access`. A Slidge external
|
|
component requests slots as a component → denied → empty result IQ.
|
|
- Fix, inside the upload component block:
|
|
```lua
|
|
Component "upload.<domain>" "http_upload"
|
|
http_upload_access = { "telegram.<domain>" }
|
|
```
|
|
- After fix: 0 errors. (`docker logs icq-slidgram --since 2m | grep -c "No upload slot"` = 0.)
|
|
4. `cross_domain_websocket` is deprecated in 13.0 but STILL read by mod_websocket → keep it.
|
|
(New mechanism is `http_cors_override`; no need to migrate yet.)
|
|
5. Single global `log` block (13.0 tolerates only one).
|
|
|
|
## Post-migration verification (no client password needed)
|
|
- `prosodyctl check config` → All checks passed.
|
|
|
|
## WebSocket SASL regression after 13.0: "no-auth-mech" / blank spinner
|
|
|
|
**Symptom:** Converse.js on https://chat.nixg.ru shows the login form for a split
|
|
second, then an infinite white spinner. Browser devtools on the WS frame shows
|
|
`<failure><no-auth-mech/></failure>` or the server offers NO SASL mechanisms.
|
|
Prosody logs flood every ~1s with:
|
|
`warn No stream features to offer on insecure session. Check encryption and security settings.`
|
|
|
|
**Cause:** TLS is terminated at the edge (Caddy → nginx → Prosody over plain HTTP
|
|
:5280), so the WebSocket session arrives at Prosody as *insecure*. In 13.0
|
|
mod_websocket only offers SASL on secure sessions; insecure → empty `<stream:features>`
|
|
→ client cannot authenticate and reconnects forever. (On 0.11.x this silently worked.)
|
|
|
|
**Fix:** in the GLOBAL config section (before VirtualHost), set
|
|
```lua
|
|
consider_websocket_secure = true
|
|
```
|
|
This is mod_websocket's own option (`module:get_option_boolean("consider_websocket_secure")`,
|
|
mod_websocket.lua:35, 286 — `session.secure = consider_websocket_secure or request.secure or session.secure`).
|
|
- `trusted_proxies` does NOT fix this — it only affects IP/logging, not session secure-ness.
|
|
- Do NOT set `c2s_require_encryption = false` — that would allow plaintext passwords on
|
|
the external 5222 port. The webchat path is already TLS all the way to the browser.
|
|
|
|
**Verify:** after restart, prosody.log shows
|
|
`Authenticated as user@nixg.ru [prosody:operator]` for WS logins and the
|
|
`No stream features...` warnings stop. Headless check:
|
|
`chromium --headless --no-sandbox --disable-gpu --virtual-time-budget=20000 --dump-dom https://chat.nixg.ru/ | grep -c converse-login-form` → 1.
|
|
- Component auth: `grep "External component successfully authenticated" prosody.log` (timestamp after restart).
|
|
- mod_privilege XEP-0356 live: `grep "privilege" prosody.log | grep "Archiving stanza"` — slidge-carbon-*
|
|
stanza entries prove privileged message/roster delivery works on prod.
|
|
- WebSocket path: raw handshake to the webchat port → `101 Switching Protocols` confirms nginx → Prosody 13.0.
|
|
- SASL logic: slixmpp/raw connect with a WRONG password → `AUTH FAILED` proves the auth chain works.
|
|
(Do not connect a second component with the same JID as the live bridge — Prosody logs
|
|
`Second component attempted to connect, denying connection`; that is normal, not an error.)
|
|
|
|
## Gotchas
|
|
- `docker exec icq-prosody sh -c 'ss/netstat...'` may show nothing if net-tools absent — rely on
|
|
`prosody.log` ("Servers started", "Certificates loaded") and external handshakes instead.
|
|
- Test-stand teardown for "stop until next update" (NOT delete):
|
|
`docker stop icq-prosody-test && docker update --restart=no icq-prosody-test`.
|
|
- Prod was re-verified healthy after: prosody/slidgram/webchat all Up, 0 upload errors.
|