How to Deploy Self-hosted Mattemost Server | Docker Swarm

Prerequisites:
- Linux Server
- Docker installed and swarm mode initiated
- Webserver (example: nginx)
- Mysql8 Database

How to setup mysql8 db:
https://blog.kafana.dev/simple-mysql-8-setup-docker-swarm/

How to setup nginx webserver:
https://blog.kafana.dev/how-to-setup-nginx-docker-swarm/

Mattermost | Docker Swarm

This is an example using docker swarm. I'll use mysql8 database and nginx as a webserver running also in docker swarm, but in separated stacks.

sudo mkdir /webapps
sudo chown $USER:$USER /webapps
cd /webapps
mkdir -p /webapps/mattermost/{Dockerfile-folder,mattermost-data} && cd mattermost/Dockerfile-folder
Create Dockerfile
nano Dockerfile

FROM ubuntu:20.04

RUN apt-get update && apt-get upgrade -y && apt-get install -y \
    nano wget curl net-tools procps sudo telnet iputils-ping


ENV DEBIAN_FRONTEND noninteractive

# Create user with sudo privileges
RUN useradd -ms /bin/bash --system --user-group -u 1000 durbok && \
    usermod -aG sudo durbok
# New added for disable sudo password
RUN echo '%sudo ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers


VOLUME /opt/mattermost

# Set as default user
USER durbok

RUN mkdir -p /opt/mattermost
RUN sudo chown -R durbok:durbok /opt/mattermost && sudo chmod -R g+w /opt/mattermost

WORKDIR /opt/mattermost
ENV DEBIAN_FRONTEND teletype


CMD ["/opt/mattermost/bin/mattermost"]

I am storing my images in selfhosted app called harbor, but you can use dockerhub or something similar.


docker build harbor.urdomain.com/kafana/mattermost:latest .
docker push harbor.urdomain.com/kafana/mattermost:latest

cd ../

Download mattermost server https://mattermost.com/deploy/?ref=download

wget https://releases.mattermost.com/6.5.0/mattermost-6.5.0-linux-amd64.tar.gz
tar xvf mattermost-6.5.0-linux-amd64.tar.gz
rm mattermost-6.5.0-linux-amd64.tar.gz
mv mattermost mattermost-data/
nano docker-compose.yml
version: "3.7"

services:

  prod:
    image: harbor.urdomain.com/kafana/mattermost:latest
    networks:
      - durbok-net
    deploy:
      placement:
        constraints:
        - node.role == manager
      replicas: 1
      restart_policy:
        condition: on-failure
    volumes:
      - ./mattermost-data/mattermost:/opt/mattermost
networks:
  durbok-net:
    external: true

Edit config.json

nano /mattermost-data/mattermost/config/config.json

Most important is to change:

    "ServiceSettings": {
        "SiteURL": "https://mattermost.urdomain.com",
        "ListenAddress": ":8065",

and

"SqlSettings": {
        "DriverName": "mysql",
        "DataSource": "mattermost:password@tcp(mysql8_prod:3306)/mattermost?charset=utf8mb4,utf8\u0026writeTimeout=30s",

This part is connection to mysql database which, in my case, is a docker container called mysql8_prod. It can be IP address or AWS RDS endpoint.
Username and database are called mattermost, however you can name yours as you please.

Nginx config

upstream backend {
    server mattermost_prod: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 {
    server_name mattermost.urdomain.com;

    location ~ /api/v[0-9]+/(users/)?websocket$ {
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        client_max_body_size 150M;
#        proxy_set_header Host $http_host;
        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_body_timeout 60;
        send_timeout 300;
        lingering_timeout 5;
        proxy_connect_timeout 90;
        proxy_send_timeout 300;
        proxy_read_timeout 90s;
        proxy_http_version 1.1;
        proxy_pass http://backend;
    }

    location / {
        client_max_body_size 150M;
        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-Forwarded-Proto $scheme;
        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;
    }

    listen 443 ssl http2;
    ssl_certificate /etc/nginx/ssl/ur-ssl.pem;
    ssl_certificate_key /etc/nginx/ssl/ur-ssl.key;
    # include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    ssl_dhparam /etc/nginx/ssl/dhparam.pem;

    ssl_session_timeout 1d;

    # Enable TLS versions (TLSv1.3 is required upcoming HTTP/3 QUIC).
    ssl_protocols TLSv1.2 TLSv1.3;

    # Enable TLSv1.3's 0-RTT. Use $ssl_early_data when reverse proxying to
    # prevent replay attacks.
    #
    # @see: https://nginx.org/en/docs/http/ngx_http_ssl_module.html#ssl_early_data
    ssl_early_data on;

    ssl_ciphers ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA;
    ssl_prefer_server_ciphers on;
    ssl_session_cache shared:SSL:5m;
    # HSTS (ngx_http_headers_module is required) (15768000 seconds = 6 months)
    add_header Strict-Transport-Security max-age=15768000;
    # OCSP Stapling ---
    # fetch OCSP records from URL in ssl_certificate and cache them
#    ssl_stapling on;
#    ssl_stapling_verify on;
}


server {
    if ($host = mattermost.urdomain.com) {
        return 301 https://$host$request_uri;
    } # managed by Certbot


    listen 80 default_server;
    server_name mattermost.urdomain.com;
    return 404; # managed by Certbot

}
docker stack deploy -c docker-compose.yml mattermost

Reload nginx.
Done.