# Jabogram XMPP-сервер для мессенджера с поддержкой голосовых/видеозвонков и хранением медиафайлов в S3. **Стек:** - [Snikket](https://snikket.org/) (Prosody) — XMPP-сервер - PostgreSQL 17 — хранение данных Prosody - rclone — монтирование S3-бакета как локальной директории - Docker Compose — оркестрация сервисов --- ## Структура репозитория ``` jabogram/ ├── server/ # Docker Compose + конфиги Snikket/Prosody │ ├── scripts/ # Скрипты управления пользователями │ └── ... └── s3-mount/ # Скрипты монтирования S3 через rclone ``` --- ## Установка с нуля ### 1. Требования к серверу - Ubuntu 22.04+ (или Debian 12+) - Docker + Docker Compose plugin - Публичный IP-адрес - Домен, указывающий на этот IP ### 2. DNS-записи Создайте три записи для вашего домена (замените `chat.example.org` на свой): | Тип | Имя | Значение | |-------|----------------------------|--------------------| | A | `chat.example.org` | IP-адрес сервера | | CNAME | `groups.chat.example.org` | `chat.example.org` | | CNAME | `share.chat.example.org` | `chat.example.org` | Записи должны быть активны до первого запуска — они нужны для получения TLS-сертификатов. ### 3. Настройка файрвола ```bash ufw allow 80/tcp ufw allow 443/tcp ufw allow 5222/tcp # XMPP client-to-server ufw allow 5269/tcp # XMPP server-to-server (федерация) ufw allow 5000/tcp # Proxy65 (передача файлов) ufw allow 3478/udp ufw allow 3478/tcp # STUN/TURN ufw allow 5349/tcp ufw allow 5349/udp # TURNS (TURN over TLS) ufw allow 49152:65535/udp # TURN relay (аудио/видео) ``` ### 4. Монтирование S3 через rclone S3-бакет монтируется в `/mnt/snikket-files` и пробрасывается в контейнер Snikket — именно туда сохраняются файлы, загруженные через XMPP (XEP-0363 HTTP File Upload). #### 4.1. Установка rclone и fuse3 ```bash cd s3-mount sudo bash install-rclone.sh ``` Скрипт установит `fuse3`, скачает и установит `rclone`, после чего запустит `rclone config` для интерактивной настройки удалённого хранилища. При конфигурации создайте remote с именем `jabogram-vk` (или измените имя в `rclone-snikket.service`), выбрав тип `s3` и указав ключи доступа к вашему S3-совместимому хранилищу. #### 4.2. Настройка systemd-сервиса Отредактируйте `s3-mount/rclone-snikket.service` при необходимости — проверьте путь к бакету: ```ini ExecStart=/usr/bin/rclone mount \ jabogram-vk:jabogram/http_file_share \ # :/ /mnt/snikket-files \ ... ``` Установите сервис: ```bash cd s3-mount sudo bash install-service.sh ``` Сервис запустится автоматически и будет стартовать при загрузке системы раньше Docker. Проверьте монтирование: ```bash systemctl status rclone-snikket ls /mnt/snikket-files ``` ### 5. Настройка сервера ```bash cd server ``` #### 5.1. snikket.conf ```bash cp snikket.conf.example snikket.conf ``` Обязательно задайте: ```ini SNIKKET_DOMAIN=chat.example.org # ваш домен (нельзя изменить после первого запуска!) SNIKKET_ADMIN_EMAIL=you@example.org # email для Let's Encrypt ``` #### 5.2. prosody.cfg.lua ```bash cp prosody.cfg.lua.example prosody.cfg.lua ``` Замените `chat.example.org` на свой домен в строке: ```lua http_upload_external_base_url = "http://chat.example.org:5050/upload/" ``` > Файл монтируется в контейнер Snikket как `/etc/prosody/conf.d/custom.cfg.lua` и задаёт PostgreSQL-бэкенд и внешний обработчик загрузки файлов. #### 5.3. secrets.env ```bash cp secrets.env.example secrets.env ``` Заполните реальными значениями: ```ini UPLOAD_SECRET=случайная-строка-32-символа AWS_ACCESS_KEY_ID=ваш-ключ AWS_SECRET_ACCESS_KEY=ваш-секретный-ключ POSTGRES_PASSWORD=надёжный-пароль ``` > `UPLOAD_SECRET` должен совпадать с `http_upload_external_secret` в `prosody.cfg.lua` — они уже связаны через `os.getenv("UPLOAD_SECRET")`. #### 5.4. docker-compose.yml — путь монтирования файлов В `docker-compose.yml` найдите строку вида: ```yaml - /mnt/snikket-files:/snikket/prosody/share%2ejbr%2ebvn13%2eme/http_file_share ``` Часть `share%2ejbr%2ebvn13%2eme` — это URL-encoded путь вида `share.<домен>`. Замените на свой домен: ```yaml - /mnt/snikket-files:/snikket/prosody/share%2echat%2eexample%2eorg/http_file_share ``` Правило кодирования: каждая точка `.` заменяется на `%2e`. ### 6. Первый запуск ```bash cd server docker compose up -d ``` Подождите ~30 секунд, пока Snikket получит TLS-сертификаты. Затем создайте администратора: ```bash docker exec snikket create-invite --admin --group default ``` Команда выведет инвайт-ссылку вида `https://chat.example.org/invite/...` — откройте её в браузере для регистрации первого администратора. --- ## Управление пользователями Все скрипты находятся в `server/scripts/` и читают `SNIKKET_DOMAIN` из `snikket.conf`. | Скрипт | Действие | |-----------------------|---------------------------------------| | `invite-new.sh` | Создать инвайт для обычного пользователя | | `invite-new-admin.sh` | Создать инвайт для администратора | | `invite-list.sh` | Показать список инвайтов | | `invite-revoke.sh` | Отозвать инвайт | | `user-delete.sh` | Удалить пользователя | | `cmd.sh` | Выполнить произвольную команду prosodyctl | --- ## Обновление ```bash cd server docker compose pull docker compose up -d ``` --- ## Бэкап ```bash cd server # Данные Snikket (аккаунты, сертификаты, настройки) docker run --rm \ -v jabogram_snikket_data:/data \ -v $(pwd):/backup \ alpine tar czf /backup/snikket-backup.tar.gz -C /data . # База данных PostgreSQL docker exec snikket-postgres pg_dump -U snikket snikket \ | gzip > snikket-pg-backup.sql.gz ``` Медиафайлы хранятся в S3-бакете и бэкапируются отдельно средствами вашего S3-провайдера. --- ## Архитектура хранения файлов ``` XMPP-клиент │ │ 1. Запрос слота (XEP-0363) ▼ Prosody (mod_http_upload_external) │ │ 2. Выдаёт подписанный URL → http://chat.example.org:5050/upload/... ▼ s3_upload_handler (порт 5050) │ │ 3. Проверяет HMAC, сохраняет файл в S3 │ (или через /mnt/snikket-files, смонтированный rclone) ▼ S3-бакет ``` --- ## Открытые порты | Порт | Протокол | Назначение | |---------------|----------|--------------------------------| | 80 | TCP | HTTP (ACME, редирект на HTTPS) | | 443 | TCP | HTTPS (веб-портал, файлы) | | 5222 | TCP | XMPP client-to-server | | 5269 | TCP | XMPP server-to-server | | 5000 | TCP | Proxy65 (передача файлов) | | 5050 | TCP | S3 upload handler | | 3478, 5349 | TCP+UDP | STUN/TURN (звонки) | | 49152–65535 | UDP | TURN relay (аудио/видео) |