README_RU.md

August 11, 2026 · View on GitHub

🌐 Другие языки: 中文 · English · 日本語 · 한국어 · Français · Deutsch · Español

Мессенджер со сквозным шифрованием в стиле WeChat. Бессостоянный ECDH + XSalsa20-Poly1305 шифрование для каждого сообщения, видеозвонки в реальном времени, хранение файлов Cloudflare R2, поддержка нескольких языков и развёртывание iOS PWA.

Rust React TypeScript MySQL Redis WebRTC License: AGPL v3

Deploy on Zeabur

Version

Google Play App Store Windows Mac


📸 Скриншоты (нажмите для просмотра) ui1 ui2 ui3 ui4 ui5 ui6 ui7 ui8 ui9 ui10 ui11 ui12 ui13 ui14 ui15 ui16 ui17 ui18

Функции

ФункцияОписание
🔐 Сквозное шифрованиеБессостоянный ECDH + XSalsa20-Poly1305 — эфемерные ключи для каждого сообщения, прямая секретность, верификация номера безопасности в стиле Signal
🗝️ Сервер с нулевым знаниемСервер хранит только зашифрованный текст; приватные ключи никогда не покидают устройство
📹 Видео- и аудиозвонкиLiveKit SFU для звонков 1:1 и конференций (до 100 участников), отключение микрофонов и режим лекции
🎙️ Изменение голосаЭффекты голоса в реальном времени для голосовых сообщений, звонков 1:1 и групповых звонков — 3 режима (0.8x низкий / 1.0x обычный / 1.2x высокий), на основе Web Audio API
📱 Сохранение сеансаAccess Token на 30 минут и автоматически продлеваемая 90-дневная refresh-сессия устройства; восстановление после смены сети/IP/VPN/прокси без ввода пароля
📨 Надёжная синхронизация сообщенийДвусторонний heartbeat, обнаружение полуоткрытых соединений, постоянная очередь исходящих, идемпотентные ID и догрузка по курсору серверной последовательности
📴 Офлайн-доступИзолированный по аккаунтам кэш контактов, групп, до 2 000 сообщений на диалог, Моментов, Ленты и медиа; офлайн-отправления повторяются автоматически
🔎 Unicode-поиск друзейЗащита композиции IME, нормализация NFC и кодирование UTF-8 обеспечивают надёжный поиск китайских имён пользователей и никнеймов
👥 Групповой чатДо 2000 участников, переключаемые режимы «Зашифрованный» / «Незашифрованный» (только владелец, при переключении история чата очищается). Зашифрованный режим использует протокол Sender Key в стиле Signal (симметричное шифрование XSalsa20-Poly1305 + распределение ключей ECDH) — только участники группы могут расшифровать сообщения; боты недоступны в зашифрованном режиме. Режим «Не беспокоить», управление участниками
👫 Система друзейЗаявки в друзья требуют одобрения с сообщением до 512 символов; пользовательские никнеймы; группировка по нескольким тегам
⏱️ Автоудаление сообщений5 уровней (никогда / 1 день / 3 дня / 1 неделя / 1 месяц), настраивается любой стороной в личных сообщениях, только владельцем в группах
🔔 Push-уведомленияWeb Push (VAPID) + FCM + OneSignal + ntfy + APNS пятиканальная доставка — доступность пользователей даже в офлайне (поддержка нативного iOS + китайских Android без Google Services)
🌐 МультиязычностьКитайский, английский, японский, корейский, французский, немецкий, русский, испанский — автоопределение + ручное переключение
📱 iOS — без корпоративного сертификатаPWA через Safari «На экран Домой», работает бессрочно без подписи Apple
📱 Нативное Android-приложениеДоступно в Google Play, с поддержкой FCM push-уведомлений
📱 Нативное iOS-приложениеДоступно в App Store, с поддержкой APNS push-уведомлений
🖥️ Десктопный клиент WindowsНативное настольное приложение для Windows, скачать здесь
🍎 Десктопный клиент MacНативное настольное приложение для Mac, скачать здесь
💬 Расширенные сообщенияТекст, изображения, видео, документы, голосовые сообщения, 200+ эмодзи, стикер-паки Telegram, отчёты о доставке, индикаторы набора текста
📤 Загрузка файловДо 500 МБ на файл, Cloudflare R2 или локальное хранилище, с анимацией прогресса
🌐 МоментыСоциальная лента в стиле WeChat: текст + до 9 фото или 1 видео (≤ 10 мин), лайки, комментарии, видимость по тегам
👤 Профиль пользователяСтраница контактного профиля с двусторонним управлением приватностью Моментов
📰 ЛентаПубличная лента в стиле Xiaohongshu — двухколоночная кладка, анонимные публикации, лайки и комментарии
🏷️ Теги друзейНазначение нескольких тегов друзьям (палитра из 12 цветов), фильтрация контактов по тегу
🗂️ Объектное хранилище R2Cloudflare R2 для изображений/голосовых файлов — опциональный публичный CDN URL
🔑 Двухфакторная аутентификация (2FA)TOTP совместимый с Google Authenticator, 8 кодов восстановления, проверка при входе
📷 Сканирование и обмен QR-кодамиСканируйте QR-коды для добавления друзей или вступления в группы с настраиваемым сроком действия
🏗️ Самостоятельный хостингDocker Compose, Zeabur в один клик или фронтенд на Vercel
🌐 Настройки проксиПоддержка SOCKS5 / HTTP / HTTPS прокси — настройка на страницах входа и настроек с указанием адреса сервера, порта, имени пользователя и пароля для ограниченных сетевых сред
🛡️ Модерация контентаЖалобы пользователей (6 категорий) + блокировка пользователей (мгновенное скрытие постов/сообщений) + Условия использования (EULA)
🔧 Панель администратораВстроенная веб-панель администратора (/admin, путь настраивается), защита паролем, проверка жалоб, удаление нарушающего контента, бан пользователей — поддержка 8 языков

