Debian

Deploy Mattermost Server on Debian 13 / 12 with SSL

Mattermost gives you a self-hosted Slack alternative with full control over your data, integrations, and compliance. If your team needs real-time messaging without handing everything to a third-party SaaS provider, this is the platform to deploy. It runs on PostgreSQL, supports webhooks and bot integrations, and the open-source edition covers what most teams actually need.

Original content from computingforgeeks.com - post 142859

This guide walks through a complete Mattermost deployment on Debian 13 (Trixie) and Debian 12 (Bookworm) with PostgreSQL as the database backend, Nginx as a reverse proxy, and Let’s Encrypt for SSL. The setup is nearly identical on both releases, with one minor Nginx syntax difference noted below. If you’re running Ubuntu instead, see our Mattermost deployment guide for Ubuntu.

Tested March 2026 | Debian 13.4 / 12.5, Mattermost 11.5.1, PostgreSQL 17.9 / 15.16, Nginx 1.26 / 1.22

Prerequisites

  • Debian 13 or Debian 12 server with at least 2 GB RAM, 2 CPU cores, and 10 GB disk
  • Root or sudo access
  • A domain name (or subdomain) with a DNS A record pointing to your server’s public IP
  • Ports 80 and 443 open on your firewall
  • Tested on: Mattermost 11.5.1, PostgreSQL 17.9 (Debian 13) / 15.16 (Debian 12), Nginx 1.26 / 1.22

Install PostgreSQL

Debian 13 ships PostgreSQL 17 from its default repositories, while Debian 12 ships PostgreSQL 15. The install command is the same on both releases:

sudo apt update
sudo apt install -y postgresql postgresql-contrib

Confirm the installed version:

psql --version

On Debian 13, this returns:

psql (PostgreSQL) 17.9

On Debian 12:

psql (PostgreSQL) 15.16

Check that the service is running:

sudo systemctl status postgresql

The status shows active (exited) because PostgreSQL runs through pg_ctlcluster rather than as a direct systemd process. This is normal on Debian. For a deeper look at PostgreSQL on Debian, see our PostgreSQL 17 installation guide for Debian.

Create the Mattermost Database

Mattermost needs a dedicated PostgreSQL database and user. Run these commands to create both and grant the required permissions:

sudo -u postgres psql -c "CREATE DATABASE mattermost;"
sudo -u postgres psql -c "CREATE USER mmuser WITH PASSWORD 'YourStrongPassword';"
sudo -u postgres psql -c "GRANT ALL PRIVILEGES ON DATABASE mattermost TO mmuser;"
sudo -u postgres psql -c "ALTER DATABASE mattermost OWNER TO mmuser;"
sudo -u postgres psql -d mattermost -c "GRANT ALL ON SCHEMA public TO mmuser;"

The last two commands are essential on PostgreSQL 15+ because the default privileges on the public schema changed in that version. Without them, Mattermost cannot create tables.

Verify the database exists and is owned by mmuser:

sudo -u postgres psql -c "\l" | grep mattermost

You should see the database listed with the correct owner:

 mattermost | mmuser   | UTF8     | C.UTF-8 | C.UTF-8 |

Download and Install Mattermost

Fetch the latest stable version number from the Mattermost download page using the GitHub API:

VER=$(curl -sL https://api.github.com/repos/mattermost/mattermost/releases/latest | grep tag_name | head -1 | sed 's/.*"v\([^"]*\)".*/\1/')
echo $VER

At the time of writing, this outputs:

11.5.1

Download and extract the archive to /opt:

wget https://releases.mattermost.com/$VER/mattermost-$VER-linux-amd64.tar.gz -O /tmp/mattermost.tar.gz
sudo tar -xzf /tmp/mattermost.tar.gz -C /opt/
sudo mkdir -p /opt/mattermost/data

Create a dedicated system user and set directory ownership:

sudo useradd --system --user-group mattermost
sudo chown -R mattermost:mattermost /opt/mattermost
sudo chmod -R g+w /opt/mattermost

The /opt/mattermost/data directory stores uploaded files, plugins, and other user data. Back this up regularly in production.

Configure Mattermost

Open the main configuration file:

sudo vi /opt/mattermost/config/config.json

Find and update these two settings. Set SiteURL to your domain and DataSource to the PostgreSQL connection string with the password you created earlier:

"SiteURL": "https://mattermost.example.com",

Under SqlSettings, replace the existing DataSource value:

"DataSource": "postgres://mmuser:YourStrongPassword@localhost:5432/mattermost?sslmode=disable&connect_timeout=10",

Replace YourStrongPassword with the actual password you set in the database step, and mattermost.example.com with your real domain. The sslmode=disable is fine here because PostgreSQL and Mattermost are on the same host, so the connection never leaves localhost.

Create the Systemd Service

Create a unit file so Mattermost starts automatically on boot:

sudo vi /etc/systemd/system/mattermost.service

Add the following content:

[Unit]
Description=Mattermost
After=syslog.target network.target postgresql.service

[Service]
Type=notify
WorkingDirectory=/opt/mattermost
User=mattermost
ExecStart=/opt/mattermost/bin/mattermost
TimeoutStartSec=3600
KillMode=mixed
Restart=always
RestartSec=10
LimitNOFILE=49152

[Install]
WantedBy=multi-user.target

The LimitNOFILE=49152 raises the open file descriptor limit, which Mattermost needs when handling many concurrent WebSocket connections. The After=postgresql.service ensures the database is available before Mattermost starts.

Reload systemd and start the service:

sudo systemctl daemon-reload
sudo systemctl enable --now mattermost

Verify it’s running:

sudo systemctl status mattermost

The output should confirm an active state:

● mattermost.service - Mattermost
     Loaded: loaded (/etc/systemd/system/mattermost.service; enabled; preset: enabled)
     Active: active (running)
   Main PID: 3859 (mattermost)
     Memory: 371.2M

Mattermost listens on port 8065 by default. Confirm with:

sudo ss -tlnp | grep 8065

Expected output:

LISTEN 0      4096               *:8065             *:*    users:(("mattermost",pid=3859,fd=19))

If the service fails to start, check the logs with sudo journalctl -u mattermost -n 50. The most common issue is a wrong database password in config.json.

Set Up Nginx Reverse Proxy with SSL

Mattermost listens on HTTP port 8065, which is not suitable for production. Nginx handles SSL termination and proxies requests to the Mattermost backend. For more on Nginx configuration, see our Nginx installation guide for Debian and Ubuntu.

Install Nginx and certbot:

sudo apt install -y nginx certbot python3-certbot-nginx

Obtain an SSL certificate from Let’s Encrypt. The --standalone method temporarily binds to port 80, so the pre/post hooks stop and start Nginx around the challenge:

sudo certbot certonly --standalone --pre-hook 'systemctl stop nginx' --post-hook 'systemctl start nginx' -d mattermost.example.com --non-interactive --agree-tos -m [email protected]

Certbot confirms with Successfully received certificate. and stores the files under /etc/letsencrypt/live/mattermost.example.com/.

Create the Nginx virtual host:

sudo vi /etc/nginx/sites-available/mattermost

Paste the following configuration. This handles both regular HTTP requests and WebSocket connections, which Mattermost uses for real-time messaging:

upstream mattermost_backend {
    server 127.0.0.1:8065;
    keepalive 32;
}

server {
    listen 80;
    server_name mattermost.example.com;
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl;
    http2 on;
    server_name mattermost.example.com;

    ssl_certificate /etc/letsencrypt/live/mattermost.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/mattermost.example.com/privkey.pem;
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_prefer_server_ciphers on;

    location ~ /api/v[0-9]+/(users/)?websocket$ {
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        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_set_header X-Frame-Options SAMEORIGIN;
        proxy_buffers 256 16k;
        proxy_buffer_size 16k;
        client_max_body_size 50M;
        proxy_read_timeout 600s;
        proxy_pass http://mattermost_backend;
    }

    location / {
        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_set_header X-Frame-Options SAMEORIGIN;
        client_max_body_size 50M;
        proxy_read_timeout 600s;
        proxy_pass http://mattermost_backend;
    }
}

Debian 12 note: If you’re running Debian 12 with Nginx 1.22, replace http2 on; with the older syntax: listen 443 ssl http2; on the listen line. Nginx 1.26 in Debian 13 deprecated the combined directive.

Enable the site, remove the default virtual host, test the configuration, and restart Nginx:

sudo ln -sf /etc/nginx/sites-available/mattermost /etc/nginx/sites-enabled/
sudo rm -f /etc/nginx/sites-enabled/default
sudo nginx -t
sudo systemctl restart nginx

The nginx -t output should show syntax is ok and test is successful. If it reports errors, double-check the certificate paths and server_name value.

Verify the SSL certificate is serving correctly:

echo | openssl s_client -connect mattermost.example.com:443 -servername mattermost.example.com 2>/dev/null | openssl x509 -noout -dates -subject

The output confirms the certificate details:

notBefore=Mar 26 11:52:23 2026 GMT
notAfter=Jun 24 11:52:22 2026 GMT
subject=CN=mattermost.computingforgeeks.com

Configure the Firewall

Debian does not enable a firewall by default. Install ufw and allow the necessary ports:

sudo apt install -y ufw
sudo ufw allow ssh
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable

Confirm the rules are active:

sudo ufw status

Port 8065 is intentionally not opened to the public. All external traffic goes through Nginx on 443, and Nginx proxies to Mattermost on localhost:8065.

Access the Web Interface

Open https://mattermost.example.com in your browser. The first user to register becomes the system administrator, so do this immediately after deployment.

The login page appears with options to create an account or sign in:

Mattermost login page with email and password fields

Click Don’t have an account? to create the admin user. Fill in your email, username, and a strong password:

Mattermost signup form with email username and password filled in

After signing up, you land in the Town Square channel, which is the default public channel:

Mattermost Town Square channel view after first login

Send a test message to confirm everything works end to end, from the browser through Nginx to Mattermost to PostgreSQL and back:

Test message sent in Mattermost Town Square channel

The System Console is where you manage server settings, users, and integrations. Access it from the menu in the top-left corner:

Mattermost System Console admin dashboard

Under Environment > Web Server, verify that the Site URL matches your domain and that the connection security shows TLS:

Mattermost System Console web server configuration showing site URL

The database configuration page under Environment > Database shows the active PostgreSQL connection:

Mattermost System Console database configuration with PostgreSQL

The user management section lists all registered users and their roles. The first user shows the System Admin badge:

Mattermost user management page showing admin user

Create Admin User via CLI (Optional)

For automated or headless deployments, you can create the first admin user from the command line instead of the web UI. This requires EnableLocalMode: true in config.json under ServiceSettings.

Create the admin user:

sudo /opt/mattermost/bin/mmctl user create --email [email protected] --username admin --password 'YourPassword' --system-admin --local

Then create a team for users to join:

sudo /opt/mattermost/bin/mmctl team create --name myteam --display-name "My Team" --email [email protected] --local

The --local flag connects to the Mattermost socket directly, bypassing authentication. This only works from the server itself.

Debian 13 vs Debian 12 Differences

The installation steps are identical on both releases. The table below summarizes the version differences you’ll encounter:

ComponentDebian 13 (Trixie)Debian 12 (Bookworm)
PostgreSQL17.915.16
Python3.13.53.11.2
OpenSSL3.5.53.0.11
Kernel6.126.1
Nginx1.26 (use http2 on;)1.22 (use listen 443 ssl http2)
Mattermost11.5.111.5.1
CertbotSameSame
Install stepsIdenticalIdentical

The only difference that affects the setup is the Nginx HTTP/2 directive. On Debian 13 with Nginx 1.26+, use the separate http2 on; directive. On Debian 12 with Nginx 1.22, use the older combined syntax listen 443 ssl http2; on the listen line. Everything else, from package names to file paths to systemd commands, is the same.

Production Hardening

Before handing this deployment off to your team, take care of these items:

  • Automatic SSL renewal – Verify certbot’s timer works by running sudo certbot renew --dry-run. Let’s Encrypt certificates expire every 90 days, and certbot handles renewal automatically if the timer is active
  • Email notifications – Configure SMTP in System Console > Environment > SMTP so Mattermost can send email notifications, password resets, and invitations. Without this, users have no way to recover their accounts
  • Automated backups – Back up /opt/mattermost/data (uploaded files and plugins) and the PostgreSQL database regularly. For PostgreSQL, use pg_dump mattermost in a cron job. Losing either one without a backup means losing all team conversations
  • Performance monitoring – Enable the built-in metrics endpoint under System Console > Environment > Performance Monitoring. This exposes Prometheus-compatible metrics on port 8067 for tracking response times, active connections, and database query performance
  • Rate limiting – Mattermost enables rate limiting by default. Review the settings under System Console > Environment > Rate Limiting and adjust the per-second limits if your team is large

The official Mattermost documentation for Debian covers additional configuration options including LDAP authentication, high availability clustering, and plugin management.

Related Articles

Web Hosting Install Drupal 8 on Debian 10 (Buster) Linux Debian Install Crater Invoicing Solution on Debian 12/11/10 Monitoring How To Install Zabbix 6 on Debian 11 / Debian 10 Debian Install and Use Wine 10.x on Debian 12 (Bookworm)

Leave a Comment

Press ESC to close