Docs / Self-host from scratch
Self-host from scratch
A complete Docker Compose stack running the Mattermore server image and PostgreSQL, with group calls and no 250 user limit from the first boot.
This page runs the Mattermore server image, our build of Mattermost itself.
That is what lifts the 250 user limit, single sign-on and guest accounts, as
well as the call features. The official mattermost/mattermost-team-edition
image does not: the user limit is enforced in the server, so no plugin can
remove it.
If your current server runs Mattermost v10 on MySQL, see Migrate from MySQL first: the Mattermore image only runs on PostgreSQL.
If you already run official Mattermost and only want group calls, the install guide covers that with a plugin upload. It leaves the user limit in place.
What you need
- A Linux host with Docker and the Compose plugin
- A domain pointing at it, if you want TLS
- UDP port 8443 open, plus TCP 8443 as a fallback, or calls will connect and then drop
1. Create the stack
Make a directory and save this as compose.yaml:
services:
postgres:
image: postgres:15-alpine
restart: unless-stopped
environment:
POSTGRES_USER: mmuser
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?set POSTGRES_PASSWORD in .env}
POSTGRES_DB: mattermost
volumes:
- postgres:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U mmuser -d mattermost"]
interval: 10s
timeout: 5s
retries: 5
mattermost:
image: ghcr.io/dennisklappe/mattermore:latest
restart: unless-stopped
depends_on:
postgres:
condition: service_healthy
environment:
MM_SQLSETTINGS_DRIVERNAME: postgres
MM_SQLSETTINGS_DATASOURCE: >-
postgres://mmuser:${POSTGRES_PASSWORD}@postgres:5432/mattermost?sslmode=disable&connect_timeout=10
MM_SERVICESETTINGS_SITEURL: ${SITE_URL:?set SITE_URL in .env}
# Group calls in every channel.
MM_CALLS_GROUP_CALLS_ALLOWED: "true"
ports:
- "8065:8065"
- "8443:8443/udp"
- "8443:8443/tcp"
volumes:
- mm-config:/mattermost/config
- mm-data:/mattermost/data
- mm-logs:/mattermost/logs
- mm-plugins:/mattermost/plugins
- mm-client-plugins:/mattermost/client/plugins
volumes:
postgres:
mm-config:
mm-data:
mm-logs:
mm-plugins:
mm-client-plugins:
Then a .env beside it:
POSTGRES_PASSWORD=use-a-long-random-string-here
SITE_URL=https://chat.example.com
SITE_URL must match the address people actually type. Calls will not connect
if it is wrong, and it is the single most common cause of a broken setup.
2. Start it
docker compose up -d
Open SITE_URL and create the first account. That account becomes the system
administrator.
3. Nothing to install
The image already contains the Mattermore server and the Mattermore calls plugin. There is no plugin to upload. To confirm you are running it, open System Console › Plugins › Calls: it reports itself as Calls (Mattermore).
4. Check it works
- Open a channel that is not a direct message
- The call button appears in the channel header
- Start a call and have two colleagues join
Three participants is the test that matters. Two would work on stock Mattermost as well.
Putting it behind TLS
Mattermost serves plain HTTP on 8065. Terminate TLS in front of it, and make sure WebSocket upgrades pass through. A minimal Caddy config:
chat.example.com {
reverse_proxy localhost:8065
}
Leave port 8443 alone. Calls media does not go through the reverse proxy, it talks to the server directly on 8443, so that port must reach the host without translation.
Firewall
sudo ufw allow 443/tcp
sudo ufw allow 8443/udp
sudo ufw allow 8443/tcp
If calls join and then drop after a few seconds, it is almost always 8443.
Backups
Two things matter, and one of them is easy to forget:
docker compose exec postgres pg_dump -U mmuser mattermost | gzip > mattermost-$(date +%F).sql.gz
docker run --rm -v mm-data:/data -v "$PWD:/backup" alpine tar czf /backup/mm-data-$(date +%F).tar.gz /data
The database holds your messages. The data volume holds uploaded files. A backup of one without the other restores to a broken server.
Upgrading
docker compose pull
docker compose up -d
This pulls the newest Mattermore image, which carries the server and the calls plugin together, so there is nothing else to update.
Troubleshooting
Call button missing in channels. The environment variable is not reaching the server. Check inside the container, not from your own shell:
docker compose exec mattermost env | grep MM_CALLS
Calls connect then drop. Port 8443, or a SITE_URL that does not match the
address people use.
Know when to upgrade
Mattermore follows upstream Mattermost. One mail when a release fixes something that matters, nothing else.