Новое в v2.3.9

  • Исправлены старые односторонние записи дружбы, из-за которых отображалось «Уже в друзьях», но контакт оставался невидимым и недоступным для чата; повторное добавление теперь восстанавливает обе стороны связи и сразу обновляет список контактов.

Новое в v2.3.8

  • Исправлена неработающая кнопка «Назад» после запуска камеры QR-сканера; при закрытии камера теперь сразу останавливается и освобождается.
  • Исправлено повреждение связи при повторной заявке уже добавленному другу; результаты поиска теперь показывают «Уже в друзьях».
  • После сквозного шифрования исходящие личные сообщения сразу получают шифротекст в оптимистическом объекте, поэтому открытый текст не сохраняется в ожидании подтверждения сервера.
  • Голосовые сообщения автоматически останавливаются на 120 секундах; результат изменения голоса имеет тот же предел.
  • Во время записи и звонков экран остаётся включённым, а при уходе со страницы устройства и таймеры освобождаются.
  • Android также защищает ключи и кэши через Android Keystore и AES-256-GCM; веб-клиент сохраняет браузерную модель хранения.

Восстановление сеанса и надёжность сообщений

PaperPhonePlus раздельно обрабатывает локальное состояние аккаунта, соединение реального времени и синхронизацию сообщений. Открытый WebSocket считается готовым только после ответа сервера auth_ok. Двусторонний ping/pong обнаруживает полуоткрытые соединения после смены VPN/IP, переключения Wi-Fi/мобильной сети или приостановки приложения.

  • Access Token действует 30 минут. Refresh Token устройства действует 90 дней и продлевается при активном использовании, поэтому пароль повторно вводить не требуется.
  • Устройства, уже вошедшие через старую версию, обновляются автоматически, пока прежний Token действителен. Если он уже истёк, потребуется один последний ручной вход.
  • Каждое исходящее сообщение имеет стабильный client_msg_id. Сообщения без ACK остаются в постоянной локальной очереди и повторно отправляются с тем же ID; уникальное ограничение сервера предотвращает дублирование.
  • Каждое сохранённое сообщение имеет монотонно растущий server_seq. После аутентификации, переподключения и возврата на передний план клиент догружает пропущенные сообщения по курсору.
  • Явный выход и отзыв устройства аннулируют долгосрочную серверную сессию. Обычные сетевые ошибки и смена IP её сохраняют.

