Intro

Matrix is an open standard for decentralised communication, which securely distributes persistent chatrooms over an open federation of servers preventing any single points of control or failure. 1

What is synapse?

Synapse is an open-source Matrix homeserver written and maintained by the Matrix.org Foundation. 2

Because the open-source concept of Matrix and Synapse there are many projects to extend the default functionalities. We cloud use so called bridges to connect an bot to our synpase server which can forward messages from WhatsApp, Signal, Telegram, Instagram or Discord to our private chatroom. 3

basic docker deployment

This deployment just include the bare minimium an synapse instance could run. We are using the original docker image and running a postgres database for storing data. With this setup you can only register users via CLI. You also will need an client to connect to your synaps matrix server. I would recommend fluffychat or element. With these settings only local (users on your instance) can chat. Federation will not work. Also please don’t run this in any serious/productive type of use-case. All packages getting send via http, so completely unencryted. Later we will use an reverse proxy manager to encrypt the traffic.

requirement:

  • web domain with an subdomain (something like matrix.foryourdomain.com)
  • access to dns records of the web domain
  • docker and docker-compose installed on the server you want to host your synapse instance

Setup an A-record for example matrix.foryourdomain.com and the ip address from your server.

Define some environment variables in ./synapsedb.env

POSTGRES_USER=YOUR_POSTGRES_USERNAME
POSTGRES_PASSWORD=YOUR_POSTGRES_PASSWORD
POSTGRES_INITDB_ARGS=--encoding=UTF-8 --lc-collate=C --lc-ctype=C

Next just run the following docker-compose file with docker-compose up -d.

version: '3'

services:

  synapse:
    container_name: synapse
    image: docker.io/matrixdotorg/synapse:latest
    restart: unless-stopped
    environment:
      - SYNAPSE_CONFIG_PATH=/data/homeserver.yaml
    volumes:
      - ./synapse:/data
    depends_on:
      - synapse-db
    networks:
      - matrix
      - postgres
    ports:
      - 8008:8008/tcp
    healthcheck:
      test: ["CMD", "curl", "-fSs", "http://localhost:8008/health"]
      interval: 15s
      timeout: 5s
      retries: 3
      start_period: 5s
    runtime: runc

  synapse-db:
    image: docker.io/postgres:12-alpine
    container_name: synapse-db
    # Change that password, of course!
    env_file:
      - synapsedb.env
    volumes:
      - ./db/schemas:/var/lib/postgresql/data
    networks:
      - postgres
    healthcheck:
      test: ["CMD", "pg_isready", "-U", "synapse"]
      interval: 15s
      timeout: 5s
    runtime: runc

networks:
  matrix:
  postgres:

After the first run you should stop the container with docker compose stop synapse and adjust the parameter of your homeserver.yaml under ./synapse/homeserver.yaml.

Here is my base configuration as an example:

server_name: "matrix.foryourdomain.com"
pid_file: /data/homeserver.pid
# i'm using an reverse proxy so this should be fine
listeners:
  - port: 8008
    tls: false
    type: http
    x_forwarded: true
    resources:
      - names: [client]
        compress: false
database:
  name: psycopg2
  args:
    user: YOUR_POSTGRES_USERNAME # please change
    password: YOUR_POSTGRES_PASSWORD # please change
    database: YOUR_POSTGRES_USERNAME # please change in the most cases the username == the postgres database names
    host: synapse-db
    cp_min: 5
    cp_max: 10
log_config: "/data/matrix.foryourdomain.com.log.config"
media_store_path: /data/media_store
registration_shared_secret: "AUTOGENERATED_SECRET"
report_stats: true
enable_metrics: true
macaroon_secret_key: "AUTOGENERATED_SECRET"
form_secret: "AUTOGENERATED_SECRET"
signing_key_path: "/data/matrix.foryourdomain.com.signing.key"
trusted_key_servers:
  - server_name: "matrix.org"

to register a new user you could run the following commands:

docker exec -it synapse /bin/bash
register_new_matrix_user -u user1 -p p@ssword -a -c /data/homeserver.yaml

this will register a new user with administrator permissions.

lets secure our traffic with an reverse proxy

Next we will use an reverse proxy to encrypt the http traffic so we could achive an secured connection between our clients and the server. I’m using nginx proxy manager there are also alternatives like haproxy, traefik or caddy. There is a nice guide how to setup nginx proxy manager on linode.com.

So I will asume you have an working reverse proxy with SSL certificates and also managed to route the traffic to the reverse proxy. Also you have to establish a encrypted connection between the synapse server and the server the reverse proxy is running on, likely an VPN connection. I’m running the reverse proxy and the synapse server on the same machine so I don’t have to mind secured connections between multiple servers.

Acording to the text about the docker-compose.yml should now look something like this:

version: "3"

services:
  synapse:
    container_name: synapse
    image: docker.io/matrixdotorg/synapse:latest
    restart: unless-stopped
    environment:
      - SYNAPSE_CONFIG_PATH=/data/homeserver.yaml
    volumes:
      - ./synapse:/data
    depends_on:
      - synapse-db
    networks:
      - matrix
      - postgres
    ports:
      - 8008:8008/tcp
    healthcheck:
      test: ["CMD", "curl", "-fSs", "http://localhost:8008/health"]
      interval: 15s
      timeout: 5s
      retries: 3
      start_period: 5s
    runtime: runc

  synapse-db:
    image: docker.io/postgres:12-alpine
    container_name: synapse-db
    # Change that password, of course!
    env_file:
      - synapsedb.env
    volumes:
      - ./db/schemas:/var/lib/postgresql/data
    networks:
      - postgres
    healthcheck:
      test: ["CMD", "pg_isready", "-U", "synapse"]
      interval: 15s
      timeout: 5s
    runtime: runc

  npm:
    image: 'jc21/nginx-proxy-manager:latest'
    container_name: nginxproxymanager
    restart: unless-stopped
    volumes:
      - ./data:/data
      - ./letsencrypt:/etc/letsencrypt
    ports:
      - '80:80'
      - '443:443'
      - '81:81'
    networks:
      - proxy

networks:
  matrix:
  postgres:
  proxy:

TODO

  1. create proxy entry
  2. test connection
  3. add additional settings

monitoring

When running services in production a common-practice is to use some monitoring software to identify problems quickly. The synapse documentation recommends the grafana monitoring stack which we will also use. TODO: add link to grafana/synapse documentation Also the synapse team is providing us a very useful dashboard.

  • grafana

optimizations

  • storage data
  • fast storage for databases and uploads