docs+fix: no-auth-mech на Prosody 13.0 — consider_websocket_secure=true (WS insecure после миграции); опыт в STATUS/WALKTHROUGH

This commit is contained in:
2026-08-30 15:13:36 +00:00
parent 4655d82f6e
commit 6a4ccd3e6d
3 changed files with 126 additions and 20 deletions
+47 -18
View File
@@ -1,10 +1,11 @@
# ICQ XMPP — ТЕКУЩИЙ СТАТУС И ПЛАН (точка входа для новой сессии) # ICQ XMPP — ТЕКУЩИЙ СТАТУС И ПЛАН (точка входа для новой сессии)
> Обновлено: 2026-08-29 (вечер) · Сессия: bigbox (/opt/icq) > Обновлено: 2026-08-30 · Сессия: bigbox (/opt/icq)
## Проект ## Проект
Self-hosted XMPP-мессенджер на **nixg.ru** (Prosody 0.11.9 + веб-клиент Converse v14 + мост Telegram). Self-hosted XMPP-мессенджер на **nixg.ru** (Prosody **13.0** + веб-клиент Converse v14 + мост Telegram).
Миграция на nixg.ru (2026-08-28): JID юзеров `user@nixg.ru`, веб-клиент chat.nixg.ru, WS wss://xmpp.nixg.ru. Миграция на nixg.ru (2026-08-28): JID юзеров `user@nixg.ru`, веб-клиент chat.nixg.ru, WS wss://xmpp.nixg.ru.
Апгрейд Prosody 0.11.9 → **13.0** (2026-08-30): образ gitea.nixg.ru/hermes/icq-prosody:13.0.
**Документация:** **Документация:**
- [INFRA.md](INFRA.md) — инфраструктура, DNS, учётные данные, TLS/LE, бэкапы - [INFRA.md](INFRA.md) — инфраструктура, DNS, учётные данные, TLS/LE, бэкапы
@@ -23,30 +24,58 @@ Self-hosted XMPP-мессенджер на **nixg.ru** (Prosody 0.11.9 + веб-
- ✅ **TG-аккаунт привязан к мосту (2026-08-29)**: estorozhenko@nixg.ru → команда register из Pidgin, номер +792****2181, api_id/api_hash из конфига. Логин OK, контакты и аватары синхронизируются. - ✅ **TG-аккаунт привязан к мосту (2026-08-29)**: estorozhenko@nixg.ru → команда register из Pidgin, номер +792****2181, api_id/api_hash из конфига. Логин OK, контакты и аватары синхронизируются.
- ✅ Пользователи: admin@nixg.ru, estorozhenko@nixg.ru (оба входят); самостоятельная регистрация ОТКЛЮЧЕНА - ✅ Пользователи: admin@nixg.ru, estorozhenko@nixg.ru (оба входят); самостоятельная регистрация ОТКЛЮЧЕНА
- ✅ **Админы сервера** (2026-08-29): `admins = { "admin@nixg.ru", "estorozhenko@nixg.ru" }` — оба могут ad-hoc команды - ✅ **Админы сервера** (2026-08-29): `admins = { "admin@nixg.ru", "estorozhenko@nixg.ru" }` — оба могут ad-hoc команды
- ✅ **Параллельный стенд Prosody 13.0 ПОДТВЕРЖДЁН** (2026-08-30, /opt/icq/test, контейнер icq-prosody-test):
авторизация (3 юзера OK + неверный пароль отклонён) и mod_privilege XEP-0356 (roster IQ → result)
работают на 13.0. Образ: gitea.nixg.ru/hermes/icq-prosody:13.0. → Основа для миграции прода.
- ✅ **Прод на Prosody 13.0** (2026-08-30): мигрирован, всё работает (см. «Выполнено» ниже).
Тестовый стенд остановлен (icq-prosody-test, --restart=no) до следующего обновления.
## Задачи (будущее) ## Задачи (будущее)
- [ ] ~~**Регистрация TG-аккаунта в мосте**~~ — ВЫПОЛНЕНО 2026-08-29 (estorozhenko@nixg.ru)
- [x] ~~**Вопрос про каналы/папки TG в рostере**~~ — РЕШЕНО/ОТВЕЧЕНО 2026-08-29 (вечер): ### ✅ ВЫПОЛНЕНО: миграция прода на Prosody 13.0 (2026-08-30)
каналов в рostере XMPP НЕТ и быть не может (роster = личные контакты, 1602 шт.). - [x] **Прод nixg.ru мигрирован с 0.11.9 на 13.0** (образ gitea.nixg.ru/hermes/icq-prosody:13.0):
Каналы/группы (91+40) живут в БД моста (room), в XMPP — через bookmarks (сломаны из-за авторизация OK, mod_privilege XEP-0356 работает (Archiving stanza в логах),
mod_privilege-стаба). Папки Telegram слайдж не поддерживает (TODO в session.py:292). WebSocket 101 через nginx, компонент telegram.nixg.ru аутентифицирован,
Подробности: WALKTHROUGH §12.9. HTTP Upload исправлен (`http_upload_access = { "telegram.nixg.ru" }` — регрессия 13.0,
слоты выдавались только c2s; без фикса — «No upload slot» у Slidge).
Детали миграции: WALKTHROUGH.md (новый раздел) + референс prosody-13-parallel-stand.md.
Изменения конфига под 13.0: pubsub → Component "pubsub.nixg.ru", component_ports удалён.
- [x] **Тестовый стенд /opt/icq/test ОСТАНОВЛЕН (не удалён)** — контейнер icq-prosody-test
`docker stop` + `--restart=no`; поднять снова при следующем обновлении.
- [ ] **module:send_iq фикс mod_privilege на проде (опция)** — если миграция 13.0 откладывается:
стаб-ACK (коммит 770c9fa) остаётся; полного XEP-0356 на 0.11.9 нет (API 0.12).
### Прочее (не критично)
- [ ] **ИДЕЯ: папки Telegram → подгруппы в ростере моста** (2026-08-30): все TG-контакты сейчас
скопом в группе «Telegram». Предложение: при подключении к мосту читать список папок/каталогов
из Telegram (архивы/папки чатов) и создавать соответствующие подгруппы в каталоге моста,
раскладывая контакты по ним. НО: при 2–3-минутном лаге логина (массовый рендер ростера
на 1602 контакта) это усугубит старт — реализация только вместе с ускорением рендера.
См. BRIDGE-TELEGRAM.md «Наблюдения». Отложено.
- [ ] **Разобраться с рендером 1600 TG-контактов в рostере при каждом логине клиента** (2026-08-30):
клиент заново скачивает весь рostер + Slidge шлёт presence по всем контактам → 2–3 мин
и «пик в сети» по каждому. Это специфика Slidge, НЕ баг (серверный рostер цел). Идеи:
проверить, можно ли в Slidge отложить/пропустить массовый рoster-рендер при login
(свойства :poll-чатов, cache), и не дёргается ли зря. См. BRIDGE-TELEGRAM.md «Наблюдения».
- [ ] **Аватары TG в мосте таймаутят** — HTTP-часть slidge не ходит через SOCKS5 (URL web.telegram.org - [ ] **Аватары TG в мосте таймаутят** — HTTP-часть slidge не ходит через SOCKS5 (URL web.telegram.org
недоступны из РФ). Косметика, на переписку не влияет. Разбор и варианты: BRIDGE-TELEGRAM.md. недоступны из РФ). Косметика, на переписку не влияет. Разбор и варианты: BRIDGE-TELEGRAM.md.
- [ ] **Сборка Prosody 0.12.x (система сборки)** — ЗАПЛАНИРОВАНО (сделать позже): - [ ] **Бот-книгоискатель (slixmpp + OPDS)** — Этап 3 PRD. (venv готов: /opt/icq/.venv)
официальный Docker-образ не имеет 0.12 (latest=0.11.9); сторонние nightly не годятся. - [ ] **Мост mautrix (WhatsApp)** — Этап 4; нужен external component. [Telegram уже на Slidge]
Собрать свой образ из исходников prosody-0.12.6.tar.gz (WALKTHROUGH §12.8). - [ ] **Push-уведомления** — после апгрейда 13.0 (util.jwt нативный); варианты — WALKTHROUGH §10.4
Закроет: нативный XEP-0356 (mod_privilege больше не нужен → «миллион приглашений» - [ ] **MAM: ошибка при логине «max_items: not a number»** — проверить настройку mod_mam (не мешает чату)
в Pidgin исчезнет, bookmarks заработают), push-уведомления (util.jwt), безопасность.
- [ ] Бот-книгоискатель (slixmpp + OPDS) — Этап 3 PRD. (venv готов: /opt/icq/.venv)
- [ ] Мост mautrix (WhatsApp) — Этап 4; нужен external component. [Telegram уже на Slidge]
- [ ] Push-уведомления — ОТЛОЖЕН до апгрейда 0.12 (нужен util.jwt); варианты — WALKTHROUGH §10.4
- [ ] MAM: ошибка при логине «max_items: not a number» — проверить настройку mod_mam (не мешает чату)
## Известные грабли (2026-08-29) ## Известные грабли (2026-08-29)
- ✅ **РЕШЕНО 2026-08-30: «no-auth-mech» / белый кружок в веб-чате после миграции на 13.0** —
Prosody 13 считает WS-сессию insecure (TLS на edge: Caddy→nginx→Prosody plain 5280),
не предлагает SASL («No stream features to offer on insecure session»), Converse
бесконечно переподключается. ФИКС: `consider_websocket_secure = true` (глобальная
секция prosody.cfg.lua). НЕ использовать `c2s_require_encryption=false` (дыра в 5222).
Детали: референс prosody-13-production-migration.md в скилле xmpp-server-prosody.
- mod_privilege (XEP-0356) сломан на 0.11.9 (module:send_iq — API 0.12). Стоит стаб-ACK (коммит 770c9fa): - mod_privilege (XEP-0356) сломан на 0.11.9 (module:send_iq — API 0.12). Стоит стаб-ACK (коммит 770c9fa):
Prosody стабилен, но bookmarks/MDS через XEP-0356 не работают → слайдж шлёт приглашения в группы вручную. Prosody стабилен, но bookmarks/MDS через XEP-0356 не работают → слайдж шлёт приглашения в группы вручную.
Полное решение — апгрейд 0.12. Детали: WALKTHROUGH §12.7. Полное решение — апгрейд 13.0 (ПОДТВЕРЖДЁН на стенде, см. задачи). Детали: WALKTHROUGH §12.7.
- ⚠️ ВАЖНО 13.0: в компонентной сессии НЕТ `full_jid` (только host), mod_privilege tip-версии логирует
«Entity nil» — это НЕ ошибка привилегий, просто лог. Привилегии выдаются корректно (см. стенд).
- Рostер TG-контактов цел на сервере (1602). Если контакты «пропали» в Pidgin после рестарта — - Рostер TG-контактов цел на сервере (1602). Если контакты «пропали» в Pidgin после рестарта —
Disable/Enable аккаунта (клиент сам скачает рostер). Не трогать сервер. Disable/Enable аккаунта (клиент сам скачает рostер). Не трогать сервер.
+61
View File
@@ -120,6 +120,27 @@ iptables -t nat -A POSTROUTING -o wg0 -j MASQUERADE
- `location / { try_files $uri $uri/ /index.html; }` - `location / { try_files $uri $uri/ /index.html; }`
- Docker-compose: сервис `webchat` (nginx:alpine), ports `8081:8081`, volume `./webchat:/usr/share/nginx/html:ro`. - Docker-compose: сервис `webchat` (nginx:alpine), ports `8081:8081`, volume `./webchat:/usr/share/nginx/html:ro`.
**ЗАСАДА: DNS-кэш nginx → Connection refused на /xmpp-websocket (инцидент 2026-08-30)**.
Симптом: chat.nixg.ru открывается, форма логина мелькает, Converse висит на пульсирующем белом
кружке (спиннер connecting). В логах icq-webchat каждую минуту:
`connect() failed (111: Connection refused) ... upstream http://172.27.0.2:5280/xmpp-websocket`.
Причина: nginx резолвит имя `prosody` ОДИН раз при старте и держит IP вечно.
После пересоздания контейнеров (prosody, slidgram) docker присваивает адреса заново —
старый IP (172.27.0.2) переходит к ДРУГОМУ контейнеру (slidgram), prosody уезжает на .4.
nginx же продолжает слать на закешированный .2 → refused → 502 → спиннер.
Лечение: `docker compose restart webchat` (пере-резолв). Профилакт — динамический resolver:
```
nginx
resolver 127.0.11 valid=30s ipv6=off; # docker embedded DNS
location /xmpp-websocket {
set $prosody_upstream http://prosody:5280;
proxy_pass $prosody_upstream/xmpp-websocket;
...
}
```
Без переменной + resolver nginx не пере-резолвит на лету. Патч применён (2026-08-30),
в `webchat/nginx.conf`.
**Критическая засада веб-клиента**: в Converse.js v14 опция WebSocket называется **`websocket_url`**, **Критическая засада веб-клиента**: в Converse.js v14 опция WebSocket называется **`websocket_url`**,
НЕ `bosh_service_url`! Если задать `bosh_service_url` с wss:// — Converse пытается подключиться по BOSH НЕ `bosh_service_url`! Если задать `bosh_service_url` с wss:// — Converse пытается подключиться по BOSH
(а у Prosody BOSH нет), падает, UI не рендерится (пустая страница!). (а у Prosody BOSH нет), падает, UI не рендерится (пустая страница!).
@@ -223,6 +244,13 @@ curl -sS https://xmpp.nixg.ru/.well-known/host-meta # 200 JSON XEP-0156
12. **dpkg прерван / apt exit 127** — сломан `chromium-browser` (snap-transitional); чинить `dpkg --configure -a` + переустановка. 12. **dpkg прерван / apt exit 127** — сломан `chromium-browser` (snap-transitional); чинить `dpkg --configure -a` + переустановка.
13. **git: .venv попал в историю** — venv НЕ коммитить (в .gitignore), удалять из истории 13. **git: .venv попал в историю** — venv НЕ коммитить (в .gitignore), удалять из истории
filter-branch + force-push (репо похудел с 22MB до 216K). filter-branch + force-push (репо похудел с 22MB до 216K).
14. **Prosody 13.0: WS-сессия «insecure» → «no-auth-mech» (2026-08-30)** — после миграции
на 13.0 веб-чат сломался: форма мелькает, белый кружок, `No stream features to offer
on insecure session` в логах, бесконечные переподключения. TLS терминируется на edge
(Caddy→nginx→Prosody plain 5280) → 13.0 не предлагает SASL на «insecure» WS.
ФИКС (глобальная секция prosody.cfg.lua): `consider_websocket_secure = true`.
НЕ ставить `c2s_require_encryption=false` (дыра в 5222: plaintext-пароли).
Проверка: `Authenticated as user@nixg.ru [prosody:operator]` в логах после входа по WS.
## 7. HTTP Upload (XEP-0363) — mod_http_upload ## 7. HTTP Upload (XEP-0363) — mod_http_upload
@@ -651,6 +679,39 @@ JSON содержит `"always_invite_when_adding_bookmarks": true` — слай
(после апгрейда 0.12). Пока слайдж-стаб не чинит bookmarks, приглашения — единственный (после апгрейда 0.12). Пока слайдж-стаб не чинит bookmarks, приглашения — единственный
способ «увидеть» каналы, их можно игнорировать в Pidgin. способ «увидеть» каналы, их можно игнорировать в Pidgin.
## 12.8. МИГРАЦИЯ ПРОДА НА PROSODY 13.0 (2026-08-30)
Прод nixg.ru переведён с 0.11.9 на 13.0 (образ `gitea.nixg.ru/hermes/icq-prosody:13.0`).
Стенд подтверждал совместимость заранее (references/prosody-13-parallel-stand.md).
**Шаги и изменения конфига (что отличается от 0.11.9):**
1. Бэкап перед миграцией: `tar czf backups/pre-migration-13-*.tar.gz config data certs modules webchat`.
2. docker-compose: `image: gitea.nixg.ru/hermes/icq-prosody:13.0` (вместо `prosody/prosody:latest`).
3. `component_ports = { 5347 }` — **УДАЛЁН** в 13.0 (listener жёстко на 5347). Убрать.
Listener поднимает module-less `Component "telegram.nixg.ru"`-блок (уже был).
4. `"pubsub"` из `modules_enabled` VirtualHost — **УБРАТЬ**: в 13.0 mod_pubsub только как Component.
Добавлен `Component "pubsub.nixg.ru" "pubsub"` (bookmarks/ленты).
Ошибка до фикса: `Pubsub should be loaded as a component`.
5. **РЕГРЕССИЯ http_upload**: slidge получал `No upload slot in this IQ: <iq ... id="0" />` —
в 13.0-версии mod_http_upload слот выдаётся только `origin.type=="c2s"` ИЛИ JID из
`http_upload_access`. Slidge просит слот от имени компонента → добавить:
`http_upload_access = { "telegram.nixg.ru" }` в блок `Component "upload.nixg.ru"`.
До фикса 180 ошибок/10 мин; после — 0.
6. `cross_domain_websocket` — deprecated (варнинг), но всё ещё читается mod_websocket → работает.
Можно оставить; новый механизм — `http_cors_override`.
7. Лог: один блок `log` в глобальной секции (в 13.0 строго один).
**Проверка после миграции:**
- `prosodyctl check config` → All checks passed.
- `External component successfully authenticated` для telegram.nixg.ru в prosody.log.
- mod_privilege: в логе `nixg.ru:privilege ... Archiving stanza` (slidge-carbon-*) — работает.
- WebSocket: рукопожатие → `101 Switching Protocols` через nginx (Chat работает).
- HTTP Upload: 0 ошибок `No upload slot` после рестарта.
- Авторизация: SASL отвечает на неверный пароль AUTH FAILED (логика работает).
**Тестовый стенд** /opt/icq/test (icq-prosody-test) ОСТАНОВЛЕН: `docker stop` + `docker update --restart=no`.
Поднять при следующем обновлении: `cd /opt/icq/test && docker compose up -d`.
## 13. TODO (следующие шаги) ## 13. TODO (следующие шаги)
- [x] ~~OMEMO (XEP-0384)~~ — ВЫПОЛНЕНО: раздел 9; скрипт scripts/omemo_check.py. - [x] ~~OMEMO (XEP-0384)~~ — ВЫПОЛНЕНО: раздел 9; скрипт scripts/omemo_check.py.
- [ ] Бот-книгоискатель (slixmpp + OPDS) — Этап 3 PRD. venv уже создан (/opt/icq/.venv: aiohttp, slixmpp). - [ ] Бот-книгоискатель (slixmpp + OPDS) — Этап 3 PRD. venv уже создан (/opt/icq/.venv: aiohttp, slixmpp).
+18 -2
View File
@@ -28,7 +28,7 @@ modules_enabled = {
"carbons"; -- Копии сообщений на все устройства "carbons"; -- Копии сообщений на все устройства
"privilege"; -- XEP-0356 Privileged Entity (roster sync для мостов Slidge) "privilege"; -- XEP-0356 Privileged Entity (roster sync для мостов Slidge)
"pep"; -- Personal eventing (OMEMO, avatars) "pep"; -- Personal eventing (OMEMO, avatars)
"pubsub"; -- Publish-Subscribe (XEP-0060): ленты, узлы; основа PEP/bookmarks -- "pubsub"; -- 13.0: НЕ модуль хоста! Загружается как Component (см. ниже Component "pubsub.nixg.ru")
"private"; -- Приватные хранилища XML "private"; -- Приватные хранилища XML
"blocklist"; -- Чёрный список "blocklist"; -- Чёрный список
"vcard4"; -- vCard 4 "vcard4"; -- vCard 4
@@ -79,7 +79,8 @@ https_ports = { 5281 }
https_interfaces = { "0.0.0.0" } https_interfaces = { "0.0.0.0" }
-- External components (XEP-0114) для мостов (Slidge/Telegram, затем WhatsApp) -- External components (XEP-0114) для мостов (Slidge/Telegram, затем WhatsApp)
component_ports = { 5347 } -- ВНИМАНИЕ 13.0: component_ports УДАЛЁН (слушатель жёстко на 5347). Listener поднимается
-- наличием module-less Component-блока ниже. component_interfaces — глобально.
component_interfaces = { "0.0.0.0" } component_interfaces = { "0.0.0.0" }
component_secrets = { component_secrets = {
["telegram.nixg.ru"] = "83276db6e870f540163f271d9bd7d3a390530b9ad7b45f58", ["telegram.nixg.ru"] = "83276db6e870f540163f271d9bd7d3a390530b9ad7b45f58",
@@ -94,6 +95,13 @@ ssl = {
-- Разрешить WebSocket-подключения с нашего веб-клиента (страница на chat.nixg.ru) -- Разрешить WebSocket-подключения с нашего веб-клиента (страница на chat.nixg.ru)
cross_domain_websocket = { "https://chat.nixg.ru", "https://xmpp.nixg.ru" } cross_domain_websocket = { "https://chat.nixg.ru", "https://xmpp.nixg.ru" }
-- WebSocket за TLS-прокси (Caddy → nginx → Prosody): Prosody 13 терминально снижает
-- TLS на edge, и WS-сессия приходит "insecure" → SASL-механизмы не предлагаются →
-- Converse: "no-auth-mech" + бесконечные переподключения (белый кружок).
-- Штатный флаг mod_websocket (Prosody 13+): считать WS endpoint безопасным.
-- Использовать вместо trusted_proxies (тот влияет только на логирование IP).
consider_websocket_secure = true
-- Домен (JID юзеров: user@nixg.ru) -- Домен (JID юзеров: user@nixg.ru)
VirtualHost "nixg.ru" VirtualHost "nixg.ru"
-- Аутентификация: внутренняя (mod_auth_internal_hashed) -- Аутентификация: внутренняя (mod_auth_internal_hashed)
@@ -121,6 +129,10 @@ VirtualHost "nixg.ru"
}; };
} }
-- PubSub (XEP-0060) — в 13.0 ТОЛЬКО как Component (не модуль хоста).
-- Основа для bookmarks/лент; PEP (личные узлы) продолжает жить на VirtualHost через mod_pep.
Component "pubsub.nixg.ru" "pubsub"
-- MUC-компонент (групповые чаты) conference.nixg.ru -- MUC-компонент (групповые чаты) conference.nixg.ru
Component "conference.nixg.ru" "muc" Component "conference.nixg.ru" "muc"
name = "ICQ Family Chat" name = "ICQ Family Chat"
@@ -135,6 +147,10 @@ Component "upload.nixg.ru" "http_upload"
http_upload_file_size_limit = 10 * 1024 * 1024 -- 10 MB (лимит HTTP-парсера Prosody) http_upload_file_size_limit = 10 * 1024 * 1024 -- 10 MB (лимит HTTP-парсера Prosody)
http_upload_expire_after = 7 * 24 * 60 * 60 -- хранить 7 дней http_upload_expire_after = 7 * 24 * 60 * 60 -- хранить 7 дней
http_upload_require_authentication = true -- только авторизованные http_upload_require_authentication = true -- только авторизованные
-- 13.0: слот выдаётся ТОЛЬКО origin.type=="c2s" ИЛИ JID из access-списка.
-- Slidge просит слот от имени компонента telegram.nixg.ru → добавить в access,
-- иначе "No upload slot" (регрессия 13.0, в 0.11 пускало компоненты молча).
http_upload_access = { "telegram.nixg.ru" }
http_upload_path = "/var/lib/prosody/http_upload" http_upload_path = "/var/lib/prosody/http_upload"
-- Внешний URL (без :5281) — Caddy на vps02 проксирует upload.nixg.ru → 10.8.0.2:5281 -- Внешний URL (без :5281) — Caddy на vps02 проксирует upload.nixg.ru → 10.8.0.2:5281
http_external_url = "https://upload.nixg.ru" http_external_url = "https://upload.nixg.ru"