Important

При обновлении сначала разверните server, затем клиенты. Server автоматически применяет и проверяет миграцию надёжности и не запускается при отсутствии обязательных столбцов. Перед обновлением production создайте резервную копию MySQL.


Технологический стек

Бэкенд (server/)
  Rust (Axum 0.8) — Высокопроизводительный асинхронный веб-фреймворк
  sqlx + MySQL 8.0 — Хранение данных пользователей/сообщений
  deadpool-redis + Redis 7 — Онлайн-статус + маршрутизация между узлами
  aws-sdk-s3 — Файловое хранилище Cloudflare R2 (S3-совместимый API)
  argon2 + jsonwebtoken аутентификация

Фронтенд (client/)
  React 19 + TypeScript + Vite 6
  Zustand управление состоянием
  libsodium-wrappers-sumo (WebAssembly — Curve25519 / XSalsa20-Poly1305)
  WebRTC API — видео / голосовые звонки
  Web Audio API — изменение голоса в реальном времени (аудиоцепочка ScriptProcessorNode)
  PWA: manifest.json + Service Worker

Криптографический уровень
  Бессостоянный ECDH + XSalsa20-Poly1305 — эфемерная пара ключей для каждого сообщения
  Четырёхуровневое хранение ключей: memory → localStorage → sessionStorage → IndexedDB
  Все приватные ключи хранятся только на устройстве — никогда не отправляются на сервер

📖 Подробное руководство по развёртыванию (中文) | Deployment Guide (English) — Полные пошаговые инструкции по гибридному развёртыванию Zeabur + Vercel, локальному развёртыванию Docker Compose + Nginx, а также настройке адреса сервера в клиентских приложениях.

Вариант 0: Zeabur — облачное развёртывание в один клик

Deploy on Zeabur

Сетевое ограничение Zeabur: шаблон развёртывает LiveKit через WebSocket/API 7880 и ICE/TCP 7881. Сейчас Zeabur не предоставляет UDP-порты сервисов, поэтому звонки 1:1 и конференции используют TCP. Для производственных звонков используйте LiveKit Cloud или виртуальную машину с поддержкой UDP.

Настройка Nginx на сервере

Используйте двухдоменную конфигурацию deploy/nginx/paperphone-plus.conf. Замените api.example.com и meeting.example.com, получите TLS-сертификаты, скопируйте файл в /etc/nginx/sites-available/paperphone-plus, включите его и выполните sudo nginx -t && sudo systemctl reload nginx. На сервере задайте LIVEKIT_URL=wss://meeting.example.com. Nginx проксирует только API и WebSocket; TCP 7881 и UDP 7882 необходимо открыть напрямую в системном и облачном межсетевых экранах.

Tip

Продвинутый вариант: гибридное развёртывание Zeabur + Vercel После развёртывания на Zeabur вы можете вручную удалить сервис client и развернуть фронтенд на Vercel (см. Вариант 2 ниже). Таким образом сервер/MySQL/Redis размещаются на Zeabur, а фронтенд ускоряется глобальной CDN Vercel. Фронтенд не требует переменных окружения на Vercel — пользователи просто вводят адрес бэкенд-сервера на странице входа.

Вариант 1: Docker Compose (Рекомендуется)

