diff --git a/README.md b/README.md index e69de29..64ef221 100644 --- a/README.md +++ b/README.md @@ -0,0 +1,263 @@ +# 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 (аудио/видео) |