You found me!
  • About
  • All posts

Swarming a Matrix - Mon, Dec 21, 2020

Years ago I was introduced to Matrix, a federated chat protocol/software suite. I’ve always been interested in federated protocols because I think these are important to keep viable alternatives to big tech platforms. But I never really got around to playing with this.

However, these last few months I’ve finaly gotten around to doing some real work with Matrix. My (fairly basic) stack consists of:

  • Postgres database
  • NGINX webserver/proxy
  • Synapse server (the Matrix ‘back-end’ server)
  • Element web-app

I’ve already got a [Docker swarm stack running]({% post_url 2020-03-25-my-docker-playground %}) so my idea was to set this up with a dedicated domain as a docker stack.

My stack file looks like this:

version: '3'

# - Bootstrap the synapse config:
#docker run -it --rm \
#    -v /path/to/docker/volumes/matrix/synapse:/data \
#    -e SYNAPSE_SERVER_NAME=mymatrixdomain.im \
#    -e SYNAPSE_REPORT_STATS=yes \
#    matrixdotorg/synapse:latest generate
#
# - Configure db settings

networks:
  matrix:
    external: false
  proxy:
    external: true

services:
  db:
    restart: always
    image: postgres:alpine
    volumes:
      - /path/to/docker/volumes/matrix/postgresql:/var/lib/postgresql/data
    environment:
      POSTGRES_USER: synapse
      POSTGRES_PASSWORD: ************
      POSTGRES_INITDB_ARGS: "--encoding='UTF8' --lc-collate='C' --lc-ctype='C'"
    networks:
      - matrix

  synapse:
    image: matrixdotorg/synapse:latest
    volumes:
      - /path/to/docker/volumes/matrix/synapse:/data
    restart: always
    networks:
      - matrix
    depends_on:
      - db

  # Config element as per https://github.com/vector-im/element-web/blob/develop/docs/config.md
  element:
    # formerly known as riot
    image: vectorim/riot-web:latest
    volumes:
      - /path/to/docker/volumes/matrix/element/config.json:/app/config.json
    restart: always
    networks:
      - matrix

  nginx: 
    image: nginx:latest
    volumes:
      - /path/to/docker/volumes/matrix/nginx/nginx.conf:/etc/nginx/nginx.conf
    networks:
      - matrix
      - proxy
    deploy:
      labels:
        traefik.enable: "true"
        traefik.http.routers.apexproxy.rule: Host(`mymatrixdomain.im`)
        traefik.http.routers.apexproxy.entrypoints: https
        traefik.http.routers.apexproxy.tls.certresolver: letsencrypt
        traefik.http.services.apexproxy.loadbalancer.server.port: 80
        traefik.docker.network: proxy

As can be seen in the top comments, a docker command is needed to initialise Synapse. It would be nice if that could also be automated, but I’ve not yet found a nice way to do it. Also, after initialisation I’ve modified the configuration to support de Postgres database. The configuration lives in homeserver.yaml. It may be worthwhile to read through it and tweak settings to your personal preferences.

 # For more information on using Synapse with Postgres, see `docs/postgres.md`.
 #
 database:
-  name: sqlite3
+  name: psycopg2
   args:
-    database: /data/homeserver.db
+    user: synapse
+    password: **********
+    database: synapse
+    host: db
+    cp_min: 5
+    cp_max: 10

Next up: Getting a configuration for Element in to a config.json file for your container. See the configuration docs for that, and adjust it for your domain and preferences. Make sure you keep registration enabled for now (you can disable it later after you registered you own user if you want). If you make changes to homeserver.yaml at some later stage don’t forget to restart the synapse container.

And finally the NGINX proxy which directs requests either to Element or Synapse depending on what is asked. Here is the nginx.conf:

user  nginx;
worker_processes  1;

error_log /dev/stdout info;
#error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;

events {
        worker_connections 768;
        # multi_accept on;
}

http {
  access_log /dev/stdout;

  server {
    listen 80;
    listen [::]:80;

    # For Matrix Synapse client connections
    location /_matrix {
        proxy_pass http://synapse:8008;
        proxy_set_header X-Forwarded-For $remote_addr;
    }

    location / {
        proxy_pass http://element:80;
        proxy_set_header X-Forwarded-For $remote_addr;
    }
  }
}

After this you should be good to go. Fire up the stack and see if you can register yourself. I’d love to hear suggestions on what can be improved here :-)

Back to Home


© Florian Overkamp 2025 | Just some personal ramblings. | Socials: Mastodon LinkedIn