git clone <repo-url> && cd paperphone-plus
cp server/.env.example server/.env
# Отредактируйте: DB_PASS / JWT_SECRET / LIVEKIT_URL и т.д.
docker compose up -d
open http://localhost

Вариант 2: Фронтенд на Vercel

# 1. Сделайте форк этого репозитория
# 2. Импортируйте в Vercel: Root Directory = client/, Build = npm run build, Output = dist/
#    Переменные окружения не требуются
# 3. Разверните бэкенд через Docker или Zeabur
# 4. Откройте фронтенд, развёрнутый на Vercel, и введите адрес бэкенд-сервера на странице входа
#    например https://your-server.zeabur.app

Вариант 3: Локальная разработка

# Бэкенд (Rust)
cd server && cp .env.example .env && cargo run --release

# Фронтенд (React)
cd client && npm install && npm run dev

Изменение голоса

Голосовые сообщения, звонки 1:1 и групповые звонки поддерживают изменение голоса в реальном времени с 3 режимами на выбор:

РежимСкоростьЭффект
🐢 Медленный0.8xБолее глубокий, низкий голос — идеально для анонимности
🔊 Обычный1.0xОригинальный голос, без обработки
🐇 Быстрый1.2xБолее высокий голос — весело и игриво

Как это работает: Используется Web Audio API для построения цепочки обработки звука (AudioContext → MediaStreamSource → ScriptProcessorNode → MediaStreamDestination), которая регулирует высоту тона/скорость микрофонного ввода в реальном времени.

  • Голосовые сообщения: Выберите режим голоса во время записи. Экспортированный файл .webm уже содержит голосовой эффект — получатели не могут восстановить оригинальный голос, что обеспечивает настоящую анонимную переписку
  • Звонки 1:1 / групповые: Нажмите кнопку изменения голоса во время звонка для переключения между режимами. Обработанная аудиодорожка заменяет оригинальную через LiveKit LocalAudioTrack.replaceTrack()

Серверная настройка не требуется. Изменение голоса работает полностью на стороне клиента.


Переменные окружения

