Install MatterMost with docker-compose behind Treafik

Install MatterMost with docker-compose behind Treafik

I expected that the instruction on mattermost github repository for docker-compose will be a simple docker-compose up -d but turns out this is not the case. I have documented how I set this up along with a slight tweak of how I am going to make it work behind traefik.


  • A Ubuntu 18.04.3 (LTS) x64 Server with minimum required configurations
  • Docker installed on the host
  • docker-compose installed on the host
  • git installed on the host
  • You already have traefik 2.1 setup on the host and configured to listen to docker provider.


Clone mattermost docker-compose repository

git clone
cd mattermost-docker

Make changes to use team edition rather than enterprise edition

The first part of the app server in the docker-compose.yml file should look the following. The comment explains what was done.

    build: #app
      # change `build:app` to `build:` and uncomment following lines for team edition or change UID/GID
      context: app
        - edition=team
        - PUID=1000
        - PGID=1000

Build the custom image

docker-compose build

This can take a few minutes based on the resources on your host and your internet connection.

Setup the volumes and assign them the correct permissions

mkdir -pv ./volumes/app/mattermost/{data,logs,config,plugins,client-plugins}
chown -R 1000:1000 ./volumes/app/mattermost/

Note that you have to setup the uid and gid setup to match the ones you specifiy in your docker-compose.yml file that was used for the build step.

Run docker-compose

docker-compose up -d

Edit: Usually the above works eventually, but I encountered some problems where the app container became unhealthy over the weekend without any visible cause. I have reverted to a setup where I manually start the database service using docker-compose up -d db and once that is fully up and accepting connections, docker-compose up -d app. This is worked well so far but I will updated as required. See note below under healthcheck.

At this point you could just run this setup and things should work if you access your host by providing the IP or a hostname that is configured to point to that IP via DNS.

Making it runnable on a repeatable basis

Air-gapped environment considerations

In my situation, the machine I used to build these images is different from where I want to deploy due to air-gap. Hence, there's additional work steps I had to perform. This will also be useful for you to create a deploy docker-compose file when you have pre-built images.

Save the relevant built images as files for transport.

docker save -o <output_file_name>.docker <input_image_name>

If you're going to use traefik as the edge router/proxy, then there's no need to save the web image with nginx. You may also need to save the relevant alpine, postgres and nginx images. I took all of them just in case, but it may work without. If you have tested it out please let me know.

Transfer the images to your deployment host and run the following commands to load them in the local docker repository.

docker load < <input-file-name>.docker

Deployment docker-compose.yml file

There are certain key points to note in the file below:

  • image is the name of the image that was generated in the build step and loaded on to the local repository or another repository that is accessible from the host
  • There are two network in involved, out which is the docker network on which traefik is listening and the default network that is only being used by app and db. Hence the database is isolated from the network that is visible to traefik.
  • There is a separate traefik instance running on the out network
  • The tls=true configuration for traefik assumes that you have configured the SSL certificates correctly on traefik. You can omit this line if you don't want to enable TLS.
  • Ensure there is no other traefik router name mattermost
version: "3"
    image: mattermost-docker_db
    read_only: true
    restart: unless-stopped
      - ./volumes/db/var/lib/postgresql/data:/var/lib/postgresql/data
      - /etc/localtime:/etc/localtime:ro
      - POSTGRES_USER=redacted
      - POSTGRES_PASSWORD=redacted
      - POSTGRES_DB=redacted
    image: mattermost-docker_app
    restart: unless-stopped
      - ./volumes/app/mattermost/config:/mattermost/config:rw
      - ./volumes/app/mattermost/data:/mattermost/data:rw
      - ./volumes/app/mattermost/logs:/mattermost/logs:rw
      - ./volumes/app/mattermost/plugins:/mattermost/plugins:rw
      - ./volumes/app/mattermost/client-plugins:/mattermost/client/plugins:rw
      - /etc/localtime:/etc/localtime:ro
      # set same as db credentials and dbname
      - MM_USERNAME=redacted
      - MM_PASSWORD=redacted
      - MM_DBNAME=redacted

      # use the credentials you've set above, in the format:
      # MM_SQLSETTINGS_DATASOURCE=postgres://${MM_USERNAME}:${MM_PASSWORD}@db:5432/${MM_DBNAME}?sslmode=disable&connect_timeout=10
      - MM_SQLSETTINGS_DATASOURCE=postgres://redacted:redacted@db:5432/redacted?sslmode=disable&connect_timeout=10
    - "traefik.enable=true"
    - "traefik.http.routers.mattermost.rule=Host(``)" 
    - "traefik.http.routers.mattermost.tls=true"
        - default
        - out   
    external: true 

Before you run docker-compose up -d

Run the setup volumes and persmission step above. Then run docker-compose up -d.

Post setup

Now navigate to and go into the setup console. Configure email setting in SMTP and ensure you get the email. Also important, setup the SiteURL parameter to point to The test live connection after this setup was unsuccessful for me and I don't know the implications of this yet. You will notice that all the configuration changes you make here will be reflected in the config file located at ./volumes/app/mattermost/config/config.json. You can also manually change some configration here. For example, I had turned on the email verification feature but had not setup email correctly and was locked out. However, I located the right configuration in the config file and changed it and attempted to login again and it was effective immediately.

Notes: Health Check

Earlier in this post I have referenced that the app container went into an unhealthy state for no apparent reason but I suspect that it was because the app was not able to connect to the database when it was invoked as the database was not in ready state to accept connections. I modified the docker-compose file and added a depends_on configuration as follows:

    - db

As per docker-compose 3 documentation, the depends_on does not mean that docker will wait till the database is fully up. As per moderns best practices taking distributed cloud native container orchestration systems in to consideration, it is expected that applications will be resilient in handling situations where a dependent resource is not available.

I add some healthcheck code in the docker-compose file. One thing to remember when configuring this is that you can reference localhost as the app container. For example you might do something like curl -k -f 'https://localhost:8000 where -k skips certificate verification and -f returns the status code (I may be wrong about this, but that's what I figured during my testing.


I had intended to describe setup of traefik 2 in this post as well but unfortunately I'm out of time. Some of this may be described elsewhere on the blog or my medium blog. There are also good posts elsewhere to describe traefik setup you can find out google.