The snikket_server image includes a TURN server that is enabled by default (SNIKKET_TWEAK_TURNSERVER=1). A separate coturn container conflicts on port 3478 and adds unnecessary complexity for a standard deployment. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
213 lines
9.5 KiB
Markdown
213 lines
9.5 KiB
Markdown
# Snikket Server
|
||
|
||
XMPP-сервер на базе [Snikket](https://snikket.org/) (обёртка над Prosody с предварительной конфигурацией).
|
||
|
||
## Состав сервисов
|
||
|
||
| Сервис | Образ | Назначение |
|
||
|--------|-------|------------|
|
||
| `snikket_server` | `snikket/snikket-server:stable` | Ядро — Prosody XMPP-сервер |
|
||
| `snikket_proxy` | `snikket/snikket-web-proxy:stable` | Веб-прокси (nginx) |
|
||
| `snikket_certs` | `snikket/snikket-cert-manager:stable` | Автоматическое получение TLS-сертификатов (Let's Encrypt) |
|
||
| `snikket_portal` | `snikket/snikket-web-portal:stable` | Веб-портал для управления пользователями и инвайтами |
|
||
| `s3_upload_handler` | собирается из `./s3-upload-handler` | Обработчик загрузки файлов — принимает файлы от XMPP-клиентов и сохраняет в S3 |
|
||
| `postgres` | `postgres:15` | База данных PostgreSQL для Prosody |
|
||
|
||
Все сервисы работают в режиме `network_mode: host`.
|
||
|
||
## Требования
|
||
|
||
### DNS-записи
|
||
|
||
Для домена `chat.example.org` необходимо создать 3 записи:
|
||
|
||
| Тип | Имя | Значение |
|
||
|-----|-----|----------|
|
||
| A | `chat.example.org` | IP-адрес сервера |
|
||
| CNAME | `groups.chat.example.org` | `chat.example.org` |
|
||
| CNAME | `share.chat.example.org` | `chat.example.org` |
|
||
|
||
Опционально: AAAA-запись для IPv6, SRV-запись `_xmpps-client._tcp` для подключения через порт 443.
|
||
|
||
### Порты
|
||
|
||
| Порт | Протокол | Назначение |
|
||
|------|----------|------------|
|
||
| 80 | TCP | HTTP (ACME challenges, редирект на HTTPS) |
|
||
| 443 | TCP | HTTPS (веб-портал, file sharing) |
|
||
| 5222 | TCP | XMPP client-to-server |
|
||
| 5269 | TCP | XMPP server-to-server (федерация) |
|
||
| 5000 | TCP | Proxy65 (передача файлов) |
|
||
| 5050 | TCP | S3 upload handler (HTTP Upload External) |
|
||
| 5432 | TCP | PostgreSQL |
|
||
| 3478 | TCP+UDP | STUN/TURN |
|
||
| 5349 | TCP+UDP | TURNS (TURN over TLS) |
|
||
| 49152–65535 | UDP | TURN relay (аудио/видео данные) |
|
||
|
||
### Настройка файрвола (UFW)
|
||
|
||
```bash
|
||
# XMPP и веб
|
||
ufw allow 80/tcp
|
||
ufw allow 443/tcp
|
||
ufw allow 5222/tcp
|
||
ufw allow 5269/tcp
|
||
ufw allow 5000/tcp
|
||
|
||
# STUN/TURN (голосовые и видеозвонки)
|
||
ufw allow 3478/udp
|
||
ufw allow 3478/tcp
|
||
ufw allow 5349/tcp
|
||
ufw allow 5349/udp
|
||
ufw allow 49152:65535/udp
|
||
```
|
||
|
||
## Конфигурация
|
||
|
||
### prosody.cfg.lua
|
||
|
||
Кастомная конфигурация Prosody, монтируется в контейнер `snikket_server` как `/etc/prosody/conf.d/custom.cfg.lua`. Содержит:
|
||
|
||
- **PostgreSQL** — `storage = "sql"` с драйвером PostgreSQL (подключение к `127.0.0.1:5432`)
|
||
- **HTTP Upload External** — `mod_http_upload_external` для загрузки файлов через внешний S3 upload handler
|
||
|
||
### secrets.env
|
||
|
||
Файл с секретами, **не коммитится в git** (добавлен в `.gitignore`). Перед первым запуском необходимо создать его и заполнить реальными значениями:
|
||
|
||
```bash
|
||
cp secrets.env.example secrets.env
|
||
# отредактировать secrets.env
|
||
```
|
||
|
||
| Переменная | Описание |
|
||
|------------|----------|
|
||
| `UPLOAD_SECRET` | Shared secret (должен совпадать с `http_upload_external_secret` в `prosody.cfg.lua`) |
|
||
| `AWS_ACCESS_KEY_ID` | Ключ доступа AWS/S3 |
|
||
| `AWS_SECRET_ACCESS_KEY` | Секретный ключ AWS/S3 |
|
||
| `POSTGRES_PASSWORD` | Пароль PostgreSQL |
|
||
|
||
### S3 Upload Handler (environment)
|
||
|
||
Несекретные параметры задаются в `docker-compose.yml` в секции `environment` сервиса `s3_upload_handler`:
|
||
|
||
| Переменная | Описание |
|
||
|------------|----------|
|
||
| `S3_BUCKET` | Имя S3-бакета |
|
||
| `S3_REGION` | Регион S3 |
|
||
| `S3_ENDPOINT` | URL S3-совместимого хранилища (MinIO и др.), не задавать для AWS |
|
||
| `PRESIGN_EXPIRE` | Время жизни presigned URL для скачивания (секунды, по умолчанию `3600`) |
|
||
|
||
### snikket.conf
|
||
|
||
### Обязательные параметры
|
||
|
||
| Переменная | Описание |
|
||
|------------|----------|
|
||
| `SNIKKET_DOMAIN` | Домен сервера. **Нельзя изменить после первого запуска.** |
|
||
| `SNIKKET_ADMIN_EMAIL` | Email администратора (используется для Let's Encrypt) |
|
||
|
||
### Основные параметры
|
||
|
||
| Переменная | По умолчанию | Описание |
|
||
|------------|-------------|----------|
|
||
| `SNIKKET_SITE_NAME` | значение `SNIKKET_DOMAIN` | Человекочитаемое имя сервера |
|
||
| `SNIKKET_RETENTION_DAYS` | `7` | Сколько дней хранить сообщения (MAM) и загруженные файлы |
|
||
| `SNIKKET_UPLOAD_STORAGE_GB` | без лимита | Лимит дискового пространства для загруженных файлов (напр. `1.5`) |
|
||
| `SNIKKET_LOGLEVEL` | `info` | Уровень логирования: `error`, `warn`, `info`, `debug` |
|
||
| `SNIKKET_ABUSE_EMAIL` | — | Публичный email для жалоб |
|
||
| `SNIKKET_SECURITY_EMAIL` | — | Публичный email для сообщений о безопасности |
|
||
| `SNIKKET_UPDATE_CHECK` | `1` | Установить `0` чтобы отключить проверку обновлений |
|
||
|
||
### Параметры reverse proxy
|
||
|
||
| Переменная | По умолчанию | Описание |
|
||
|------------|-------------|----------|
|
||
| `SNIKKET_TWEAK_HTTP_PORT` | `80` | HTTP-порт (изменить при работе за reverse proxy) |
|
||
| `SNIKKET_TWEAK_HTTPS_PORT` | `443` | HTTPS-порт (изменить при работе за reverse proxy) |
|
||
|
||
### Параметры TURN-сервера
|
||
|
||
| Переменная | По умолчанию | Описание |
|
||
|------------|-------------|----------|
|
||
| `SNIKKET_TWEAK_TURNSERVER` | `1` | Установить `0` для отключения встроенного TURN |
|
||
| `SNIKKET_TWEAK_TURNSERVER_DOMAIN` | значение `SNIKKET_DOMAIN` | Домен внешнего TURN-сервера |
|
||
| `SNIKKET_TWEAK_TURNSERVER_PORT` | `3478` | Порт TURN-сервера |
|
||
| `SNIKKET_TWEAK_TURNSERVER_SECRET` | автогенерация | Shared secret для аутентификации TURN |
|
||
|
||
### Прочие параметры
|
||
|
||
| Переменная | По умолчанию | Описание |
|
||
|------------|-------------|----------|
|
||
| `SNIKKET_TWEAK_IPV6` | `1` | Установить `0` для отключения IPv6 |
|
||
| `SNIKKET_TWEAK_STORAGE` | `files` | Бэкенд хранения: `files` или `sqlite` (превью) |
|
||
| `SNIKKET_TWEAK_EXTRA_CONFIG` | — | Путь/glob к дополнительным файлам конфигурации Prosody |
|
||
| `SNIKKET_PROXY65_PORT` | `5000` | Порт proxy для передачи файлов |
|
||
| `SNIKKET_TWEAK_DNSSEC` | — | Включить поддержку DNSSEC и DANE |
|
||
|
||
## Запуск
|
||
|
||
```bash
|
||
cd server
|
||
|
||
# 1. Настроить конфигурацию
|
||
# отредактировать snikket.conf значениями вашего домена
|
||
|
||
# 2. Заполнить секреты
|
||
cp secrets.env.example secrets.env
|
||
# отредактировать secrets.env реальными значениями
|
||
|
||
# 3. Запустить
|
||
docker compose up -d
|
||
|
||
# 3. Создать admin-аккаунт
|
||
docker exec snikket create-invite --admin --group default
|
||
```
|
||
|
||
Инвайт-ссылку открыть в браузере для регистрации администратора.
|
||
|
||
## Обновление
|
||
|
||
```bash
|
||
cd server
|
||
docker compose pull
|
||
docker compose up -d
|
||
```
|
||
|
||
## Хранение данных
|
||
|
||
Данные хранятся в Docker volumes:
|
||
|
||
| Volume | Содержимое |
|
||
|--------|-----------|
|
||
| `snikket_data` | Данные сервера: аккаунты, сообщения, TLS-сертификаты |
|
||
| `acme_challenges` | Временные файлы ACME (Let's Encrypt) |
|
||
| `postgres_data` | Данные PostgreSQL |
|
||
|
||
Загруженные файлы хранятся в S3-бакете (не в volumes).
|
||
|
||
### Бэкап
|
||
|
||
Необходимо сохранить volume `snikket_data` и базу PostgreSQL:
|
||
|
||
```bash
|
||
# Snikket data
|
||
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)
|
||
|
||
Загруженные файлы (HTTP File Upload, XEP-0363) хранятся в **S3-бакете** через кастомный `s3_upload_handler`.
|
||
|
||
Схема работы:
|
||
|
||
1. XMPP-клиент запрашивает у Prosody слот для загрузки файла
|
||
2. Prosody (`mod_http_upload_external`) генерирует подписанный URL, указывающий на `s3_upload_handler`
|
||
3. Клиент загружает файл по этому URL
|
||
4. `s3_upload_handler` проверяет HMAC-подпись и сохраняет файл в S3
|
||
5. При скачивании — handler генерирует presigned S3 URL и делает redirect
|