MAATRIX / Блог / Matrix (Synapse) на сервере: частые ошибки и решения

Matrix (Synapse) на сервере: частые ошибки и решения

MAATRIX

Свой сервер Matrix ставят ради простой идеи: сообщения со сквозным шифрованием, которые не зависят от чужой инфраструктуры. Synapse — эталонная реализация протокола — разворачивается за полчаса, а дальше начинаются вопросы: почему сервер не виден в федерации, почему PostgreSQL отказывается стартовать, почему за месяц диск съеден медиафайлами. Ниже — разбор конкретных проблем с командами и конфигами, а не общий обзор протокола.

Обсудить статью, задать вопрос или начать новую тему

Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.

Перейти в сообщество →

С чего начинать диагностику Synapse

Synapse — это Python-приложение, которое обычно живёт под systemd и слушает локальный порт (по умолчанию 8008), а наружу его выводит reverse-proxy. Первый источник правды — логи самого сервиса:

journalctl -u matrix-synapse -f --no-pager

Если Synapse настроен по умолчанию, отдельный лог-файл тоже есть — путь задаётся в log_config внутри homeserver.yaml, обычно это /var/log/matrix-synapse/homeserver.log. Там видны трейсбеки Python, а не просто HTTP-коды, поэтому именно этот файл читайте в первую очередь при падении процесса.

Второй шаг — проверить, что сервер вообще отвечает локально, до всякого reverse-proxy:

curl -s http://127.0.0.1:8008/_matrix/client/versions

Если это отдаёт JSON со списком версий протокола — Synapse жив, и проблема снаружи, в nginx, DNS или файрволе. Если соединение не устанавливается — смотрите systemctl status matrix-synapse и ищите причину именно в самом процессе: не хватает памяти, не поднялась база, битый homeserver.yaml. Разделение «жив ли Synapse локально» и «виден ли он снаружи» экономит массу времени: не нужно гадать, в каком слое сбой.

Федерация не работает: сервер не виден снаружи

Самая частая жалоба владельцев свежего сервера: локальный чат работает, но пользователи с других серверов Matrix не могут написать. Проверка начинается с Federation Tester — вставьте туда server_name из конфига и посмотрите, что он видит.

Здесь есть тонкость, которая ломает федерацию чаще всего: server_name в homeserver.yaml — это ваш основной домен (например, example.com), а сам Synapse обычно крутится на поддомене вроде matrix.example.com. Чтобы другие серверы поняли, куда стучаться, нужна делегация через .well-known, отдаваемый именно с основного домена по HTTPS:

# https://example.com/.well-known/matrix/server
{
  "m.server": "matrix.example.com:443"
}
# https://example.com/.well-known/matrix/client
{
  "m.homeserver": {
    "base_url": "https://matrix.example.com"
  }
}

Частая ошибка — отдать этот JSON с неправильным Content-Type (должен быть application/json) или забыть, что файл должен читаться именно с корневого домена, а не с поддомена Synapse. Если делегация настроена верно, но федерация всё равно не видит сервер, проверьте, что порт 8448 (или тот, что указан после : в m.server) открыт файрволом наружу — федерация ходит именно туда, а не только по 443 клиентского трафика.

Второй вариант делегации — SRV-запись _matrix._tcp.example.com, если управлять .well-known-файлами неудобно. Оба способа равноценны, но смешивать их не стоит: выбирайте один и проверяйте результат тем же Federation Tester после каждого изменения DNS, с учётом TTL записи.

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать сервер

Ошибки PostgreSQL и локали базы

На SQLite Synapse стартует «из коробки», но для рабочего сервера с несколькими комнатами и пользователями официально рекомендуют PostgreSQL — SQLite не тянет параллельные запросы и заметно медленнее на federation join в крупные комнаты. При переходе на Postgres чаще всего ловят одну и ту же ошибку при первом запуске:

Database has incorrect collation of "en_US.UTF-8", expected "C"

Synapse требует, чтобы база была создана с локалью C — иначе сортировка строк работает иначе, чем ожидает код, и это может привести к тонким багам в дедупликации событий. База создаётся так:

