Team chat is one of those categories where the hosted services work well but data ownership matters more the longer you use them. Message history, file attachments, integrations with internal systems — if that data lives on your own server, it stays under your control.
Mattermost gives you the full team chat experience — channels, direct messages, threads, file sharing, bots, integrations — self-hosted. Complete message history, no seat-based pricing that scales with headcount, and the ability to build integrations against your internal APIs.
The setup is more involved than most apps in this series: PostgreSQL, the Mattermost binary, Nginx, email configuration. Plan for about an hour. I'll also cover push notifications, which require one additional configuration step that's easy to miss.
I run Mattermost for a small development team. We have complete message history, file storage on our server, and custom integrations that work exactly the way we need them to.
I run Mattermost on Tencent Cloud Lighthouse. The 2 GB RAM / 2 vCPU plan handles a team of under 50 people; 4 GB for larger teams or heavy file sharing. The key financial advantage of self-hosting Mattermost on Lighthouse: no per-seat pricing — a flat monthly server cost regardless of team size. As your team grows from 10 to 50 people, the infrastructure cost doesn't multiply. Lighthouse's CBS cloud disk expansion handles growing file attachment storage, and the snapshot feature protects your team's message history before major Mattermost version upgrades.
- Key Takeaways
Mattermost on your own server provides:
The Mattermost Team Edition is free and covers all the essentials. The Enterprise Edition adds LDAP, compliance features, and advanced permissions.
| Requirement | Details |
|---|---|
| Server | Ubuntu 22.04, 2 GB+ RAM |
| PostgreSQL | 13+ |
| Domain | Required for HTTPS |
| SMTP for notifications (optional but recommended) |
sudo apt update
sudo apt install -y postgresql postgresql-contrib
sudo systemctl enable postgresql
sudo systemctl start postgresql
Create database and user:
sudo -u postgres psql
CREATE DATABASE mattermost;
CREATE USER mmuser WITH ENCRYPTED PASSWORD 'your-db-password';
GRANT ALL PRIVILEGES ON DATABASE mattermost TO mmuser;
ALTER DATABASE mattermost OWNER TO mmuser;
\q
MM_VERSION="9.11.0" # Check latest at mattermost.com/deploy
wget "https://releases.mattermost.com/${MM_VERSION}/mattermost-team-${MM_VERSION}-linux-amd64.tar.gz"
tar -xzf mattermost-team-${MM_VERSION}-linux-amd64.tar.gz
sudo mv mattermost /opt/mattermost
rm mattermost-team-${MM_VERSION}-linux-amd64.tar.gz
sudo useradd --system --user-group mattermost
sudo mkdir -p /opt/mattermost/data
sudo chown -R mattermost:mattermost /opt/mattermost
sudo chmod -R g+w /opt/mattermost
sudo nano /opt/mattermost/config/config.json
Key settings:
Database:
"SqlSettings": {
"DriverName": "postgres",
"DataSource": "postgres://mmuser:your-db-password@localhost/mattermost?sslmode=disable&connect_timeout=10"
}
Site URL:
"ServiceSettings": {
"SiteURL": "https://chat.yourdomain.com",
"ListenAddress": ":8065"
}
File Storage:
"FileSettings": {
"DriverName": "local",
"Directory": "/opt/mattermost/data/"
}
cd /opt/mattermost
sudo -u mattermost ./bin/mattermost db init
sudo nano /etc/systemd/system/mattermost.service
[Unit]
Description=Mattermost
After=network.target postgresql.service
[Service]
Type=notify
ExecStart=/opt/mattermost/bin/mattermost
TimeoutStartSec=3600
KillMode=mixed
Restart=always
RestartSec=10
WorkingDirectory=/opt/mattermost
User=mattermost
Group=mattermost
LimitNOFILE=49152
[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable mattermost
sudo systemctl start mattermost
sudo systemctl status mattermost
sudo apt install -y nginx certbot python3-certbot-nginx
sudo nano /etc/nginx/sites-available/mattermost
upstream backend {
server localhost:8065;
keepalive 32;
}
proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=mattermost_cache:10m max_size=3g inactive=120m use_temp_path=off;
server {
listen 80;
server_name chat.yourdomain.com;
location ~ /api/v[0-9]+/(users/)?websocket$ {
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
client_max_body_size 50M;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Frame-Options SAMEORIGIN;
proxy_buffers 256 16k;
proxy_buffer_size 16k;
client_body_timeout 60s;
send_timeout 300s;
lingering_timeout 5s;
proxy_connect_timeout 90s;
proxy_send_timeout 300s;
proxy_read_timeout 90s;
proxy_pass http://backend;
}
location / {
client_max_body_size 50M;
proxy_set_header Connection "";
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Frame-Options SAMEORIGIN;
proxy_buffers 256 16k;
proxy_buffer_size 16k;
proxy_read_timeout 600s;
proxy_cache mattermost_cache;
proxy_cache_revalidate on;
proxy_cache_min_uses 2;
proxy_cache_use_stale timeout;
proxy_cache_lock on;
proxy_http_version 1.1;
proxy_pass http://backend;
}
}
sudo ln -s /etc/nginx/sites-available/mattermost /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
sudo certbot --nginx -d chat.yourdomain.com
Navigate to https://chat.yourdomain.com.
You'll see the Mattermost setup wizard. Create the first account — this becomes the system admin.
https://chat.yourdomain.com/your-teamDefault channels are created automatically (town-square, off-topic). Add more:
#engineering, #general, #random, etc.Main Menu → Invite People:
| Platform | Download |
|---|---|
| Windows/macOS/Linux | mattermost.com/download |
| iOS | App Store → "Mattermost" |
| Android | Play Store → "Mattermost" |
When setting up the app, point it to your server URL: https://chat.yourdomain.com
Email notifications require SMTP configuration in the System Console.
Go to System Console → Environment → SMTP:
SMTP Server: smtp.sendgrid.net
SMTP Port: 587
Connection Security: STARTTLS
SMTP Username: apikey
SMTP Password: YOUR_SENDGRID_API_KEY
From Name: Mattermost
From Email: mattermost@yourdomain.com
Click Save and Test Connection.
After setting up Mattermost and creating the first account, push notifications to the mobile app weren't working even though I'd configured the app to point to my server.
Mattermost on mobile uses its own notification relay for push notifications — by default it routes through Mattermost's own push notification service (HPNS). For self-hosted servers, this requires either:
The fix: Register at mattermost.com/pl/notifications to get a push proxy address for your server, then in System Console → Environment → Push Notification Server, add the proxy URL.
Or if you don't need mobile push notifications, just leave the default — in-app notifications still work for desktop and web.
| Issue | Likely Cause | Fix |
|---|---|---|
| Can't connect from mobile | Wrong server URL | Use full HTTPS URL: https://chat.yourdomain.com |
| WebSocket disconnect | Nginx timeout | Check WebSocket proxy config in Nginx |
| Files not uploading | Size limit | Check client_max_body_size in Nginx (set to 50M+) |
| Push notifications not working | HPNS not configured | Register for Mattermost notification proxy |
| Database errors | Wrong PostgreSQL credentials | Check config.json DataSource string |
| High memory | Large team with many channels | Upgrade to 4 GB RAM |
| Email not sending | SMTP misconfigured | Test in System Console → SMTP → Test Connection |
✅ What you built:
The free Mattermost Team Edition covers all the core team chat features without per-user fees. Your message history, files, and user data stay on your server.
How many users can Mattermost support on a self-hosted server?
For a 2 GB RAM server, up to ~50 concurrent users is reasonable. Larger teams may need more RAM. Monitor memory usage and scale the server spec as the team grows.
Is self-hosted Mattermost end-to-end encrypted?
Mattermost encrypts data in transit (HTTPS) and at rest (encrypted database). It's not end-to-end encrypted in the sense that the server operator can access message data. For true E2EE, the server never holds plaintext.
How do I migrate message history when upgrading the server?
Export the application data (usually a dump or export command), install on the new server, import the data, and update DNS. The guide covers the backup and restore process.
Can team members use mobile apps with self-hosted Mattermost?
Yes — configure the mobile app to point to your server URL instead of the default cloud service. The setup is typically: enter your server address in the app's server settings.
👉 Get started with Tencent Cloud Lighthouse
👉 View current pricing and launch promotions
👉 Explore all active deals and offers