Docker + Synapse + Element = your own, scalable selfhosted messaging service, and it works on your Synology NAS!
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.
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 followPrerequisites
- 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 newsynapse
folder - Inside your
synapse
folder, create two files,docker-compose.yml
and.env
- Still inside your
synapse
directory, create two folders,config
andschema
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 treesynapse
>config
(so thatconfig
is a folder insidesynapse
) - 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
[ ]
bracketsWhen 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]
Using postgres
- In your
homserver.yaml
file, locate the part that starts withdatabases
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'
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!
Have some feedback or something to add? Comments are welcome!
Please note comments should be respectful, and may be moderated