Kituwa IT · Self-hosting guides

Install Mattermost with Docker Compose

Self-hosted team chat and calls

chatteamscalls

Mattermost is a self-hosted Slack with threads, markdown, file sharing, voice and video channels, and an integrations framework serious enough that regulated teams run on it. If you need "Slack but ours", this is the one.

Category
Productivity
License
MIT / Enterprise add-ons
Needs
Postgres + Redis
Image
mattermost-team-edition

What it is

Channels, DMs, threads, emoji, slash commands, webhooks in and out, and a plugin marketplace. Mattermost Calls provides built-in voice/video with a Jitsi backend, so you get meetings without running a whole second stack.

Before you start

  • Use the team-edition image. The enterprise-edition tag needs a licence key and will boot into a nag screen without one.
  • Redis needs a maxmemory policy. Without allkeys-lru it will grow until Postgres starts failing and nobody knows why.
  • SMTP is configured by file, not env var, and it is fiddly. Budget time for it — chat that silently fails to send email is worse than no email.

1 — Create the directories

Command / configuration
mkdir -p ~/services/mattermost/{config,data,logs,plugins,client/plugins}
cd ~/services/mattermost

2 — Write the compose file

Command / configuration
services:
  db:
    image: postgres:16-alpine
    container_name: mm-db
    restart: unless-stopped
    environment:
      POSTGRES_USER: mmuser
      POSTGRES_PASSWORD: CHANGE_ME
      POSTGRES_DB: mattermost
    volumes:
      - ./pgdata:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U mmuser"]
      interval: 10s
      timeout: 5s
      retries: 5

  cache:
    image: redis:7-alpine
    container_name: mm-cache
    restart: unless-stopped
    command: >-
      redis-server --requirepass CHANGE_ME
      --maxmemory 256mb --maxmemory-policy allkeys-lru
    healthcheck:
      test: ["CMD", "redis-cli", "-a", "CHANGE_ME", "ping"]
      interval: 30s
      timeout: 5s
      retries: 3

  app:
    image: mattermost/mattermost-team-edition:latest
    container_name: mattermost
    restart: unless-stopped
    depends_on:
      db:
        condition: service_healthy
      cache:
        condition: service_healthy
    ports:
      - "127.0.0.1:8065:8065"
    volumes:
      - ./config:/mattermost/config
      - ./data:/mattermost/data
      - ./logs:/mattermost/logs
      - ./plugins:/mattermost/plugins
      - ./client/plugins:/mattermost/client/plugins
    environment:
      MM_SQLSETTINGS_DATASOURCE: >-
        postgres://mmuser:CHANGE_ME@db:5432/mattermost?sslmode=disable&connect_timeout=10
      MM_SQLSETTINGS_DRIVERNAME: postgres
      MM_SERVICESETTINGS_SITEURL: https://chat.example.com
      MM_SERVICESETTINGS_LISTENADDRESS: ":8065"
      MM_SERVICESETTINGS_ENABLELOCALMODE: "true"
      MM_CACHESETTINGS_CACHETYPE: redis
      MM_CACHESETTINGS_REDISADDRESS: cache:6379
      MM_CACHESETTINGS_REDISPASSWORD: CHANGE_ME
      MM_TEAMSETTINGS_ENABLEUSERACCESSIONS: "true"

3 — Start it

Command / configuration
docker compose up -d
docker compose logs -f app | grep -i "server is listening\|error"

4 — First-run setup

  1. Create the first account in the browser at http://yourhost:8065, then immediately create the System Admin role. The first user is not automatically a system admin.
  2. System Console → Environment → Web Server: set Serve over TLS connections off only if your proxy terminates TLS, and set Websocket URL to wss://chat.example.com. Missing that wss setting is why live typing sometimes turns into a spinner.
  3. System Console → Environment → Email: set SMTP. Send yourself a test and read the result in ./logs before declaring it done.
  4. Under Integrations, create an incoming webhook for notifications and an outgoing one for your own automations. This is the single most useful feature in the product.

5 — Back it up

Command / configuration
docker exec -u mmuser mm-db pg_dump -U mmuser mattermost | gzip > mm-$(date +%F).sql.gz
tar -czf mm-plugins.tgz ./plugins ./client/plugins
Mattermost is chat history you cannot get backWithout a Postgres dump, losing the volume means losing every message, DM and attachment in the workspace. Schedule it in cron and, more importantly, copy the dump off the machine.

Help when you need it

Want help getting this running?

We can help with a supported Linux host, application setup, migration or troubleshooting. Contact us to confirm the software, scope and scheduling before ordering.

Related guides

← Browse all 30 guides · Back to top