MAATRIX / Блог / Mattermost в Docker Compose: готовый файл

Mattermost в Docker Compose: готовый файл

MAATRIX

Команда переросла общий чат в Telegram, а платить за Slack по количеству голов не хочется — тем более что переписка компании тогда лежит на чужих серверах. Mattermost закрывает эту задачу: open-source мессенджер с каналами, тредами, интеграциями и API, который разворачивается на своём сервере за 15 минут через один docker-compose.yml. Ниже — рабочий файл, который выдерживает продакшн-нагрузку небольшой команды, плюс HTTPS, бэкап и обновления без сюрпризов.

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

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

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

Архитектура: что входит в стек и зачем

Минимальный продакшн-стек Mattermost — это два контейнера:

  • mattermost — само приложение (Go-бэкенд + React-фронтенд в одном образе), слушает порт 8065;
  • postgres — база данных, где хранятся сообщения, пользователи, настройки каналов.

Файлы, плагины и загруженные вложения Mattermost хранит на диске, а не только в базе — под них нужны отдельные volume'ы, иначе при пересоздании контейнера вы потеряете все прикреплённые файлы и логи. Снаружи стек закрывает обратный прокси (nginx или Caddy) — он терминирует TLS и правильно проксирует WebSocket-соединения, через которые Mattermost доставляет сообщения в реальном времени.

Схема каталогов на хосте:

mattermost/
├── docker-compose.yml
├── .env
└── volumes/
    ├── db/                  # данные PostgreSQL
    └── app/mattermost/
        ├── config/
        ├── data/            # вложения, аватары
        ├── logs/
        ├── plugins/
        ├── client/plugins/
        └── bleve-indexes/   # поисковый индекс

Ресурсы: для команды до 30–50 человек хватает 2 vCPU и 4 ГБ RAM — при этом 1–1.5 ГБ уйдёт под PostgreSQL, остальное под сам Mattermost. На 100+ активных пользователей закладывайте 4 vCPU / 8 ГБ и SSD-диск — база растёт быстро за счёт истории сообщений и поискового индекса.

Готовый docker-compose.yml

Создайте рабочую директорию и подготовьте volume'ы с правильными правами (Mattermost внутри контейнера работает от пользователя с UID 2000):

mkdir -p mattermost/volumes/{db,app/mattermost/{config,data,logs,plugins,client/plugins,bleve-indexes}}
cd mattermost
sudo chown -R 2000:2000 volumes/app

Файл .env:

POSTGRES_USER=mmuser
POSTGRES_PASSWORD=замените_на_свой_сложный_пароль
POSTGRES_DB=mattermost
MM_SITEURL=https://chat.example.com

Файл docker-compose.yml:

services:
  postgres:
    image: postgres:16-alpine
    restart: unless-stopped
    env_file: .env
    environment:
      POSTGRES_USER: ${POSTGRES_USER}
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
      POSTGRES_DB: ${POSTGRES_DB}
    volumes:
      - ./volumes/db:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER}"]
      interval: 10s
      timeout: 5s
      retries: 5
    networks:
      - mattermost

  mattermost:
    image: mattermost/mattermost-team-edition:latest
    restart: unless-stopped
    depends_on:
      postgres:
        condition: service_healthy
    env_file: .env
    environment:
      MM_SQLSETTINGS_DRIVERNAME: postgres
      MM_SQLSETTINGS_DATASOURCE: "postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB}?sslmode=disable&connect_timeout=10"
      MM_SERVICESETTINGS_SITEURL: ${MM_SITEURL}
      MM_BLEVESETTINGS_INDEXDIR: /mattermost/bleve-indexes
    volumes:
      - ./volumes/app/mattermost/config:/mattermost/config
      - ./volumes/app/mattermost/data:/mattermost/data
      - ./volumes/app/mattermost/logs:/mattermost/logs
      - ./volumes/app/mattermost/plugins:/mattermost/plugins
      - ./volumes/app/mattermost/client/plugins:/mattermost/client/plugins
      - ./volumes/app/mattermost/bleve-indexes:/mattermost/bleve-indexes
    ports:
      - "127.0.0.1:8065:8065"
    healthcheck:
      test: ["CMD", "wget", "-qO-", "http://localhost:8065/api/v4/system/ping"]
      interval: 30s
      timeout: 10s
      retries: 3
    ulimits:
      nofile:
        soft: 65536
        hard: 65536
    networks:
      - mattermost

networks:
  mattermost:
    driver: bridge

Порт 8065 намеренно опубликован только на 127.0.0.1 — наружу приложение отдаёт обратный прокси, а не сам контейнер. Это отдельный слой защиты: даже если в firewall что-то пойдёт не так, порт Mattermost не будет торчать в интернет напрямую.

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

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

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

Первый запуск и создание администратора

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

docker compose up -d
docker compose logs -f mattermost

Первый пользователь, который зарегистрируется через веб-интерфейс, автоматически становится системным администратором — поэтому сразу после запуска зайдите на http://ваш-ip:8065 (или домен, если прокси уже настроен) и создайте аккаунт, прежде чем это сделает кто-то ещё. Если сервер уже смотрит в открытый интернет без прокси — на время первичной настройки лучше временно закрыть 8065 в firewall и открыть его только для своего IP.

После создания администратора сразу отключите открытую регистрацию, если она не нужна: System Console → Authentication → SignupEnable Open Server = false. Иначе зарегистрироваться на вашем сервере сможет кто угодно, кто узнает адрес.

HTTPS через обратный прокси