ПеременнаяОписаниеПо умолчанию
PORTПорт сервера3000
JWT_SECRETКлюч подписи JWT (измените в продакшене)dev_secret
DB_HOST / DB_PASS / DB_NAMEПодключение к MySQL
REDIS_HOST / REDIS_PASSПодключение к Redis
R2_ACCOUNT_IDID аккаунта Cloudflare
R2_ACCESS_KEY_IDКлюч доступа API-токена R2
R2_SECRET_ACCESS_KEYСекретный ключ API-токена R2
R2_BUCKETНазвание бакета R2
R2_PUBLIC_URLПубличный базовый URL R2 (опционально)
LIVEKIT_URLПубличный WebSocket URL LiveKit для всех звонков
LIVEKIT_API_KEYAPI Key, общий для сервера и LiveKit
LIVEKIT_API_SECRETAPI Secret, общий для сервера и LiveKit
VAPID_PUBLIC_KEYПубличный ключ Web Push VAPID (опционально)
VAPID_PRIVATE_KEYПриватный ключ Web Push VAPID (опционально)
VAPID_SUBJECTКонтактный email VAPID (опционально)mailto:admin@paperphoneplus.app
FCM_PROJECT_IDID проекта Firebase (опционально, Capacitor Android)
FCM_CLIENT_EMAILEmail сервисного аккаунта Firebase (опционально)
FCM_PRIVATE_KEYПриватный ключ сервисного аккаунта Firebase (опционально, поддерживает как экранирование \n, так и реальные переводы строк; см. ниже)
FCM_RELAY_SECRETСекрет relay FCM push (опционально, установите на relay-хосте для активации эндпоинта)
FCM_RELAY_URLURL relay FCM push (опционально, self-hosted серверы указывают на relay-хост)
FCM_RELAY_KEYКлюч авторизации relay FCM push (опционально, должен совпадать с FCM_RELAY_SECRET relay-хоста)
ONESIGNAL_APP_IDOneSignal App ID (опционально)
ONESIGNAL_REST_KEYOneSignal REST API Key (опционально)
ONESIGNAL_RELAY_SECRETСекрет relay OneSignal push (опционально, установите на relay-хосте для активации эндпоинта)
ONESIGNAL_RELAY_URLURL relay OneSignal push (опционально, self-hosted серверы указывают на relay-хост)
ONESIGNAL_RELAY_KEYКлюч авторизации relay OneSignal push (опционально, должен совпадать с ONESIGNAL_RELAY_SECRET relay-хоста)
NTFY_BASE_URLURL сервера ntfy (опционально, по умолчанию используется публичный ntfy.sh)https://ntfy.sh
NTFY_TOKENТокен авторизации ntfy (опционально, для self-hosted серверов)
APNS_TEAM_IDTeam ID разработчика Apple (опционально, нативный iOS push)
APNS_KEY_IDID ключа авторизации APNS (опционально)
APNS_PRIVATE_KEYСодержимое приватного ключа APNS .p8 (опционально, поддерживает экранирование \n)
APNS_BUNDLE_IDBundle Identifier iOS-приложения (опционально)
APNS_SANDBOXРежим песочницы APNS (опционально, true для разработки/TestFlight)false
APNS_RELAY_SECRETСекрет push relay (опционально, установите на relay-хосте для активации эндпоинта)
APNS_RELAY_URLURL push relay (опционально, self-hosted серверы указывают на relay-хост)
APNS_RELAY_KEYКлюч авторизации push relay (опционально, должен совпадать с APNS_RELAY_SECRET relay-хоста)
TELEGRAM_BOT_TOKENТокен Telegram-бота (опционально)
STICKER_PACKSПользовательские стикер-паки (опционально, name:label)12 встроенных по умолчанию
ADMIN_PATHURL-путь панели администратора/admin
ADMIN_PASSWORDПароль панели администратора (измените в продакшене)admin123

Обработка переводов строк в приватном ключе FCM

Поле private_key в JSON сервисного аккаунта Firebase содержит RSA-ключ в формате PEM, который требует реальных символов перевода строки (\n, ASCII 0x0A) между каждой 64-символьной строкой. Однако многие платформы развёртывания (Zeabur, Vercel, Railway, Docker) хранят переменные окружения как однострочные значения, преобразуя \n в буквальную двухсимвольную последовательность \ + n.

Это самая распространённая причина сбоя FCM push-уведомлений — парсер PEM молча завершается с ошибкой, и push-уведомления не отправляются без каких-либо записей в логах.

Сервер обрабатывает это автоматически: fcm.rs нормализует буквальные последовательности \n обратно в реальные переводы строк перед парсингом. Оба формата работают:

  • Однострочный (рекомендуется для облачных платформ): Вставьте необработанное значение private_key из JSON-файла как есть, с экранированием \n:

    FCM_PRIVATE_KEY=-----BEGIN PRIVATE KEY-----\nMIIEvQ...\n-----END PRIVATE KEY-----\n
    
  • Многострочный (для .env файлов): Оберните полное содержимое PEM в кавычки с реальными переводами строк:

    FCM_PRIVATE_KEY="-----BEGIN PRIVATE KEY-----
    MIIEvQ...
    -----END PRIVATE KEY-----"
    
ПлатформаРекомендуемый форматПримечания
ZeaburОднострочный (экранирование \n)Вставьте значение JSON непосредственно в панели Variables
Docker / docker-composeЛюбойИспользуйте YAML | для многострочного формата; однострочный в .env
Vercel / RailwayОднострочный (экранирование \n)Поля ввода обычно не поддерживают реальные переводы строк
Linux .env файлМногострочный (в кавычках)Убедитесь, что кавычки правильно закрыты

