# Настройка Prosody для Luma Ниже приведён ориентир для актуальных Prosody 0.12/13. Сохраните существующие модули аутентификации, TLS и federation вашего сервера — пример показывает только функции, необходимые клиенту. ```lua VirtualHost "example.org" modules_enabled = { -- ваши базовые модули; "roster"; -- RFC 6121: серверный список контактов "pep"; -- PEP: OMEMO device lists/bundles и XEP-0084 аватары "smacks"; -- XEP-0198 "carbons"; -- XEP-0280 "mam"; -- XEP-0313 "turn_external"; -- XEP-0215: STUN/TURN для Jingle-звонков } -- Тот же секрет укажите в coturn как static-auth-secret. turn_external_secret = "ЗАМЕНИТЕ_ДЛИННЫМ_СЛУЧАЙНЫМ_СЕКРЕТОМ" turn_external_host = "turn.example.org" turn_external_port = 3478 -- Необязательно: если coturn принимает TURN/TLS на 5349. turn_external_tls_port = 5349 default_archive_policy = true archive_expires_after = "1mon" max_archive_query_results = 100 -- Рекомендуется SQL-хранилище для архива. storage = { archive = "sql"; } Component "upload.example.org" "http_file_share" -- Luma не задаёт собственного предела; выберите серверный лимит под диск -- и reverse proxy. Ниже пример на 1 ГиБ. http_file_share_size_limit = 1024 * 1024 * 1024 http_file_share_expires_after = "1 month" -- Prosody 13 modules_disabled = { "s2s" } -- XEP-0045: групповые комнаты Luma/Conversations/Monal Component "conference.example.org" "muc" name = "Групповые чаты" restrict_room_creation = false -- либо "local" для локальных пользователей modules_enabled = { "muc_mam" } muc_log_by_default = true muc_log_expires_after = "1mon" ``` ## Аудио- и видеозвонки Сам XMPP-сервер только согласовывает Jingle-сессию. Для двух клиентов с доступными адресами этого достаточно, но за NAT/CGNAT нужен coturn. Начиная с Prosody 0.12 проще всего использовать встроенный `mod_turn_external`, как в примере выше: он публикует STUN/TURN и выдаёт клиенту временные учётные данные через XEP-0215. Минимальные соответствующие параметры coturn: ```ini fingerprint use-auth-secret static-auth-secret=ЗАМЕНИТЕ_ТЕМ_ЖЕ_СЕКРЕТОМ realm=example.org listening-port=3478 tls-listening-port=5349 # Для TURN/TLS также задайте cert= и pkey=. ``` Откройте для coturn UDP/TCP 3478, при использовании TLS — TCP 5349, а также настроенный UDP relay range. После перезапуска проверьте выдачу сервиса: ```bash prosodyctl check turn ``` Без собственного TURN Luma использует публичный STUN только для обнаружения адресов; STUN не может ретранслировать медиапоток, поэтому звонок между двумя сложными NAT может не установиться. Luma проверяет ответы XEP-0215 до создания WebRTC-соединения. Для `turn`/`turns` Prosody должен выдать и `username`, и `password`; `stuns`/`turns` допускают TCP (или отсутствие явного `transport`), а истёкшие временные credentials игнорируются. Если одна серверная конфигурация всё же не принимается WebRTC, клиент повторяет запуск с публичным STUN, затем с прямыми host candidates. В Debug-консоли при таком fallback появляется строка `Luma WebRTC:` без URL и учётных данных. Для группового OMEMO комната должна быть неанонимной; рекомендуется также members-only. При создании комнаты Luma сама отправляет owner configuration с `muc#roomconfig_whois = anyone`, `muc#roomconfig_membersonly = true` и `muc#roomconfig_persistentroom = true`, а также разрешает ролям moderator и participant читать member list. Для уже существующей комнаты включите в настройках владельца показ реальных JID всем участникам и доступ к списку участников. Если вошедший пользователь — владелец, Luma попробует изменить `whois` при первой зашифрованной отправке; обычный участник не может менять эту настройку. В Prosody 0.12.x срок хранения задаётся числом секунд, например `http_file_share_expires_after = 31 * 24 * 60 * 60`; строковый интервал выше используйте на Prosody 13. Для `upload.example.org` нужен корректный HTTPS URL. Если компонент не является прямым поддоменом VirtualHost, добавьте его в `disco_items`. При reverse proxy задайте `http_host`/`http_external_url` согласно вашей топологии. Например, для `wthome.ru` за HTTPS reverse proxy: ```lua Component "upload.wthome.ru" "http_file_share" http_file_share_size_limit = 1024 * 1024 * 1024 http_host = "upload.wthome.ru" http_external_url = "https://upload.wthome.ru/" trusted_proxies = { "127.0.0.1", "::1" } modules_disabled = { "s2s" } ``` Reverse proxy должен передавать `Host: upload.wthome.ru` и `X-Forwarded-Proto: https`. Иначе Prosody может выдать клиенту `http://` URL или маршрут, возвращающий 404; Luma намеренно не понижает upload до HTTP. Проверьте также: - валидный сертификат и STARTTLS на 5222 либо direct TLS на 5223; - SRV-записи `_xmpp-client._tcp` и, если используется, `_xmpps-client._tcp`; - доступность server disco и upload component disco; - права пользователей на PEP/pubsub nodes; - доставку PEP notifications `urn:xmpp:avatar:metadata+notify` контактам; - что MAM действительно пишет в постоянное хранилище, а не fallback memory. - доступность `conference.example.org` через service discovery и возможность локального пользователя создать/войти в комнату. - успешный `prosodyctl check turn` и доступность relay-портов coturn извне. Полезные команды: ```bash prosodyctl check config prosodyctl check certs prosodyctl shell module info http_file_share prosodyctl shell http list upload.wthome.ru ``` Начиная с 0.3.0 Luma различает ошибки discovery, получения upload slot, транспортную ошибку PUT и HTTP status. Если приложение пишет, что XEP-0363 не найден, проверьте `disco_items`; если показывает HTTP 404/413/5xx — проверяйте `http_host`, proxy path и лимит файла соответственно. ## Push на iOS `mod_cloud_notify` реализует серверную сторону XEP-0357, но одного включения модуля недостаточно. Нужен доступный по XMPP push gateway разработчика Luma, который принимает события Prosody и отправляет APNs. В текущем MVP клиент не регистрирует такой endpoint, потому что его адрес, APNs topic и ключи зависят от вашей Apple Developer учётной записи. Когда gateway будет готов, включите `cloud_notify` вместе со `smacks`, `mam` и `carbons`; не включайте передачу реального тела или sender в push без отдельного решения по приватности. ### Совместимость с сервером Monal Можно использовать открытый сервер [`monal-im/fpush`](https://github.com/monal-im/fpush), но его нужно развернуть для Luma либо договориться с владельцем уже работающего экземпляра о добавлении отдельного push-модуля. Подключить Luma к production endpoint Monal как к универсальному APNs relay нельзя: APNs device token относится к конкретному приложению, а gateway должен подписывать запросы сертификатом этого приложения и указывать его bundle ID (`app.luma.chat`) как topic. `fpush` подключается к Prosody как XEP-0114 component и поддерживает несколько приложений через `pushModule`. Минимальная конфигурация его APNs-модуля выглядит так (секреты и сертификат не храните в репозитории): ```json { "component": { "componentHostname": "push.example.org", "componentKey": "CHANGE_ME", "serverHostname": "127.0.0.1", "serverPort": 5347 }, "pushModules": { "lumaProdIOS": { "type": "apple", "is_default_module": true, "apns": { "certFilePath": "/run/secrets/luma-apns.p12", "certPassword": "CHANGE_ME", "topic": "app.luma.chat", "environment": "production" }, "ratelimit": { "ratelimitTime": "20s", "ratelimitCleanupInterval": "300s", "enabled": true } } }, "timeout": { "xmppconnectionError": "20s" } } ``` Для полного подключения ещё нужны: 1. Push Notifications capability и подходящий provisioning profile для Luma. 2. Регистрация iOS-приложения в APNs и получение device token. 3. Отправка XEP-0357 `` с `node` = APNs token, JID компонента и полем `pushModule=lumaProdIOS`; `` при выходе из аккаунта. 4. `smacks`, `mam`, `carbons`, `cloud_notify` в Prosody и доступ компонента `push.example.org` по component-порту или s2s — в зависимости от схемы развёртывания. Без APNs credentials от Apple Developer аккаунта приложение продолжит показывать только уже реализованные локальные уведомления, пока процесс жив.