Docker Compose: A better way to deploy Rocketchat, Wekan, and MongoDB

View recent blog entries

A few months back, I posted instructions on deploying Rocket.Chat and Wekan instances (and their mutual dependency, MongoDB) individually. Since then, I've spent some time with Docker Compose, a set of scripts which help you to define, build, and manage a set of Docker containers. Docker Compose is a thing of beauty. This is the way I now deploy Rocket.Chat, Wekan, and MongoDB together.

Install Docker and Docker Compose

Install Docker (including the "post-installation" steps to allow non-root users to run Docker) and Docker Compose on your server (we recommend Ubuntu 16.04 or the older 14.04). We recommend using the "pip" (Python package manager) to do the install.

Create your Docker Compose recipe

We recommend creating a directory with an obvious name - in my case, it's /home/www/docker-rocketchat-wekan-mongo

In that directory, I create a file called docker-compose.yml containing (I've removed implementation specific details and replaced them with [placeholders]):

version: '2'
services:
  mongo:
    restart: unless-stopped
    image: mongo
    volumes:
      - [data directory path]:/data/db
      - [backup directory path]:/backups
    command: --smallfiles
  rocketchat-oeru:
    restart: unless-stopped
    image: rocket.chat
    ports:
      - "127.0.0.1:[port number]:3000" # should be a free port above 1024
    depends_on:
      - mongo
    environment:
      - MONGO_URL=mongodb://mongo/rocket
      - ROOT_URL=[domain name (including schema, e.g. http://)]
    volumes:
      - [upload directory path]:/var/www/rocket.chat/uploads
  wekan:
    restart: unless-stopped
    image: mquandalle/wekan
    ports:
      - "127.0.0.1:[port number]:80" # should be a free port above 1024
    depends_on:
      - mongo
    environment:
      - VIRTUAL_HOST=[domain name (don't include schema, e.g. https://)]
      - MONGO_URL=mongodb://mongo/plan
      - ROOT_URL=[domain name (include schema, e.g. https://)]
      - MAIL_URL=smtp://[smtp username]:[smtp password]@[server name or IP]:[port: 25, 465, or 587]/
    volumes:
      - [path to public content]:/built_app/programs/web.browser/app

Note, you can include multiple instances of either Rocket.Chat or Wekan simply by providing a new name (e.g. rocketchat2 or wekan2 or similar) and a new set of properties - just make sure you're using a unique (and otherwise unused) port number! You can check what's on your server's ports using netstat -punta | less to make sure you're not doubling up. 

In case it's not obvious, you can leave out either the rocketchat or wekan definitions if you don't want to run those services!

Creating and Running the Docker Containers

It's easy to create the containers: simply run

docker pull mongo
docker pull rocket.chat
docker pull mquandalle/wekan

and when it's finished, run

docker-compose up

which should start all your containers, but leave you with a running log - this is great for testing, but when you're happy it's all running you hit CTRL-C (to shut down the current set of containers) and then run

docker-compose up -d

which runs the containers in daemon mode, without the running log. You can then log out of your server, and your containers will continue running!

Based on the configuration above (the "unless-stopped" directive), your containers will restart automatically if your server is rebooted. If you do want to stop them for some reason, you can via

docker-compose stop

Easy.

Serving them to the Web

Once you've got your containers running, you need to make sure you've got a web server running on your host to act as the reverse proxy so that external requests get sent to them reliably! We use Nginx.

RocketChat Nginx

Here's our configuration (with appropriate [substitutions]) - you can create it as /etc/nginx/sites-available/[domain name]:

server {
    listen 80;
    server_name [domain name];

  ## Access and error logs.
  access_log /var/log/nginx/[domain name]_access.log;
  error_log /var/log/nginx/[domain name]_error.log;

  # see https://tech.oeru.org/protecting-your-users-lets-encrypt-ssl-certs
  include /etc/nginx/includes/letsencrypt.conf

  # we use a 302 temporary redirect rather than a 301 permanent redir
  location / {
    return 302 https://[domain name]$request_uri;
  }
}

server {
    listen 443 ssl;
    ssl on;

       # see https://tech.oeru.org/protecting-your-users-lets-encrypt-ssl-certs
    ssl_certificate /etc/letsencrypt/live/[domain name]/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/[domain name]/privkey.pem;
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_dhparam /etc/ssl/certs/dhparam.pem;

    keepalive_timeout 20s;

    root /var/www/html;
    index index.html index.htm;

    server_name [domain name];

    ## Access and error logs.
    access_log /var/log/nginx/[domain name]_access.log;
    error_log /var/log/nginx/[domain name]_error.log;

    location / {
        proxy_pass http://127.0.0.1:[your rocketchat port];
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $http_host;
        proxy_set_header X-Forwarded-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-Forward-Proto http;
        proxy_set_header X-Nginx-Proxy true;
        proxy_redirect off;
    }
}

 

Wekan Nginx

Here's our configuration (with appropriate [substitutions]) - you can create it as /etc/nginx/sites-available/[domain name]

# from https://github.com/wekan/wekan/wiki/Install-Wekan-Docker-in-production
upstream websocket {
    server 127.0.0.1:[wekan port];
}

map $http_upgrade $connection_upgrade {
    default upgrade;
    '' close;
}


server {
    listen    80;

    root /var/www/html;
    index index.html index.htm;

    # Make site accessible from http://localhost/
    server_name [domain name];

    access_log /var/log/nginx/[domain name]_access.log;
    error_log /var/log/nginx/[domain name]_error.log;

    # see https://tech.oeru.org/protecting-your-users-lets-encrypt-ssl-certs
    include /etc/nginx/includes/letsencrypt.conf

    location / {
        return 302 https://[domain name]$request_uri; 
    }
}

server {
    listen 443 ssl;
    ssl on;

       # see https://tech.oeru.org/protecting-your-users-lets-encrypt-ssl-certs
    ssl_certificate /etc/letsencrypt/live/[domain name]/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/[domain name]/privkey.pem;
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_dhparam /etc/ssl/certs/dhparam.pem;

    keepalive_timeout 20s;

    access_log /var/log/nginx/[domain name]_access.log;
    error_log /var/log/nginx/[domain name]_error.log;

    root /var/www/html;
    index index.html index.htm;

    server_name [domain name];

    location / {
        proxy_read_timeout 300;
        proxy_connect_timeout 300;
        proxy_redirect off;
        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_pass http://127.0.0.1:[your wekan port];
        proxy_set_header Host $host;
    }

    location ~ websocket$ {
        proxy_pass http://websocket;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $connection_upgrade;
    }

}

Enable Nginx Configuration

To make your configurations active, do the following for each of your Nginx configurations:

cd /etc/nginx/sites-enabled

Do this for each file:
ln -sf ../sites-available/[filename] .

To check if there are any errors in the files, run

nginx -t

If not, you can restart Nginx to incorporate the new configuration files:

sudo service nginx reload

You can check for errors in the relevant log files specified in your nginx configurations above in /var/log/nginx/*_error.log or /var/log/nginx/*_access.log.

Protecting your users and reputation with encryption

We encourage you to ensure that these services are made available with full encryption to protect your users' privacy. It's easy (and no cost) to set up!  The "include" directive in the Nginx configuration files above are examples of this approach.

Upgrades and Backups

We also encourage you to keep your services upgraded. It's easy to do and you'll experience little if any perceptible down time!

Simply re-pull the containers and restart them - the updated containers will be launched without loss of data!

docker pull mongo
docker pull rocket.chat
docker pull mquandalle/wekan

docker-compose up -d

If you want to back up your data - you need to do normal file backups of the directories on your local server that you've configured in the docker-compose.yml file, and you can do MongoDB backups based on our previous article on the topic!