Deploy Mattermost on Dokku

Mattermost started as an open-source Slack alternative, like Gitlab for GitHub, and as such has been adopted by a lot of organizations because you can self-host it for free (although you have to pay for your own servers and you’re responsible for the maintainance and updates).

Dokku is a single-server self-hosted PaaS. Think of Heroku, but open-source and on your own server. It’s very useful because it deals with all the intricacies of building and serving multiple Web apps on the same server to let you focus on what matters: the development of the app itself. You just describe how to build the app (or Dokku detects it) and git push it and Dokku deploys it for you. Apps are deployed as Docker containers behind an nginx server that does the routing. Dokku has tons of plugins to link the apps to various databases (Postgres, ElasticSearch, etc) and customize the front-end routing to add Let’s Encrypt certicates, HTTP Auth, etc.

At Bixoto, we use Mattermost for our internal chat, and Dokku to deploy most of our websites. Our own Mattermost is deployed on its own server for historical reasons: we started using Mattermost before Dokku. Recently, we had to deploy a new Mattermost instance for an project we have with another company. Now that we use Dokku for virtually every project and have some experience with it, we decided to deploy Mattermost on it.

This is made easier by the fact that Mattermost already supports a Docker-based deployment.

Initial git repository

First, create a new git repository:

git init mattermost && cd mattermost

Create a Dockerfile with the Mattermost version you want to deploy:

FROM mattermost/mattermost-team-edition:7.8.2

Here, we use Mattermost 7.8.2, which is the latest LTS release at the time of this writing. The Dockerfile doesn’t contain anything because everything is already described in Mattermost’s Docker image.

Note: having a repo associated with an app gives a place to store the documentation for that app. You can also avoid altogether creating such repo by running dokku git:from-image $APP_NAME mattermost/mattermost-team-edition:7.8.2 directly on the server.

Dokku app

Note: in this post we assume you already installed Dokku on your server. If it’s your first time with it, follow the official documentation to install it. Be aware that Dokku uses nginx and configures it all by itself; as such it doesn’t support other non-Dokku websites served from that same server. If you already have some website on your server, avoid installing Dokku on it because it will break.

To make the commands in this tutorial easier to copy/paste, we’ll set two variables in the shell. SSH onto the server you installed Dokku on, and set these variables:

APP_NAME=my-mattermost
DOMAIN=chat.example.com

These are example values; change them to what you want. The APP_NAME is used to name the app in Dokku. Don’t use spaces or any character that could be interpreted by the shell. The DOMAIN is the domain from which the app will be served. Edit your DNS zone to point it to your Dokku server.

Then, create the app:

dokku apps:create $APP_NAME

And configure its domain:

dokku domains:add $APP_NAME $DOMAIN
dokku config:set --no-restart $APP_NAME DOMAIN=$DOMAIN

The second command is needed because Mattermost needs a DOMAIN environment variable to know which domain it’s served under.

Persistent storage

We need to have persistent storage so the data is kept between app deployments. You wouldn’t want to lose all the messages every time you update Mattermost!

Create Mattermost’s persistent storage directories and mount them on the app:

for d in config data logs plugins client/plugins bleve-indexes; do
    volume="/var/lib/dokku/data/storage/$APP_NAME/$d"
    sudo mkdir -p "$volume"
    sudo chown -R 2000:2000 "$volume"
    dokku storage:mount $APP_NAME "$volume:/mattermost/$d"
done

This uses Dokku’s standard location for persistent storage directories. It sets the ownership to 2000:2000 because that’s what Mattermost requires.

Database

Create the Postgres database and link it:

dokku postgres:create $APP_NAME-db
dokku postgres:link $APP_NAME $APP_NAME-db

By default Dokku exports the connection string as the environment variable DATABASE_URL, but Mattermost doesn’t read it, so we need to tweak the config so it knows how to connect to the database:

# Get the Postgres URL
PG_URL="$(dokku config:get $APP_NAME DATABASE_URL)"
# Configure the app database config
dokku config:set --no-restart $APP_NAME MM_SQLSETTINGS_DRIVERNAME=postgres MM_SQLSETTINGS_DATASOURCE="$PG_URL?sslmode=disable&connect_timeout=10"

Last configuration

At this point, we can also configure the timezone Mattermost should use:

# Change "Europe/Paris" to whichever timezone you want
dokku config:set --no-restart $APP_NAME TZ=Europe/Paris

Mattermost supports a lot more configuration variables. Check their documentation for more info.

Deployment

It’s now time to make the first deployment of our app! In your local git repository, commit your files (there should be the Dockerfile we created earlier and maybe a README.md for your own documentation):

git commit -m "initial commit"

Now, push it to your Dokku server. If you haven’t done it already, configure Dokku to allow SSH access. Then, in your ~/.ssh/config file (create it if it doesn’t exist), add an entry for Dokku:

Host dokku-deploy
  User dokku
  Hostname <the IP of your server>

This adds an alias called dokku-deploy for dokku<the IP of your server>. Now, use this alias to add your server as a remote for your app:

git remote add dokku dokku-deploy:$APP_NAME

$APP_NAME is the name of the app you created earlier.

Now that you’re all set, push:

git push dokku main

You should see the output of the build and your Mattermost instance should now be deployed! It’s not yet usable, so check the next step to fix the last things.

Post-Deployment

SSL certificate

Let’s add a SSL certificate for our app:

dokku letsencrypt:enable $APP_NAME
dokku letsencrypt:cron-job --add $APP_NAME
dokku config:set $APP_NAME MM_SERVICESETTINGS_SITEURL=https://$DOMAIN

Fix the ports mapping

If the app is not accessible yet, it’s very likely because Dokku didn’t correctly detect the ports exposed by the app. Let’s fix that:

dokku proxy:ports-clear $APP_NAME
dokku proxy:set $APP_NAME http:80:8065 https:443:8065

You should now be able to access your Mattermost instance at https://<your domain>!

Local access

Mattermost has a mmctl tool that you can use to run admin commands on the instance, such as creating users and resetting passwords. By default, it requires an authentication, but you can enable a “local” mode that gives you unauthenticated access through a UNIX socket that only users with direct access to the server can use.

  1. Edit /var/lib/dokku/data/storage/$APP_NAME/config/config.json to set "EnableLocalMode" to true
  2. Restart the app: dokku ps:restart $APP_NAME

Then use dokku enter $APP_NAME to enter in the running container, and use mmtl --local <command>. See the official docs for more info.