CREATE ROLE synapse_user WITH LOGIN PASSWORD 'пароль';
CREATE DATABASE synapse
  ENCODING 'UTF8'
  LC_COLLATE 'C'
  LC_CTYPE 'C'
  TEMPLATE template0
  OWNER synapse_user;

Если база уже создана с неправильной локалью и в ней есть данные, пересоздать её на лету нельзя — единственный надёжный путь это дамп через pg_dump, создание новой базы с LC_COLLATE 'C' и восстановление в неё. Проще сделать это правильно один раз при установке, чем чинить постфактум. Секция подключения в homeserver.yaml:

database:
  name: psycopg2
  args:
    user: synapse_user
    password: пароль
    database: synapse
    host: 127.0.0.1
    cp_min: 5
    cp_max: 10

Общие проблемы с самим PostgreSQL — отказ принимать подключения, рост WAL, медленный vacuum — разобраны отдельно в статье про частые ошибки PostgreSQL на сервере: всё это применимо и к базе Synapse, у неё нет специфики в этой части.

Nginx как reverse-proxy перед Synapse: типичные проблемы

Synapse почти никогда не смотрит наружу напрямую — перед ним ставят nginx, который терминирует TLS и проксирует запросы на локальный порт 8008. Минимальный рабочий блок для поддомена matrix.example.com:

server {
    listen 443 ssl http2;
    server_name matrix.example.com;

    location ~ ^(/_matrix|/_synapse/client) {
        proxy_pass http://127.0.0.1:8008;
        proxy_set_header X-Forwarded-For $remote_addr;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header Host $host;
        client_max_body_size 50M;
        proxy_read_timeout 120s;
    }
}

Два параметра здесь ломают в первую очередь. Первый — client_max_body_size: по умолчанию nginx режет тело запроса на 1 МБ, а Synapse позволяет грузить аватары и вложения крупнее — в ответ клиент получает 413 Request Entity Too Large без внятного пояснения. Значение здесь должно соответствовать max_upload_size в homeserver.yaml, иначе одно из двух ограничений станет бесполезным. Второй — proxy_read_timeout: клиенты Matrix держат долгий long-poll запрос /sync, ожидая новых событий, и слишком короткий таймаут рвёт это соединение раньше времени, из-за чего клиент выглядит «подвисшим» и постоянно переподключается.

Если federation-порт 8448 тоже проксируется через nginx (а не пробрасывается напрямую в Synapse), для него нужен отдельный server-блок с тем же proxy_pass, но своим сертификатом — федерация проверяет TLS так же строго, как обычный HTTPS-клиент. Общие принципы reverse-proxy — 502, битые заголовки, обрыв WebSocket — подробно разобраны в статье про nginx как reverse-proxy, а получение и обновление сертификатов — в материале про Let's Encrypt на сервере.

Регистрация и вход: shared secret, лимиты, ошибки

По умолчанию свежий Synapse запрещает открытую регистрацию — это правильно для сервера, который не должен превратиться в открытую точку спама. Первого администратора создают через shared secret, заданный в конфиге:

registration_shared_secret: "длинная-случайная-строка"
register_new_matrix_user -c homeserver.yaml http://localhost:8008

Частая ошибка — забыть перезапустить Synapse после добавления registration_shared_secret в конфиг: утилита подключается к живому серверу, а не читает конфиг напрямую, поэтому без reload она откажет с ошибкой авторизации. Если вы сознательно открываете регистрацию для команды или сообщества (enable_registration: true), обязательно включите капчу или email-верификацию через registrations_require_3pid, иначе сервер быстро станет мишенью ботов-регистраторов.

Вторая типичная жалоба — пользователи получают M_LIMIT_EXCEEDED при частых попытках входа или отправке сообщений. Это встроенный rate limiting Synapse, а не сбой. Пороги настраиваются точечно, например для логина:

rc_login:
  address:
    per_second: 0.17
    burst_count: 3

