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 :-)