Matrix homeserver with Docker
Tags: docker, matrix, chat, element
Published: 2019-01-04 11:41:52

---
title: Matrix homeserver with Docker
published: true
tags: docker,matrix,chat,element
canonical_url: https://jonnev.se/matrix-homeserver-with-docker/
---

 ![Matrix homeserver with Docker](https://jonnev.se/content/images/2017/09/Screen-Shot-2017-09-15-at-12.05.34-1.png)

There are many good reasons to switch to Matrix from whatever proprietary monolith chat system you are using today. As others have written about that I'm not gonna delve on those now.

I'm a big Docker fan so when I decided to setup my own Synapse homeserver I was glad to find an [image](https://github.com/silvio/docker-matrix) ready to use. I'll take you through setting up Synapse together with Postgres and a Let's Encrypt certificate. With this setup adding additional services like bots or bridges is easy.

Before we start here are some general points about Matrix.

- Matrix is the _protocol_.
- There are a couple of [servers](https://matrix.org/docs/projects/try-matrix-now.html#servers) available but Synapse is AFAIK the only (more or less) production ready. It will eventually be replaced by Dendrite (written in Go).
- [Clients](https://matrix.org/docs/projects/try-matrix-now.html#clients) are plenty so you should be able to find one to your liking. I prefer Riot both for desktop and mobile.
- There are also a lot of bridges (called _Application Services_) to other networks like IRC, Slack and Gitter to name a few.

## Prerequisites

This guide assumes some general knowledge of Linux and that you have a server available with these services installed:

- [docker](https://docs.docker.com/engine/installation/linux/docker-ce/ubuntu/)
- [docker-compose](https://docs.docker.com/compose/install/)
- Let's Encrypt [certbot](https://certbot.eff.org)
- [nginx](https://nginx.org/en/download.html)
- A **domain** to host your homeserver on

I use **Ubuntu 16.04** , most of this should work just fine for other distros but you know, YMMV.

_If you're gonna start up a new server - like a VPS - I recommend [this guide](https://plusbryan.com/my-first-5-minutes-on-a-server-or-essential-security-for-linux-servers) for some basic security._

Also, I used [Digital Ocean](https://www.digitalocean.com) to follow my own guide and make sure everything worked. I think they are great and if you haven't tried it already feel free to use this [referral link](https://m.do.co/c/37d221e6802a) to get $10 for your Matrix server :D

**Edit** : For those unfamiliar with `nginx` [Martial Lienert](https://twitter.com/MartialLienert) suggested [Caddy](https://caddyserver.com). I haven't tried it myself but for serving a single host like Synapse it looks pretty neat.

## Setup

We'll be using `docker-compose` to be able to easily change options for the containers or adding new services. The default database is `sqlite` but even with a small homeserver like mine I noticed a big difference in responsiveness with `postgres`. And if you plan on joining big rooms like [#matrix:matrix.org](https://matrix.to/#/#matrix:matrix.org) it's a must since Matrix will federate data to all servers with at least one user in a room. So in a room with 10000+ users there will be a lot of writes to the database.

_Clicking on the #matrix link above will display a page where you can pick a client and join directly. Although I recommend not creating an account on [matrix.org](http://matrix.org) if you plan on running your own homeserver, since migration isn't available at the moment._

It might be a good idea to read through the Synapse [README](https://github.com/matrix-org/synapse/blob/master/README.rst) if you haven't already. **Note that the parts about which ports to use** is kinda confusing. This guide will have everything setup the recommended way but if you're curious about the details you should read [this issue](https://github.com/matrix-org/synapse/issues/2438).

### Base directory

To keep the different services grouped together and for a more manageable `docker-compose.yaml` we'll create a base directory.

```
sudo mkdir /opt/matrix
```

### Generating Synapse files

Next we will generate the required files for Synapse. This will add a self-signed certificate used for federation, a `homeserver.yaml` config file and a log config.

You need to decide on what hostname to use. It's possible to host Synapse on a subdomain (f.e `matrix.example.com`) and still have clients connect to `example.com`, but it requires some [extra setup](https://github.com/matrix-org/synapse#id34). I'd recommend having a dedicated domain.

```
# This will create /opt/matrix/synapse
docker run -v /opt/matrix/synapse:/data --rm \
    -e SERVER_NAME=example.com -e REPORT_STATS=yes silviof/docker-matrix generate
```

☝️ **Remember to replace `example.com` in the command.**

**Edit:** I've changed the `REPORT_STATS` above from `no` after discussion since I think it's important to support Matrix in any way possible. Originally I just copied the command from the image README and gave it no further thought. If you are interested in what's being shared, have a look [here](https://github.com/matrix-org/synapse/blob/24df57679521925a16595423d0b37db58668dcd7/synapse/app/homeserver.py#L407-L439). (Thanks Rob!)

### Creating a docker network

To have the containers talk to each other and also the ability to add other services to the same network without including them in the `docker-compose.yaml` (bots for example), we'll create a docker network.

```
docker network create matrix-network
# To see what containers are connected (none atm..)
docker network inspect matrix-network
```

### Setting up docker-compose

Now we create a `docker-compose.yaml` with our two services. Some options here are rather important to the setup so I've commented them in the file. [Here](https://gist.github.com/joenas/be7e1ca587301b8910c9fd44c3751c08) is a gist with the contents as well.

```
cd /opt/matrix
sudo nano docker-compose.yaml

version: "2"
services:
  postgres:
    image: postgres:9.6.4
    restart: always
    
    # I like to be able to use psql on the host to connect to the database 
    # for maintenance. If you already have a postgres running you should remove 
    # the 'ports' section and uncomment 'expose'
    # expose:
    # - 5432
    
    # Adding 127.0.0.1 ensures the port isn't exposed ON the host
    ports:
      - "127.0.0.1:5432:5432"
    volumes:
     - /opt/matrix/pgdata:/var/lib/postgresql/data

    # These will be used in homeserver.yaml later on
    environment:
     - POSTGRES_PASSWORD=YOUR_PASSWORD_HERE
     - POSTGRES_USER=synapse

  synapse:
    image: silviof/docker-matrix
    # Exposing 8008 (no TLS) on localhost means we can reverse proxy with nginx
    # 8448 is for federation and should be exposed on host
    # 3478 is for TURN (voip calls)
    ports:
     - "127.0.0.1:8008:8008"
     - "8448:8448"
     - "3478:3478"
    volumes:
     - /opt/matrix/synapse:/data

# Our docker network!
networks:
  default:
    external:
      name: matrix-network
```

### Editing homeserver.yaml

There are a couple of places we need to make **modifications**. We want to disable the built-in `webclient` and make sure port `8008` is accessible from the host.

```
sudo nano /opt/matrix/synapse/homeserver.yaml

# I've remove default comments and added mine
listeners:
  -
    port: 8448

    bind_addresses:
      - '0.0.0.0'

    type: http
    tls: true

    resources:
      -
        names:
          - client
          #- webclient # I've disabled this
        compress: true

      - names: [federation] # Federation APIs
        compress: false

  # Unsecure HTTP listener,
  - port: 8008
    tls: false
    
    # Since it's running in a container we need to listen to 0.0.0.0
    # The port is only exposed on the host and put behind reverse proxy
    bind_addresses:
      - '0.0.0.0'

    type: http
    x_forwarded: true
    resources:
      # I've removed webclient here as well
      - names: [client]
        compress: true
      - names: [federation]
        compress: false
```

We change from default `sqlite` database to `postgres` with our credentials from `docker-compose.yaml`.

```
# Database configuration
database:
  name: psycopg2
  args:
    user: synapse
    password: YOUR_PASSWORD_HERE
    database: synapse

    # This hostname is accessible through the docker network and is set 
    # by docker-compose. If you change the name of the service it will be different
    host: postgres
```

We'll enable registration to be able to test. You can change this later on.

```
# Enable registration for new users.
enable_registration: True
```

☝️ **Don't replace the entire `homeserver.yaml` with this, just make sure the corresponding sections are correct**.

### Editing log config (optional)

I prefer to have the logs in a separate directory so let's change that. There should be a file in your `/opt/matrix/synapse` called `yourhostname.log.config`. Edit it and change to

```
handlers:
  file:
    filename: /data/log/homeserver.log

# Create the directory
sudo mkdir /opt/matrix/synapse/log
```

### Obtaining Let's Encrypt cert

You need to have [certbot](https://certbot.eff.org) installed!

```
sudo service nginx stop
sudo letsencrypt certonly --standalone -d yourhostname.com
sudo service nginx start
```

### Nginx configuration

Here's the [gist](https://gist.github.com/joenas/194af2f7c2ccf2b04b0a8472974c2447).

```
sudo nano /etc/nginx/sites-available/example.com # or whatever

server {
       listen 80;
       server_name example.com www.example.com;
       return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl;
    listen [::]:443 ssl;
    server_name example.com;

    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

    # If you don't wanna serve a site, comment this out
    root /var/www/example.com;
    index index.html index.htm;

    location /_matrix {
      proxy_pass http://0.0.0.0:8008;
      proxy_set_header X-Forwarded-For $remote_addr;
    }
 }

sudo ln -s /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled/example.com
```

### Start all the things!

Now we should be ready to go so let's try.

```
cd /opt/matrix
docker-compose up -d
docker-compose ps

# Something like this 
matrix_postgres_1 docker-entrypoint.sh postgres Up 127.0.0.1:5432->5432/tcp
matrix_synapse_1 /start.sh start Up 0.0.0.0:3478->3478/tcp, 127.0.0.1:8008->8008/tcp, 0.0.0.0:8448->8448/tcp
```

If everything looks good

```
sudo service nginx reload
```

### Register account and login

Here comes the fun part! Let's create an account :)

Any client would do but for this let's use Riot. Click [here](https://riot.im/app/#/register), fill in your info and change the _"Custom server"_ to the hostname of your newly created one. Adding an email is optional but if you **ever need to reset your password you can't without it**.

![Matrix homeserver with Docker](https://jonnev.se/content/images/2017/09/Screen-Shot-2017-09-15-at-12.02.19.png)

### If everything is ok you should be greeted by the friendly `@riot-bot`!

![Matrix homeserver with Docker](https://jonnev.se/content/images/2017/09/Screen-Shot-2017-09-15-at-12.05.34.png)

## Happy happy joy joy

So, hopefully you've made it this far and now have your own Matrix homeserver. There are a lot of neat things to do with Matrix and I'll be posting more about that, bots and other integrations for example. But for now enjoy your awesome federated open source chat and invite some friends!

If you found any errors in this guide or just feel like sharing your appreciation, drop me an email or tweet :)