Mattermost активно использует WebSocket для live-обновлений — обычный прокси-конфиг без Upgrade-заголовков будет обрывать соединения раз в минуту, и пользователи будут жаловаться на «зависающий» чат. Пример конфига для nginx (устанавливается и настраивается по общей схеме, описанной в статье про nginx как обратный прокси):

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;

    location / {
        proxy_pass http://127.0.0.1:8065;
        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;
    }
}

Если предпочитаете не возиться с certbot вручную, Caddy получает сертификат сам — конфиг короче в разы (см. Caddy с авто-SSL):

chat.example.com {
    reverse_proxy 127.0.0.1:8065
}

Caddy сам добавляет заголовки Upgrade/Connection для WebSocket, отдельно прописывать их не нужно.

Резервное копирование и обновление

Бэкапить нужно две вещи отдельно: базу PostgreSQL и файловое хранилище (data/, вложения и аватары). Простой скрипт для крон-задания:

#!/bin/bash
BACKUP_DIR=/backups/mattermost
DATE=$(date +%Y%m%d_%H%M%S)
mkdir -p "$BACKUP_DIR"

docker compose exec -T postgres pg_dump -U mmuser mattermost \
  | gzip > "$BACKUP_DIR/db_$DATE.sql.gz"

tar czf "$BACKUP_DIR/data_$DATE.tar.gz" \
  -C volumes/app/mattermost data config

find "$BACKUP_DIR" -mtime +14 -delete

Если данных много, для отдельного бэкапа volume'ов удобнее специализированный инструмент — общий подход к бэкапу докер-томов разобран в статье про бэкап Docker volume.

Обновление — стандартный для docker compose цикл, но перед ним обязателен свежий бэкап (миграции схемы БД при апгрейде необратимы без отката из бэкапа):

# сначала бэкап (см. выше)
docker compose pull mattermost
docker compose up -d mattermost
docker compose logs -f mattermost   # проверить, что миграции прошли без ошибок

Mattermost выпускает релизы примерно раз в месяц; переходить сразу на самую свежую версию не обязательно — можно пропускать промежуточные, но не перепрыгивать через мажорные версии за один раз, если апгрейдите сервер, который давно не обновлялся.

Продакшн-настройки: почта, лимиты, безопасность

Часть настроек удобнее задать переменными окружения в .env, чтобы они не терялись при пересоздании конфига через веб-интерфейс:

# уведомления по почте
MM_EMAILSETTINGS_SENDEMAILNOTIFICATIONS=true
MM_EMAILSETTINGS_SMTPSERVER=smtp.example.com
MM_EMAILSETTINGS_SMTPPORT=587
MM_EMAILSETTINGS_SMTPUSERNAME=mattermost@example.com
MM_EMAILSETTINGS_SMTPPASSWORD=пароль_smtp
MM_EMAILSETTINGS_ENABLESMTPAUTH=true
MM_EMAILSETTINGS_CONNECTIONSECURITY=STARTTLS

# ограничение размера загружаемых файлов (в байтах, здесь 100 МБ)
MM_FILESETTINGS_MAXFILESIZE=104857600

Добавьте их в блок environment сервиса mattermost в docker-compose.yml (или используйте env_file, ссылаясь на переменные напрямую — Mattermost читает MM_*-переменные при старте и они перекрывают config.json).

Из практических моментов безопасности:

  • держите PostgreSQL и Mattermost в отдельной bridge-сети без публикации портов БД наружу (в примере выше это уже так — у postgres нет секции ports);
  • ограничьте вход в System Console через Guest Access и Multi-factor Authentication — MFA включается в пару кликов и закрывает основной риск компрометации аккаунта;
  • если сервер смотрит в интернет напрямую, добавьте fail2ban на nginx-логи — методика описана в статье про fail2ban для nginx;
  • регулярно проверяйте docker compose logs mattermost | grep -i error — Mattermost логирует неудачные попытки входа и ошибки интеграций в общий лог-поток.

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

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

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

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

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

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

Нужен ли отдельный сервер под Mattermost или хватит того же VPS, где уже что-то крутится?

Для команды до 20–30 человек хватает 2 vCPU / 4 ГБ RAM даже при совместном использовании с другими лёгкими сервисами — но PostgreSQL под Mattermost лучше не делить с другими нагруженными базами на том же диске, чтобы не ловить конкуренцию за I/O.

Чем Team Edition отличается от Enterprise?

Team Edition (используется в этом конфиге) бесплатна и включает каналы, треды, звонки, интеграции и API. Enterprise добавляет SSO/SAML, расширенные политики соответствия и AD/LDAP — для большинства небольших команд это не критично.

Как перенести Mattermost на другой сервер?

Останавливаете стек, копируете папку volumes/ целиком (или восстанавливаете из бэкапа по схеме выше) вместе с docker-compose.yml и .env, поднимаете docker compose up -d на новом сервере, обновляете DNS-запись на новый IP.

Можно ли подключить свой домен и получить сертификат бесплатно?

Да, Let's Encrypt через certbot или встроенный механизм Caddy — оба варианта показаны выше, оба бесплатны и продлеваются автоматически.

Почему после развёртывания браузер жалуется на «небезопасное соединение»?

Значит, вы зашли напрямую на :8065 без прокси и SSL, либо сертификат ещё не выпущен. Проверьте, что nginx/Caddy запущен и слушает 443, а DNS-запись домена уже указывает на IP сервера.

Как включить push-уведомления на телефон?

По умолчанию Mattermost использует публичный push-прокси-сервис проекта; для полностью self-hosted варианта нужно поднимать собственный Push Proxy Server отдельно — это отдельная и не обязательная для старта задача.

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

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

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