Устранение неполадок: Если переменные FCM установлены, но push-уведомления Android не работают, проверьте логи сервера:

  • [FCM] No access token available → Ошибка формата приватного ключа (проблема с переводами строк)
  • [FCM] ✅ Push sent to user xxx → Отправка FCM работает, проблема на стороне клиента
  • Логи FCM отсутствуют → FCM_PROJECT_ID не установлен или нет токена в таблице fcm_tokens

Push-уведомления ntfy (Android-устройства без Google Services)

Для Android-устройств без Google Mobile Services (Huawei, Xiaomi, OPPO, vivo и др.) PaperPhonePlus поддерживает push-уведомления через ntfy.

Настройка по умолчанию (без конфигурации): Используется публичный сервис ntfy.sh. Дополнительная настройка не требуется.

Опциональная конфигурация (для self-hosted серверов ntfy):

NTFY_BASE_URL=https://your-ntfy-server.com
NTFY_TOKEN=your_optional_auth_token

Порядок настройки для пользователя:

  1. Установите приложение ntfy (Google Play / F-Droid / Прямая загрузка)
  2. Откройте настройки PaperPhonePlus и найдите карточку «ntfy Push»
  3. Скопируйте отображаемое имя темы и подпишитесь на неё в приложении ntfy
  4. Нажмите «Зарегистрировать Push» для завершения регистрации

Примечание по безопасности: Уведомления ntfy содержат заголовки и краткие описания в открытом виде (не фактическое содержание сообщений). Для повышения безопасности рассмотрите возможность self-hosted сервера ntfy.

APNS Push (Нативное iOS-приложение)

APNS (Apple Push Notification Service) отправляет push-уведомления нативным iOS-приложениям, созданным с помощью Capacitor. Доступны два варианта конфигурации:

Вариант A: Прямая конфигурация (сервер разработчика приложения)

  1. Войдите в Apple DeveloperCertificates, Identifiers & ProfilesKeys
  2. Нажмите + для создания нового ключа → отметьте Apple Push Notifications service (APNs) → Register
  3. Скачайте файл .p8 (⚠️ можно скачать только один раз!) и запишите Key ID
  4. Запишите ваш Team ID со страницы Apple Developer Membership (10-символьный буквенно-цифровой код)
  5. Добавьте в server/.env:
APNS_TEAM_ID=AB12CD34EF
APNS_KEY_ID=LH4Z9YN3P7
APNS_PRIVATE_KEY="-----BEGIN PRIVATE KEY-----\nMIGTAgEA...(содержимое файла .p8)...\n-----END PRIVATE KEY-----"
APNS_BUNDLE_ID=com.yourcompany.paperphoneplus
APNS_SANDBOX=false

APNS_SANDBOX: Установите true для сборок разработки/TestFlight, false для продакшена App Store.

Вариант B: Через Push Relay (self-hosted серверы)

Если вы используете чужое iOS-приложение (например, скачанное из App Store), у вас нет учётных данных Apple разработчика и вы не можете отправлять APNS push напрямую. Используйте Push Relay.

Как это работает:

┌──────────────────────┐       ┌─────────────────────────┐       ┌─────────┐
│  Self-hosted сервер   │  HTTP  │  Сервер разработчика     │  APNS  │  Apple  │
│  (нет учётных данных  │──────→│  (есть .p8 Key + Relay)  │──────→│  ──→ 📱 │
│   Apple)              │       │                          │       └─────────┘
│                       │       │                          │
│  APNS_RELAY_URL=...   │       │  APNS_TEAM_ID=...        │
│  APNS_RELAY_KEY=...   │       │  APNS_RELAY_SECRET=...   │
└──────────────────────┘       └─────────────────────────┘

Шаг 1: Разработчик приложения включает эндпоинт Relay

На сервере разработчика приложения (который уже имеет учётные данные APNS) установите секрет relay:

# .env сервера разработчика приложения (уже содержит APNS_TEAM_ID и т.д.)
APNS_RELAY_SECRET=a_long_random_shared_secret

Это автоматически активирует эндпоинт push relay по адресу POST /api/push-relay/apns.

Шаг 2: Пользователь self-hosted сервера настраивает Relay

Self-hosted серверам нужны только две переменные — учётные данные Apple не требуются:

# .env self-hosted сервера
APNS_RELAY_URL=https://app-developer-server.com
APNS_RELAY_KEY=the_shared_secret_from_step_1

Как это работает:

  1. Self-hosted сервер получает офлайн-сообщение → запрашивает локальную таблицу apns_tokens для получения токенов iOS-устройств пользователя
  2. Отправляет токены устройств + заголовок/тело push через HTTP POST на Relay
  3. Relay проверяет ключ, затем отправляет в Apple с использованием собственных учётных данных APNS
  4. Relay возвращает список устаревших токенов; self-hosted сервер автоматически очищает свою локальную базу данных

Приоритет: Локальные учётные данные APNS → Push Relay → пропуск (без уведомления). Если оба варианта настроены, приоритет имеет прямое локальное подключение.

Примечание по безопасности: Relay передаёт только заголовки и краткие описания push-уведомлений (например, «Вам пришло новое сообщение»), а не фактическое содержание сообщений. Токены устройств не могут использоваться для чтения данных пользователей.

Push Relay (Все каналы)

Для операторов self-hosted серверов, использующих чужое опубликованное приложение (например, из App Store/Google Play), у вас нет учётных данных push разработчика (Apple .p8 Key / сервисный аккаунт Firebase / API-ключ OneSignal).

Система Push Relay обеспечивает возможность ретрансляции для каналов APNS, FCM и OneSignal:

Разработчик приложения включает эндпоинты relay на своём сервере:

# .env сервера разработчика приложения
APNS_RELAY_SECRET=a_long_random_string
FCM_RELAY_SECRET=a_long_random_string
ONESIGNAL_RELAY_SECRET=a_long_random_string

Пользователи self-hosted серверов указывают только URL relay и ключ — учётные данные push-сервисов не требуются:

# .env self-hosted сервера
# APNS (нативный iOS push)
APNS_RELAY_URL=https://app-developer-server.com
APNS_RELAY_KEY=shared_secret

# FCM (нативный Android push)
FCM_RELAY_URL=https://app-developer-server.com
FCM_RELAY_KEY=shared_secret

# OneSignal (приложения, обёрнутые через Median.co)
ONESIGNAL_RELAY_URL=https://app-developer-server.com
ONESIGNAL_RELAY_KEY=shared_secret

Приоритет: Локальные учётные данные → Push Relay → пропуск (без уведомления). Если оба варианта настроены, приоритет имеет прямое локальное подключение.


Официальный Push Relay

Операторы self-hosted серверов могут использовать официальный push relay для включения push-уведомлений iOS/Android без настройки каких-либо учётных данных push:

# 2026-05-18
APNS_RELAY_URL=https://619.chat
APNS_RELAY_KEY=EzmpqftbsENaRUO6BTABxLV96q7RuEDyokXJr1DWdDjL54cLg7yXVUQqydCQvxrX
FCM_RELAY_URL=https://619.chat
FCM_RELAY_KEY=EzmpqftbsENaRUO6BTABxLV96q7RuEDyokXJr1DWdDjL54cLg7yXVUQqydCQvxrX
ONESIGNAL_RELAY_URL=https://619.chat
ONESIGNAL_RELAY_KEY=EzmpqftbsENaRUO6BTABxLV96q7RuEDyokXJr1DWdDjL54cLg7yXVUQqydCQvxrX

Добавьте эти строки в файл .env вашего self-hosted сервера.


Лицензия

Этот проект лицензирован под GNU Affero General Public License v3.0 (AGPL-3.0).