self hosting your whatsapp replacement with synapse / matrix, element and your reverse proxy, all in docker

Photo by Adrian Swancar / Unsplash

Docker + Synapse + Element = your own, scalable selfhosted messaging service, and it works on your Synology NAS!

Containers Nov 24, 2022

For those of us looking to move away from centralized messaging services such as WhatsApp, hosting our own versions is attractive. Enter Synapse/Matrix, and a whole host of ready-made clients you can use, safe in the knowledge that your messages aren't going anywhere except between you and your contacts.

💡
This setup is not as straightforward as running docker-compose up -d or docker run and everything works out nicely. That being said, it's not the most complicated of processes, so you should find the below steps relatively easy to follow

Prerequisites

  • Docker and docker-compose installed on your machine
  • sudo privileges to be able to run docker commands as root, or you've added your user to the docker group to bypass that
  • The ability to SSH / use CLI/terminal on your machine, or use Portainer to spin up your stacks
  • Some sort of access and relevant permissions to manage and create new directories
  • If you intend to use federation, an FQDN (fully qualified domain name) such as pointtosource.com
  • A reverse proxy already set up for the service you want, on its own docker network (for instance called proxy) with the relevant SSL certificate(s) (check out my SWAG article for some info on how to do that if you haven't already)

Setting up Synapse

There are a number of steps here.

Choosing your Synapse server name

This needs to be done first, as it cannot be changed later.

Any users who join your server will be reachable at @user:server-name.example. If you are planning on having your instance completely separate and private from the web (i.e. you cannot join other Synapse selfhosted instances and they cannot see yours) then this server name can be anything you want.

If however you do want to be able to join other servers, then you need federation (click the link to read more about it) and that means using your FQDN, such as pointtosource.com, with a reverse proxy, such as SWAG.

I will choose my server name to be element.pointtosource.com which means that I, with the username PTS would have be reachable at @PTS:element.pointtosource.com.

Creating your folder structure

For this project we need a few folders to be set up.

  • Navigate to your docker folder, or wherever you keep your compose files, and create a new synapse folder
  • Inside your synapse folder, create two files, docker-compose.yml and .env
  • Still inside your synapse directory, create two folders, config and schema

Done

Creating your proxy docker network

The compose file below will create a synapse docker bridge network for you but relies on a pre-existing proxy network for your reverse proxy. I'm assuming you have one already, but if not, here's how to create it:

  • SSH into your machine
  • Copy and paste the following:
docker network create proxy

Creating your docker-compose and .env files

Create and edit a docker-compose.yml file, pasting in the contents below:

networks:
  default:
    name: synapse
  proxy: # reverse proxy network, edit as necessary
    external: true

services:
  synapse:
    #build:
      #context: ../..
      #dockerfile: docker/Dockerfile
    image: docker.io/matrixdotorg/synapse:latest
    # Since synapse does not retry to connect to the database, restart upon
    # failure
    restart: unless-stopped
    container_name: synapse
    environment:
      - SYNAPSE_CONFIG_PATH=/data/homeserver.yaml
    volumes:
      - ./config:/data
    depends_on:
      - synapse-db
    ports:
      - 8448:8448/tcp
    networks:
      - default
      - proxy

  synapse-db:
    image: docker.io/postgres:12-alpine
    container_name: synapse-db
    environment:
      - POSTGRES_USER=$PGUSR
      - POSTGRES_PASSWORD=$PGPWD
      - POSTGRES_INITDB_ARGS=--encoding=UTF-8 --lc-collate=C --lc-ctype=C
    volumes:
      - ./schema:/var/lib/postgresql/data
  • Create and edit a .env file, pasting the contents below:
PGPWD=[create a strong password here]
PGUSR=[create your username here]

Once you've saved the above 2 files, you can move onto the next step.

Generating your config file

Once you have chosen your server name, you need to create a few folders.

  • Inside your preferred docker folder, create a subfolder tree synapse > config (so that config is a folder inside synapse)
  • SSH into your machine
  • Copy the following command
docker-compose run --rm -e SYNAPSE_SERVER_NAME=[your.synapse.server] -e SYNAPSE_REPORT_STATS=yes synapse generate
add your server name, removing the [ ] brackets

When you've done that, you should get an output similar to below. Note the files on the left hand side of the image which have been created, notably the homeserver.yaml file:

There are a LOT of config options for the homeserver.yaml file which I recommend you read here. However we need to make a few changes ourselves, namely to enable registration and also set the database to the postgres one we just created.


Editing the homserver config file

As mentioned above, a few things for us to do here:

Enabling user registration with a captcha

  • Visit this page which walks you through setting up a catcha site
  • Make sure you save your public key and secret keys
  • Open your homeserver.yaml
  • Scroll to the bottom and add the following lines
enable_registration: true
#enable_registration_without_verification: true
enable_registration_captcha: true
recaptcha_public_key: [add your public key]
recaptcha_private_key: [add your secret key]
if for any reason your captcha doesn't work, you can comment out the captcha lines, and uncomment the 'enable without verification' line

Using postgres

  • In your homserver.yaml file, locate the part that starts with databases and looks like this:
database:
  name: sqlite3
  args:
    database: /data/homeserver.db
  • Paste over the above by copying the following lines:
database:
  name: psycopg2
  args:
    user: [the USER you specified in the .env file]
    password: [the PASSWORD you specified in the .env file]
    database: postgres
    host: synapse-db
    cp_min: 5
    cp_max: 10

Save the file.

Reverse proxy

At this point, I recommend setting up your reverse proxy to point to https://matrix.yourdomain.com.

Spinning up the containers

You can now spin up the full stack, by typing docker-compose up -d into your SSH client while in the synapse folder. All being well, you will get a number of lines in the logs with no errors.


Testing and using your synapse instance

The best way to do this is to download the Element client on your device, or in your browser go directly to https://app.element.io/#/register:

  • Click the 'Edit' button top right
  • Select 'Other homeserver' and type in the URL (not server name you chose earlier), then press 'Continue'
  • Select a username (all lowercase) and your passwords, then press 'Continue'
  • Your captcha should then pop up, tick the 'I am not a robot' button and then follow the captcha

And you're in!

Additional clients for the same user

Once you've created an account, every time you log in using a different client you will need to verify it using an existing account. For example, if you download Element for Android and now log in, you will need to verify it on element web.


Setting a user as an admin

For this, we need to bash into our postgres container and edit it directly:

  • Paste the following into your SSH terminal:
docker exec -it synapse-db bash

psql postgres [username]

UPDATE users SET admin = 1 WHERE name = '@user:your.synapse.server';

Some notes:

  • Replace [username] with the USER you set in your .env file
  • Replace @user:your.synapse.server with the user you just registered, i.e. @someuser:element.pointtosource.com
  • When you've run those three, you should get an output of UPDATE 1

You can now find your access token using Element in your browser. This is necessary when making admin level API requests on your Synapse host machine.

  • Log in again (if necessary)
  • Click the settings cog bottom left, then click the 'All settings' button
  • Click 'Help & About' in the left hand nav panel
  • Scroll to the bottom of the modal and then hit the drop down arrow for 'Access Token'
💡
IMPORTANT! This access token gives full access to your account. Do not share it with anyone.

Disabling registration

When all your users are added, you can comment out the enable users line in the homeserver.yaml and restart the container. This prevents others you don't know from being able to register.

Alternatively, you could set registration_requires_token and manage it that way, wherein only users with the correct tokens can register. This requires more admin management, and you can read up more on that here.


And that's it. You now have your very own Synapse server which works with Element!

PTS

PTS fell down the selfhosted rabbit hole after buying his first NAS in October 2020, only intending to use it as a Plex server. Find him on the Synology discord channel https://discord.gg/vgSq5pcT

Have some feedback or something to add? Comments are welcome!

Please note comments should be respectful, and may be moderated