2026-03-24 09:24:25 +03:00
2026-02-27 00:32:28 +03:00
2026-03-02 14:46:34 +03:00
2026-03-24 09:24:25 +03:00
2026-03-21 00:14:22 +03:00
2026-02-27 00:32:28 +03:00

Jabogram

XMPP-сервер для мессенджера с поддержкой голосовых/видеозвонков и хранением медиафайлов в S3.

Стек:

  • Snikket (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. Настройка файрвола

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

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 при необходимости — проверьте путь к бакету:

ExecStart=/usr/bin/rclone mount \
    jabogram-vk:jabogram/http_file_share \   # <remote>:<bucket>/<path>
    /mnt/snikket-files \
    ...

Установите сервис:

cd s3-mount
sudo bash install-service.sh

Сервис запустится автоматически и будет стартовать при загрузке системы раньше Docker.

Проверьте монтирование:

systemctl status rclone-snikket
ls /mnt/snikket-files

5. Настройка сервера

cd server

5.1. snikket.conf

cp snikket.conf.example snikket.conf

Обязательно задайте:

SNIKKET_DOMAIN=chat.example.org     # ваш домен (нельзя изменить после первого запуска!)
SNIKKET_ADMIN_EMAIL=you@example.org # email для Let's Encrypt

5.2. prosody.cfg.lua

cp prosody.cfg.lua.example prosody.cfg.lua

Замените chat.example.org на свой домен в строке:

http_upload_external_base_url = "http://chat.example.org:5050/upload/"

Файл монтируется в контейнер Snikket как /etc/prosody/conf.d/custom.cfg.lua и задаёт PostgreSQL-бэкенд и внешний обработчик загрузки файлов.

5.3. secrets.env

cp secrets.env.example secrets.env

Заполните реальными значениями:

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 найдите строку вида:

- /mnt/snikket-files:/snikket/prosody/share%2ejbr%2ebvn13%2eme/http_file_share

Часть share%2ejbr%2ebvn13%2eme — это URL-encoded путь вида share.<домен>. Замените на свой домен:

- /mnt/snikket-files:/snikket/prosody/share%2echat%2eexample%2eorg/http_file_share

Правило кодирования: каждая точка . заменяется на %2e.

6. Первый запуск

cd server
docker compose up -d

Подождите ~30 секунд, пока Snikket получит TLS-сертификаты. Затем создайте администратора:

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

Обновление

cd server
docker compose pull
docker compose up -d

Бэкап

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 (звонки)
4915265535 UDP TURN relay (аудио/видео)
Description
No description provided
Readme 95 KiB
Languages
Shell 100%