Понижать эти лимиты стоит с осторожностью — они же защищают сервер от подбора паролей и флуда, и слишком мягкие настройки открывают дорогу к тем же атакам, от которых лимиты изначально введены.

Медиа-хранилище, диск и производительность

Диск, отведённый под Synapse, растёт быстрее, чем кажется на старте — и не только от файлов, которые загрузили ваши пользователи. В комнатах с федерацией сервер кеширует у себя медиа с чужих серверов: чужие аватары, картинки, стикеры. Эта копия хранится в media_store_path и никуда не девается сама по себе — Synapse не удаляет её автоматически.

Проверить, что именно занимает место, и почистить кеш удалённого медиа старше определённого возраста можно через Admin API (нужен токен администратора):

curl -X POST \
  -H "Authorization: Bearer TOKEN" \
  "http://127.0.0.1:8008/_synapse/admin/v1/purge_media_cache?before_ts=1735689600000"

Это удаляет только кеш чужого медиа, а не файлы, загруженные вашими пользователями, — их работа остаётся нетронутой. Для регулярной чистки такую команду удобно повесить в cron с датой «месяц назад» вместо фиксированного before_ts.

Отдельная категория роста — не файлы, а сама база: история состояний в больших и старых комнатах (state_groups) может занимать неожиданно много места из-за того, как Matrix переигрывает разрешение конфликтов состояния. Официальный инструмент synapse-compress-state сжимает эту историю без потери данных комнаты — полезно применить его, если база растёт заметно быстрее, чем объём реальной переписки.

На нагрузку по CPU и памяти сильнее всего влияет число одновременно активных комнат с федерацией — каждая требует обработки state resolution при любом сообщении. Для одного небольшого сообщества обычно хватает пары ядер и 2–4 ГБ RAM, но это грубый ориентир: у вас может отличаться в разы в зависимости от размера комнат и числа федеративных участников. Если однопроцессный Synapse упирается в потолок, следующий шаг — разделение на воркеры (federation sender, generic worker, stream writers) поверх Redis для репликации между ними; это уже полноценная многопроцессная архитектура, а не просто настройка конфига, и имеет смысл только когда монолитный процесс объективно не справляется. Развёртывать такую связку удобнее через docker compose — общие грабли такого подхода в продакшене разобраны в статье про docker compose для продакшена.

Для самого Synapse и базы данных под ним важна не только память, но и скорость диска: NVMe заметно снижает задержки на state resolution по сравнению с сетевыми дисками. Если сервер стабильно упирается в ресурсы, проще взять VPS с запасом RAM и NVMe сразу, чем постоянно тюнинговать конфиг под нехватку железа — у MAATRIX это можно сделать в локациях RU, US или UK с оплатой из России картой или криптой.

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать сервер

Нужны сами нейросети для контента?

Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.

Частые вопросы

Почему федерация видит мой сервер, но сообщения от других серверов не доходят?

Чаще всего дело в неоткрытом порте 8448 наружу или в устаревшем DNS-кеше делегации — перепроверьте через Federation Tester после изменения TTL записи.

Можно ли обойтись без PostgreSQL и остаться на SQLite?

Технически да, но для рабочего сервера с федерацией и несколькими пользователями это не рекомендуется — SQLite не держит параллельные запросы, и производительность заметно падает на больших комнатах.

Что делать, если Synapse не стартует после обновления версии?

Смотрите journalctl -u matrix-synapse -f — почти всегда там есть трейсбек с точной причиной, включая незавершённые миграции базы, которые нужно дождаться перед повторным запуском.

Как ограничить размер загружаемых файлов?

Параметром max_upload_size в homeserver.yaml, но не забудьте синхронизировать это значение с client_max_body_size в nginx — иначе одно из двух ограничений сработает раньше другого.

Почему диск заполняется, даже если пользователи почти ничего не загружают?

Скорее всего растёт кеш чужого медиа из федеративных комнат в media_store_path — почистите его через Admin API purge_media_cache и настройте это по расписанию.

Обсудить статью, задать вопрос или начать новую тему

Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.

Перейти в сообщество →