Deploy mattermost to a docker swarm with secrets
Tags: mattermost, docker, selfhosted, security
Published: 2020-07-10 13:59:14

I deployed [mattermost](https://mattermost.com/) to a [docker swarm](https://docs.docker.com/engine/swarm/) using [docker secrets](https://docs.docker.com/engine/swarm/secrets/), while the process was smooth, I had to make some modifications to original [mattermost-docker](https://github.com/acrlakshman/mattermost-docker) source to achieve desired goal. This article describes the following:

* Deploy mattermost on a single node swarm (e.g. on digitalocean) and publish under a subdomain.
* Pass secrets to the stack.
* Enable plugins upload.
* Configure mattermost for email notifications using gmail's smtp server.

Before presenting details, here are the final products:

* Repository: https://github.com/acrlakshman/mattermost-docker
* Self hosted mattermost: https://mattermost.lakshmananumolu.com/public

```sh
username: test
password: test1234
```

* Docker images:

 * https://hub.docker.com/repository/docker/acrlakshman/mattermost-team
 * https://hub.docker.com/repository/docker/acrlakshman/mattermost-prod-db

## Deploy mattermost onto a single node swarm

I found few articles that describe [deploying mattermost in kubernetes](https://medium.com/mattermost/mattermost-5-15-76cf34f87d05), [single click app on digitalocean](https://medium.com/mattermost/install-mattermost-with-a-1-click-app-on-the-digitalocean-marketplace-e8ccd7be2e0e). While there are other ways to install, I wanted to deploy it myself on my digitalocean server space, which helps me learn few things along the way and may be contribute to the project. Here are the steps:

```sh
# ssh to server
ssh <user>@<public ip>
# Prepare swarm
docker swarm init --advertise-addr <public-ip>
# Clone the repository to your desired location
git clone https://github.com/acrlakshman/mattermost-docker
# Prepare volumes
cd mattermost-docker
mkdir -p volumes/app/mattermost/logs
mkdir -p volumes/app/mattermost/data
mkdir -p volumes/app/mattermost/config
mkdir -p volumes/app/mattermost/plugins
mkdir -p volumes/app/mattermost/client_plugins
sudo chown -R 2000:2000 ./volumes/app/mattermost
# create secrets to store database (postgresql) details
echo "database_user" | docker secret create mm_db_user -                       echo "database_password" | docker secret create mm_db_password -                       echo "database_name" | docker secret create mm_db_name -
# deploy stack
docker stack deploy -c docker-stack.yml mm
```

We now have a stack _**mm**_ created that manages three services, _mm_app_, _mm_db_, _mm_visualizer_.

##### `watch docker service ls`
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/8imdbnoyr6n1qxnasgn4.png)

While I have not presented the technical details above, some modifications are made to [original mattermost-docker](https://github.com/mattermost/mattermost-docker) in order to use credentials via docker secrets. _entrypoint.sh_ scripts for both _mattermost-docker/app/_ and _mattermost-docker/db/_ are changed and are custom built to use in this stack. A slightly modified version of [Basilio Vera](https://medium.com/@basi)'s script is used in this work which helped in [expanding secrets and assign them to environment variables](https://medium.com/@basi/docker-environment-variables-expanded-from-secrets-8fa70617b3bc).

##Point subdomain to mattermost instance

Webserver: nginx
CDN: [cloudflare](https://www.cloudflare.com/)
OS: Debian

Mattermost app now runs in docker and listens to host port at *7070*. I have used nginx as a proxy webserver on Debian. Here are the details:

```sh
cd /etc/nginx/sites-available

# Create a file with <sub.domain.com>
# In my case this is mattermost.lakshmananumolu.com
sudo vim <sub.domain.com>

# My <sub.domain.com> has the following
server {
  listen 80;
  listen [::]:80;
  server_name <sub.domain.com> www.<sub.domain.com>;
  return 301 https://<sub.domain.com>$request_uri;
}

map $http_x_forwarded_proto $proxy_x_forwarded_proto {
  default $http_x_forwarded_proto;
  ''      $scheme;
}

server {
  # SSL configuration
  listen 443;
  listen [::]:443;

  ssl     on;
  ssl_certificate <path-to>/<domain.com>.pem;
  ssl_certificate_key <path-to>/<domain.com>.key;
  ssl_session_timeout 5m;
  ssl_prefer_server_ciphers on;

  server_name <sub.domain.com> www.<sub.domain.com>;
  include hhvm.conf;

  location ~ /api/v[0-9]+/(users/)?websocket$ {
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header X-Forwarded-Ssl on;
    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-Forwarded-Proto $proxy_x_forwarded_proto;
    proxy_set_header X-Frame-Options SAMEORIGIN;
    proxy_buffers 256 16k;
    proxy_buffer_size 16k;
    proxy_read_timeout 600s;
    proxy_pass http://127.0.0.1:7070;
  }

  location / {
    # First attempt to serve request as file, then
    # as directory, then fall back to displaying a 404.
    gzip on;
    proxy_set_header X-Forwarded-Ssl on;

    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_pass http://127.0.0.1:7070;
  }
}

# enable this site.
sudo ln -s /etc/nginx/sites-available/<sub.domain.com> /etc/nginx/sites-enabled/<sub.domain.com>

# restart nginx.
sudo service nginx restart
```

I used [cloudflare](https://www.cloudflare.com/) as CDN, from where I obtained _ssl certificate_ and _key_, that are used in nginx configuration above.

## Mattermost initial configuration and enable plugins upload

Subdomain now points to mattermost instance. At this point we can create a new account and remember the credentials. Role of this user is _System Admin_.

At this point we can change mattermost config file to enable uploads for plugin. Edit _volumes/app/mattermost/config/config.json_ to

```sh
sudo vim <mattermost-repo-clone>/volumes/app/mattermost/config/config.json

# Search and set `EnableUploads` to true.
PluginSettings {
  ...
  "EnableUploads": true,
  ...
}
```

Execute _docker stack deploy_… that will restart mattermost app.

```sh
docker stack deploy -c docker-stack.yml mm
```

Plugins can now be uploaded to mattermost instance.

##### `System Console -> Plugin Management`
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/tiuox69mlsi26sxsuvb9.png)

## SMTP Email setup

Mattermost has excellent [documentation](https://docs.mattermost.com/install/smtp-email-setup.html) for this settings, I used that webpage to configure SMTP. Minor detail that I followed to get it to work with gmail is included here.

_System Console -> Environment -> SMTP_

```sh
SMTP Server: smtp.gmail.com
SMTP Server Port: 587
Enable SMTP Authentication: true
SMTP Server Username: <gmail address>
SMTP Server Password: <Generated app password with 2-factor authentication ON>
Connection Security: STARTTLS
```

For SMTP Server Password, I did the following

* I have 2-factor authentication enabled for my gmail account.
* Visit _Google account settings -> Security -> App passwords_
  * Generate an app password and use that for SMTP Server Password in mattermost.

## Visualizer

Above docker deployment comes with visualizer, which can be viewed on port _*7071*_. For my mattermost installation here is the [visualizer](https://visualizer.lakshmananumolu.com/).

## Extras

For extra installations such as [pgadmin4](https://hub.docker.com/r/dpage/pgadmin4/) alongside above services, please refer to `team-extras` branch (https://github.com/acrlakshman/mattermost-docker/tree/team-extras).

## Some plugins

* https://github.com/streamer45/mattermost-plugin-voice
* https://github.com/blindsidenetworks/mattermost-plugin-bigbluebutton
* https://github.com/scottleedavis/mattermost-plugin-remind

## References

* https://medium.com/mattermost/mattermost-5-15-76cf34f87d05
* https://medium.com/@basi/docker-environment-variables-expanded-from-secrets-8fa70617b3bc
* https://docs.mattermost.com/mobile/mobile-hpns.html