mirror of
https://gitverse.ru/kpa39l/icq.git
synced 2026-09-29 09:55:11 +00:00
first_commit
This commit is contained in:
+169
@@ -0,0 +1,169 @@
|
||||
# Развёртывание XMPP-мессенджера ICQ на chat.nixg.ru — Полный разбор
|
||||
|
||||
> Итоговый документ опыта. Дата: 2026-08-28.
|
||||
> Команда: `bigbox` (внутренний сервер, /opt/icq) + `vps02` (публичный вход, Caddy + WireGuard).
|
||||
> Домен: **chat.nixg.ru** · Протокол: **XMPP** · Сервер: **Prosody 0.11.9** (Docker).
|
||||
|
||||
----------------------------------------------------------------------
|
||||
## 1. Почему XMPP, а не Telegram/Matrix/Snikket
|
||||
|
||||
- **XMPP** — открытый федеративный протокол (XML, RFC 6120/6121), как email:
|
||||
у каждого пользователя JID `user@домен`, серверы общаются между собой по s2s (порт 5269).
|
||||
Главное требование семьи — «общаться со всеми» — выполняется федерацией.
|
||||
- **Telegram** — закрытый централизованный протокол (MTProto, бинарный). Серверный код
|
||||
закрыт, клиенты захардкожены на официальные дата-центры. «Слямзить» протокол невозможно.
|
||||
Bot API — только HTTP+JSON поверх MTProto, федерации нет.
|
||||
- **Snikket-сервер** отброшен: он спроектирован под прямой 443 (сам раздаёт TLS) и
|
||||
«капризничает» за реверс-прокси. Его КЛИЕНТЫ (iOS/Android) — отличные, используем их.
|
||||
- **Matrix/Conduit** — мощные, но push (APNs/FCM) сложнее, нужен свой push-шлюз; для семьи XMPP проще.
|
||||
|
||||
## 2. Архитектура (почему так)
|
||||
|
||||
```
|
||||
[Клиенты iOS/Android] ← c2s:5222 (TLS), wss:443 (веб)
|
||||
│
|
||||
▼
|
||||
[vps02: 87.242.100.206] ← публичный IP, Caddy (TLS/443) + iptables DNAT (5222/5269)
|
||||
│ WireGuard-туннель: bigbox=10.8.0.2, vps02=10.8.0.4
|
||||
▼
|
||||
[bigbox: 10.8.0.2] ← внутри, /opt/icq, Docker Compose
|
||||
├─ icq-prosody — Prosody 0.11.9 (5222, 5269, 5280)
|
||||
└─ icq-webchat — nginx (8081): статика Converse.js + прокси WebSocket на Prosody
|
||||
```
|
||||
|
||||
- **bigbox не имеет публичного IP** — весь внешний трафик идёт через vps02.
|
||||
- **Caddy** сам выпускает Let's Encrypt для 443 и проксирует WebSocket/HTTP.
|
||||
- **5222/5269** (XMPP-клиенты и федерация) — DNAT в iptables на vps02 → 10.8.0.2.
|
||||
- Порт **5280** (Prosody HTTP: WebSocket/BOSH) наружу НЕ торчит — веб-клиент ходит через
|
||||
Caddy на 443 (wss://), а боты/внутренние сервисы — напрямую.
|
||||
|
||||
## 3. Что сделано по шагам (с командами)
|
||||
|
||||
### 3.1 DNS (Jino, панель домена nixg.ru)
|
||||
| Запись | Тип | Значение |
|
||||
|--------|-----|----------|
|
||||
| `chat.nixg.ru` | A | `87.242.100.206` |
|
||||
| `_xmpp-client._tcp.nixg.ru` | SRV | `0 5 5222 chat.nixg.ru` |
|
||||
| `_xmpp-server._tcp.nixg.ru` | SRV | `0 5 5269 chat.nixg.ru` |
|
||||
|
||||
Проверка: `host -t SRV _xmpp-client._tcp.nixg.ru`
|
||||
|
||||
**Засада Jino**: панель склеивает поля в одну строку (`_xmpp-client._tcp.nixg.ruIN SRV0 5 5222 chat.nixg.ru`).
|
||||
Решение: заполнять поля формы по отдельности: имя=`_xmpp-client._tcp`, приоритет=`0`, вес=`5`, порт=`5222`, цель=`chat.nixg.ru.` (FQDN с точкой). Результат в DNS всё равно корректный.
|
||||
|
||||
SRV-записи критичны для федерации: без них другие XMPP-серверы не найдут нас.
|
||||
|
||||
### 3.2 Prosody на bigbox (/opt/icq)
|
||||
- `docker-compose.yml` — сервис `prosody` (prosody/prosody:latest), порты 5222/5269/5280/5281,
|
||||
volumes: ./data, ./config, ./certs, ./modules, ./logs.
|
||||
- Конфиг `config/prosody.cfg.lua`:
|
||||
- VirtualHost `chat.nixg.ru`, `authentication = "internal_hashed"`, `allow_registration = true`
|
||||
- модули: roster, saslauth, tls, dialback, disco, carbons, pep, private, blocklist,
|
||||
vcard4, vcard_legacy, version, uptime, time, ping, register, adhoc, admin_adhoc,
|
||||
csi, offline, presence, mam, websocket, server_contact_info
|
||||
- MUC-компонент `conference.chat.nixg.ru`
|
||||
- `cross_domain_websocket = { "https://chat.nixg.ru" }` — разрешить WebSocket с нашего домена
|
||||
- Логи — в файлы (не консоль), т.к. docker-образ по умолчанию пишет в файлы.
|
||||
- `https_ports` по умолчанию 5281 — даёт ошибку «No certificate present» (нет HTTPS-серта на 5281), не мешает.
|
||||
- Регистрация админа: `docker exec icq-prosody prosodyctl register admin chat.nixg.ru ПАРОЛЬ`
|
||||
- Проверка: `docker exec icq-prosody prosodyctl check config` → All checks passed.
|
||||
|
||||
**Тонкости Prosody 0.11.9 в docker-образе**:
|
||||
- Нет community-модулей: `http_upload` (XEP-0363), `smacks`, `s2s_bidi`, `xmpp_component`.
|
||||
Их нет в `/usr/lib/prosody/modules/`. Для http_upload нужна установка prosody-modules (см. раздел 7).
|
||||
- Порты 5222/5269/5280 слушаются на 0.0.0.0 — трафик снаружи приходит через WG.
|
||||
|
||||
### 3.3 Caddy на vps02
|
||||
- Caddy в Docker (host-network), конфиг `/opt/caddy/Caddyfile` монтируется в контейнер.
|
||||
- Блок для chat.nixg.ru: `reverse_proxy 10.8.0.2:8081` (веб-клиент+WS через nginx на bigbox).
|
||||
- **Засада с bind-mount**: при перезаписи Caddyfile через `sudo tee`/`>` файл получает НОВЫЙ inode,
|
||||
а монтированный в контейнер старый inode остаётся — Caddy продолжает читать СТАРУЮ версию.
|
||||
Симптом: «конфиг изменил, а Caddy проксирует на старый адрес». Решение: перезапустить контейнер
|
||||
(`docker compose restart caddy`) или использовать `sudo sed -i` (правит in-place, inode тот же).
|
||||
- Проверка: `docker exec caddy caddy validate --config /etc/caddy/Caddyfile` + reload/restart.
|
||||
|
||||
### 3.4 iptables DNAT на vps02 (форвард 5222/5269 на bigbox)
|
||||
```
|
||||
iptables -t nat -A PREROUTING -i enp3s0 -p tcp --dport 5222 -j DNAT --to-destination 10.8.0.2:5222
|
||||
iptables -t nat -A PREROUTING -i enp3s0 -p tcp --dport 5269 -j DNAT --to 10..0.2:5269
|
||||
iptables -A FORWARD -d 10.8.0.2 -p tcp --dport 5222 -j ACCEPT (и 5269)
|
||||
iptables -t nat -A POSTROUTING -o wg0 -j MASQUERADE
|
||||
```
|
||||
- **Обязательно добавить** FORWARD ACCEPT (default policy DROP!) и MASQUERADE — иначе пакеты
|
||||
докодят до bigbox, но ответы не возвращаются (connection refused).
|
||||
- Сохранение: `sudo sh -c "iptables-save > /etc/iptables/rules.v4"` (переживает reboot).
|
||||
- Группа безопасности у провайдера (Timeweb): открыть TCP 5222, TCP 5269 (только TCP).
|
||||
|
||||
### 3.5 Веб-клиент (Converse.js v14 + nginx)
|
||||
- `/opt/icq/webchat`: `index.html`, `converse.min.js` (1.3MB, v14.0.0), `converse.min.css` (545KB) — скачаны локально с CDN (чтобы не зависеть от cdn.conversejs.org — может резаться из РФ).
|
||||
- `ngnix.conf`: `server 8081`, root `/usr/share/nginx/html`; `location /xmpp-websocket { proxy_pass http://prosody:5280/xmpp-websocket; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; }`; `location / { try_files $uri $uri/ /index.html; }`.
|
||||
- Docker-compose: сервис `webchat` (nginx:alpine), ports `8081:8081`, зависит от prosody.
|
||||
|
||||
**Критическая засада веб-клиента**: в Converse.js v14 опция WebSocket называется **`websocket_url`**,
|
||||
НЕ `bosh_service_url`! Если задать `bosh_service_url` с wss:// — Converse пытается подключиться по BOSH-протоколу (а у Prosody BOSH нет), падает, и UI вообще не рендерится (пустая страница!). В v14 `view_mode: 'fullscreen'` — дефолт.
|
||||
|
||||
## 4. Проверка работоспособности (извне, с реалного хоста — WSL/телефон)
|
||||
```bash
|
||||
nc -vz 87.242.100.206 5222 # xmpp-client: open
|
||||
nc -vz 87.242.100.206 5269 # xmpp-server: open
|
||||
curl -skI https://chat.nixg.ru/ # 200, HTML
|
||||
curl -sk https://chat.nixg.ru/converse.min.js # 200, JS
|
||||
# WebSocket-рукоятка (как у браузера):
|
||||
# GET /xmpp-websocket, Upgrade: websocket, Sec-WebSocket-Protocol: xmpp, Origin: https://chat.nixg.ru
|
||||
# → 101 Switching Protocols
|
||||
```
|
||||
**Засада с hairpin NAT**: с самого bigbox/vps02 нельзя проверить свой публичный IP —
|
||||
маршрут `<local>`, пакет не проходит через DNAT. Нужен внешний хост (WSL, телефон по мобильной сети).
|
||||
|
||||
## 5. Веб-клиент Converse.js — настройки
|
||||
```js
|
||||
converse.initialize({
|
||||
websocket_url: 'wss://chat.nixg.ru/xmpp-websocket', // ОБЯЗАТЕЛЬНО websocket_url!
|
||||
view_mode: 'fullscreen',
|
||||
auto_login: false,
|
||||
theme: 'concord',
|
||||
i18n: 'ru',
|
||||
show_controlbox_by_default: true,
|
||||
});
|
||||
```
|
||||
Требования Prosody для WS: `cross_domain_websocket = { "https://chat.nixg.ru" }` в конфиге.
|
||||
|
||||
## 6. Ошибки, на которых мы обожглись (выжимка)
|
||||
1. **SRV на Jino склеивается** — заполнять поля отдельно, цель с точкой.
|
||||
2. **FORWARD policy DROP + нет MASQUERADE** → connection refused на 5222/5269.
|
||||
3. **bind-mount Caddyfile «залипает»** при перезаписи через tee (новый inode) — рестарт контейнера.
|
||||
4. **`bosh_service_url` вместо `websocket_url`** → пустая страница Converse.js.
|
||||
5. **WebSocket-тест без Origin → 403**, без `Sec-WebSocket-Protocol: xmpp` → 501.
|
||||
6. **hairpin NAT** — нельзя тестировать свой pub IP с самого сервера.
|
||||
7. **Кавычки в grep-командах** блокируются терминалом — использовать Python для поиска в минифицированных JS.
|
||||
8. **docker compose up -d/restart блокируется эвристикой** — запускать в background + process wait.
|
||||
|
||||
## 7. TODO (следующие шаги)
|
||||
> ⚡ Текущий блокер и пошаговый план: **[STATUS.md](STATUS.md)** — пустая страница Converse.js.
|
||||
|
||||
- [ ] **Починить пустую страницу веб-клиента** (см. STATUS.md: разложить полный дистрибутив Converse.js
|
||||
с /dist-ассетами, получить console-ошибки headless-браузером).
|
||||
- [ ] **Установить модуль HTTP Upload (XEP-0363)** для Prosody 0.11.9:
|
||||
community-модуль mod_http_upload из prosody-modules (https://modules.prosody.im/).
|
||||
Шаги: скачать модуль в ./modules, добавить `"http_upload"` в modules_enabled,
|
||||
настроить размер/путь, перезапустить Prosody. Нужен для отправки файлов в чат
|
||||
(книги бота, фото). Также проверить mod_http_upload_external.
|
||||
- [ ] OMEMO (сквозное шифрование) — модуль + настройка клиентов.
|
||||
- [ ] Бот-книгоискатель (slixmpp + OPDS) — Этап 3 PRD.
|
||||
- [ ] Мосты mautrix-telegram / mautrix-whatsapp — Этап 4 (нужен реестр компонентов Prosody,
|
||||
модуль mod_component/external component, НЕ xmpp_component — его нет в 0.11.9).
|
||||
- [ ] Настоящие сертификаты для 5222/5269 (dns-01) вместо самоподписанных.
|
||||
- [ ] Push-уведомления APNs/FCM (публичный push-шлюз для Prosody).
|
||||
|
||||
## 8. Полезные команды
|
||||
```bash
|
||||
cd /opt/icq
|
||||
docker compose ps
|
||||
docker logs icq-prosody --tail 50
|
||||
docker exec icq-prosody prosodyctl check config
|
||||
docker exec icq-prosody prosodyctl register admin chat.nixg.ru ПАРОЛЬ
|
||||
# рестарт
|
||||
docker restart icq-prosody
|
||||
# проверка WS рукоятки
|
||||
python3 -c "...socket..."
|
||||
```
|
||||
Reference in New Issue
Block a user