Mattermost на сервере: частые ошибки и решения
Mattermost — самый популярный self-hosted аналог Slack, но развернуть его «по инструкции» и получить рабочую систему без сюрпризов — разные вещи. Половина проблем всплывает не на этапе установки, а через неделю эксплуатации: перестают приходить уведомления, обрывается WebSocket, не грузятся файлы больше определённого размера. Ниже — конкретные ошибки, с которыми реально сталкиваешься при запуске Mattermost на своём сервере, и как их закрыть.
Содержание
- Nginx не пробрасывает WebSocket — чат "залипает"
- Файлы не загружаются или обрываются на середине
- PostgreSQL: подключения обрываются или база "не успевает"
- Push-уведомления не приходят на телефон
- Docker Compose: контейнер стартует и сразу падает
- Поиск по сообщениям работает медленно или не находит ничего
- На каком сервере разворачивать Mattermost и сколько ресурсов закладывать
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →Nginx не пробрасывает WebSocket — чат "залипает"
Самая частая жалоба на self-hosted Mattermost: сообщения не появляются в реальном времени, статус "печатает" не работает, приходится обновлять страницу руками. Причина почти всегда одна — nginx как reverse proxy перед Mattermost не настроен на апгрейд соединения до WebSocket.
Mattermost использует один и тот же порт (по умолчанию 8065) и для обычных HTTP-запросов, и для WebSocket-соединения (/api/v4/websocket). Если в конфиге nginx нет заголовков Upgrade и Connection, браузер откатывается на long polling или вовсе теряет связь после разрыва.
Рабочий блок для nginx:
upstream mattermost_backend {
server 127.0.0.1:8065;
keepalive 32;
}
server {
listen 443 ssl http2;
server_name chat.example.com;
ssl_certificate /etc/letsencrypt/live/chat.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/chat.example.com/privkey.pem;
client_max_body_size 100M;
location / {
proxy_pass http://mattermost_backend;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_read_timeout 600s;
proxy_send_timeout 600s;
}
}
Ключевые моменты: proxy_http_version 1.1 обязателен, потому что WebSocket не работает по HTTP/1.0. Connection "upgrade" (именно так, с большой буквы в значении заголовка, а не переменная $connection_upgrade, если вы не объявили её map-блоком отдельно) переключает соединение. И proxy_read_timeout стоит поднять выше дефолтных 60 секунд — иначе nginx рвёт долгоживущее WebSocket-соединение сам, даже если сервер Mattermost жив. Подробнее про типовые грабли самого nginx как proxy разобрано в статье про nginx как reverse proxy.
Если у вас Caddy вместо nginx — задача проще: Caddy апгрейдит WebSocket автоматически при reverse_proxy, никаких дополнительных заголовков прописывать не нужно.
Файлы не загружаются или обрываются на середине
Вторая по частоте боль — вложения. Пользователь пытается прикрепить файл 30-40 МБ, загрузка виснет на середине или сразу падает с ошибкой "413 Request Entity Too Large". Здесь накладываются сразу три лимита, и нужно поднять все три:
- Nginx — параметр
client_max_body_sizeв конфиге сервера или location (см. пример выше, 100M). - Сам Mattermost — в
config.jsonили через System Console → Environment → File Storage есть параметрMaxFileSize(в байтах). По умолчанию это 100 МБ (104857600), но если вы подняли лимит в nginx, а в Mattermost не подняли — упрётесь в него раньше. - Если используете S3-совместимое хранилище (MinIO, Cloudflare R2) вместо локального диска — там свои таймауты на upload, особенно при multipart.
Проверить и поднять лимит в Mattermost:
{
"FileSettings": {
"MaxFileSize": 524288000,
"DriverName": "local",
"Directory": "/opt/mattermost/data/"
}
}
После правки config.json нужен рестарт сервиса:
sudo systemctl restart mattermost
Если файлы хранятся локально — проверьте ещё и права на директорию data/, владелец должен совпадать с пользователем, от которого запущен сервис Mattermost (обычно mattermost:mattermost), иначе загрузка падает с невнятной ошибкой в UI и понятной в логе mattermost.log.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверPostgreSQL: подключения обрываются или база "не успевает"
Mattermost из коробки хорошо работает с PostgreSQL, но на серверах с ограниченной памятью или при росте команды до 50-100+ активных пользователей начинают вылезать ошибки вида pq: sorry, too many clients already или подтормаживание поиска по сообщениям.
Типичная причина — дефолтный max_connections в PostgreSQL (обычно 100) съедается не только Mattermost, но и фоновыми джобами, ботами, интеграциями. Mattermost сам держит пул соединений, настраиваемый в config.json:
{
"SqlSettings": {
"DataSourceReplicas": [],
"MaxIdleConns": 20,
"MaxOpenConns": 300,
"ConnMaxLifetimeMilliseconds": 3600000
}
}
Если MaxOpenConns у Mattermost больше, чем max_connections у самого PostgreSQL, при пиковой нагрузке начнутся обрывы. Проверьте текущий лимит и поднимите его в postgresql.conf:
max_connections = 200
shared_buffers = 512MB
После изменения max_connections PostgreSQL нужно перезапустить (это не параметр, применяемый на лету):
sudo systemctl restart postgresql
Ориентируйтесь на то, что каждое соединение PostgreSQL — это реальная память процесса на стороне сервера, поэтому слепо задирать max_connections до тысячи на сервере с 2 ГБ RAM не стоит — вы упрётесь в OOM раньше, чем в лимит подключений. Общие подходы к диагностике PostgreSQL под нагрузкой разобраны в статье про частые ошибки PostgreSQL на сервере, а если команда растёт быстро — пригодится и материал про тюнинг PostgreSQL.
Push-уведомления не приходят на телефон
Web-версия и десктоп-клиент показывают сообщения нормально, а мобильные push не долетают — классика self-hosted мессенджеров. У Mattermost по умолчанию push-уведомления идут через собственный HPNS (Hosted Push Notification Service) от Mattermost Inc., который требует исходящего доступа с вашего сервера к их инфраструктуре.
Что стоит проверить по порядку:
- Исходящий трафик наружу. Если сервер стоит за строгим firewall, HPNS не достучится. Проверьте, что исходящие соединения на 443 порт разрешены.
- Настройки в System Console → Environment → Push Notification Server. URL по умолчанию
https://push.mattermost.com— если он случайно затёрт при копировании конфига с чужого сервера, push молчит без явной ошибки в UI. - Собственный push-сервер. Если не хотите зависеть от инфраструктуры Mattermost Inc., можно поднять свой TPNS (Team Push Notification Service) — отдельный компонент через Docker, но требует собственных сертификатов APNs (iOS) и FCM (Android). Для команд до пары сотен человек это избыточно, дефолтный HPNS справляется.
Если push не работает именно на iOS при рабочем Android — почти всегда дело в specifics APNs-сертификата на стороне HPNS, тут стоит написать в поддержку Mattermost с ID своей инсталляции, локально это не чинится.
Docker Compose: контейнер стартует и сразу падает
Если вы разворачиваете Mattermost через официальный docker-compose.yml, частая ситуация — контейнер mattermost уходит в restart loop сразу после docker compose up -d. Первое, что нужно посмотреть:
docker compose logs mattermost --tail 100
Три типичные причины в логах:
- База данных ещё не готова, когда стартует Mattermost (нет
depends_onсcondition: service_healthyдля контейнера PostgreSQL). Решение — healthcheck в compose-файле:
services:
postgres:
image: postgres:15-alpine
healthcheck:
test: ["CMD-SHELL", "pg_isready -U mmuser"]
interval: 5s
timeout: 5s
retries: 5
mattermost:
depends_on:
postgres:
condition: service_healthy
- Неверные права на volume. Официальный образ Mattermost запускается не от root, и если директории
./volumes/app/mattermost/data,logs,configбыли созданы от root вручную — процесс внутри контейнера не может в них писать. Лечится черезchownна UID 2000 (стандартный UID пользователя mattermost в образе):
sudo chown -R 2000:2000 ./volumes/app/mattermost/
- Переменные окружения базы не совпадают между сервисом
postgresиmattermost(разный пароль, имя базы) — тогда в логах прямая ошибка аутентификации, это самый очевидный случай.
Общие подходы к диагностике падающих контейнеров — в статье про контейнеры, которые не запускаются, а для более широкого стека пригодится материал про production-конфигурацию docker compose.
Поиск по сообщениям работает медленно или не находит ничего
По умолчанию Mattermost использует встроенный полнотекстовый поиск PostgreSQL (tsvector). На малых и средних командах этого достаточно, но на объёме в сотни тысяч сообщений поиск начинает тормозить, а иногда не находит очевидные совпадения — особенно с русским текстом, если конфигурация PostgreSQL не учитывает нужный language config для полнотекстового индекса.
Что можно сделать без смены архитектуры:
- Проверить, что индекс полнотекстового поиска действительно построен:
SELECT * FROM pg_indexes WHERE tablename = 'posts';— должен быть индекс поsearchvectorили аналогичному полю в зависимости от версии. - Убедиться, что
full-text search languageв System Console соответствует реальному языку контента команды (влияет на стемминг — поиск "сервера" может не находить "сервер" при неверной конфигурации).
Для команд от нескольких сотен активных пользователей с большой историей сообщений Mattermost поддерживает Elasticsearch как внешний поисковый движок (доступность этой функции зависит от редакции и лицензии, уточняйте актуальные условия на момент внедрения). Он снимает нагрузку с базы и ускоряет поиск, но добавляет ещё один сервис на поддержке — закладывайте от 2 ГБ RAM только под него.
На каком сервере разворачивать Mattermost и сколько ресурсов закладывать
Mattermost сам по себе не тяжёлый по CPU, но состоит минимум из трёх компонентов, каждому из которых нужна память: сам сервис Mattermost (Go-приложение), PostgreSQL и nginx/Caddy перед ними. Ориентировочные рамки для команды на своём сервере (это именно ориентир, а не точный расчёт — реальное потребление зависит от активности, числа интеграций и объёма истории):
| Размер команды | vCPU | RAM | Диск |
|---|---|---|---|
| до 20 человек | 2 | 4 ГБ | 40 ГБ SSD |
| 20-100 человек | 2-4 | 8 ГБ | 80-160 ГБ SSD |
| 100-500 человек | 4-8 | 16 ГБ | от 250 ГБ SSD |
Диск важнее CPU — активная команда с обменом файлами быстро съедает место, особенно если ретеншн вложений не настроен. Если часть команды работает из России, а Mattermost используется ещё и для звонков через интеграции, стоит заранее определиться с локацией сервера — сравнение вариантов в статье про выбор между Россией и США для мессенджеров и звонков.
Mattermost хорошо ложится на обычный VPS с Ubuntu 24.04 или Debian 12, устанавливается либо .deb-пакетом через systemd, либо через Docker Compose — оба пути официально поддерживаются.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверНужны сами нейросети для контента?
Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.
Частые вопросы
Можно ли перенести Mattermost на другой сервер без потери истории сообщений?
Да. Официальный способ — mmctl для экспорта/импорта воркспейса или прямой перенос данных PostgreSQL (pg_dump/pg_restore) вместе с директорией файлов (data/). Важно перенести оба компонента синхронно, иначе ссылки на вложения в базе не будут совпадать с реальными файлами.
Нужен ли отдельный сервер под PostgreSQL или можно на одном сервере с Mattermost?
Для команд до пары сотен человек одного сервера достаточно — Mattermost и PostgreSQL спокойно живут рядом, если правильно поделить память между shared_buffers PostgreSQL и остальными процессами. Вынос базы на отдельный сервер имеет смысл при большой нагрузке или требованиях к отказоустойчивости.
Чем self-hosted Mattermost отличается от облачной версии по возможностям?
Открытая (Team Edition) версия покрывает основной функционал — каналы, треды, звонки через плагин, интеграции по webhook. Часть функций (продвинутый поиск через Elasticsearch, SSO через SAML, детальные политики доступа) относится к платным Enterprise-планам поверх той же кодовой базы.
Что делать, если после обновления Mattermost сервис не стартует?
Первым делом — бэкап базы данных перед любым обновлением (миграции схемы необратимы штатными средствами). Если сервис не поднимается после апдейта, смотрите mattermost.log — почти всегда там явно указано, какая миграция не прошла или какого поля не хватает в конфиге после смены версии.
Как ограничить регистрацию новых пользователей без приглашения?
В System Console → Authentication → Signup выключите Enable Open Server и настройте домены email, с которых разрешена регистрация, либо переключитесь на инвайт-ссылки — это закрывает самый частый вектор случайной публичной регистрации на self-hosted инсталляции, забытой открытой наружу.
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →