🚀 Update 🚀
Synapse v1.0.0
is now released! I have upgraded my server without any problems and therefore updated the guide with the latest version.
So our good friends at matrix.org released a v0.99.1.1
of Synapse as a precursor for a much anticipated 1.0 release. A big change in the upcoming release is that federation between servers will now require a proper TLS certificate and the current self signed cert that Synapse provides won't work. Homeserver owners are advised to make that change as soon as possible, as v1 is supposed to be released in March.
I've been running my Synapse behind Traefik for quite some time now but never bothered to replace the certificate for federation, although I have proper TLS on the client side. Once I figured out the different options it was pretty straight forward to find one that worked with Traefik.
In this guide we are going to put both the client side and federation of Synapse on a non-subdomain - ie example.com
- and use port 443
for both, so no 8448
for federation. If you have another setup - for example matrix.example.com
- it should be possible with some adjustments.
We'll achive this by using both a SRV record and a .well-known/matrix/server
file to delegate federation to example.com
. Synapse itself will be available on synapse.example.com
.
I'm also using postgres
as the database for Synapse.
Prerequisites
If you already have a server with Traefik running then continue. Otherwise I recommend you read my previous post and you'll be back here soon.
Also if you want to set up your own Matrix server at Digital Ocean feel free to use my referral link to get $100 for your server or my Hetzner link to get €20 😊 The referrals keep this blog going!
Setup
Let's make a directory for your data to live in, as sudo if needed.
mkdir /opt/matrix
# If you had to use sudo, set permissons
sudo chown -R $USER:$GROUP /opt/matrix
Then we need an internal docker network for the services to communicate on
docker network create matrix
docker-compose.yml
We'll put our services in a docker-compose file to be able to easily manage things. We'll start with Synapse. I'm using the avhost/docker-matrix image but it should be possible to use the official one too I'm sure.
nano /opt/matrix/docker-compose.yml
version: "2"
services:
postgres:
image: postgres:9.6.4
restart: unless-stopped
networks:
- default
volumes:
- /opt/matrix/pgdata:/var/lib/postgresql/data
environment:
- POSTGRES_PASSWORD=SECRET
- POSTGRES_USER=synapse
labels:
- "traefik.enable=false"
synapse:
image: avhost/docker-matrix:v1.0.0
restart: unless-stopped
depends_on:
- postgres
networks:
- web
- default
ports:
# Coturn
- "3478:3478"
- "5349:5349"
volumes:
- /opt/matrix/synapse:/data
labels:
- "traefik.backend=synapse"
- "traefik.enable=true"
- "traefik.frontend=true"
- "traefik.port=8008"
- "traefik.frontend.rule=Host:synapse.example.com"
- "traefik.docker.network=web"
networks:
default:
external:
name: matrix
# Traefiks network
web:
external: true
☝️ Remember to replace example.com
in traefik.frontend.rule
. That is where we do the reverse proxy for servers. Also change the POSTGRES_PASSWORD
env.
Nginx
To be able to serve the .well-known
path on our domain we need Nginx. We're also going to use nginx to proxy clients to Synapse. With this setup you have the options to also serve static files on your domain, like example.com/some-site
.
Let's make a directory for nginx with a subdirectory for www.
mkdir -p /opt/matrix/nginx/www
Then we need a .well-known directory to put files in, for both our server and for clients.
mkdir -p /opt/matrix/nginx/www/.well-known/matrix
We start with the server file. This will take care of proxying federation to your subdomain so you'll be able to have usernames in Matrix like @me:example.com
, while actually hosting Synapse at synapse.example.com
.
nano /opt/matrix/nginx/www/.well-known/matrix/server
Here you place a JSON formatted file.
{
"m.server": "synapse.example.com:443"
}
☝️ Replace example.com
above and make sure to NOT include https
or anything like that.
Next up is a client
file, which makes it possible to sign in to your Riot with custom domain configured by only using your username
and not full MXID (@username:example.com
).
nano /opt/matrix/nginx/www/.well-known/matrix/client
Another JSON formatted file.
{
"m.homeserver": {
"base_url": "https://example.com"
}
}
☝️ Here you include the full URL. You can also add m.identity_server
if you have your own.
Now we need a config file for nginx
!
nano /opt/matrix/nginx/matrix.conf
server {
listen 80 default_server;
server_name example.com;
# Traefik -> nginx -> synapse
location /_matrix {
proxy_pass http://synapse:8008;
proxy_set_header X-Forwarded-For $remote_addr;
client_max_body_size 128m;
}
location /.well-known/matrix/ {
root /var/www/;
default_type application/json;
add_header Access-Control-Allow-Origin *;
}
}
Now we can add nginx to our docker-compose.yml
.
version: "2"
services:
postgres:
# ...
synapse:
# ...
# Add this
nginx:
image: nginx:1.12-alpine
restart: unless-stopped
networks:
- web
- default
labels:
- "traefik.enable=true"
- "traefik.frontend.rule=Host:example.com"
- "traefik.frontend.passHostHeader=true"
- "traefik.port=80"
- "traefik.docker.network=web"
volumes:
- ./nginx/matrix.conf:/etc/nginx/conf.d/matrix.conf
- ./nginx/www:/var/www/
networks:
# ...
Synapse config
Now we are ready to configure our Synapse so we can get it up and running.
This will create a homeserver.yaml
in our synapse
directory.
docker run -v /opt/matrix/synapse:/data --rm \
-e SERVER_NAME=example.com \
-e REPORT_STATS=yes \
avhost/docker-matrix:v1.0.0 \
generate
☝️ Replace example.com
with your "short" domain, no subdomains.
We then need to edit some stuff.
sudo nano /opt/matrix/synapse/homeserver.yaml
This is not a complete configuration file, just the parts that needs editing.
## Server ##
server_name: "example.com"
☝️ Since we are using a proxy for federation we only use the "short" domain here, without the subdomain (synapse.example.com
).
listeners:
- port: 8008
tls: false
# Since it's running in a container we need to listen to 0.0.0.0
# The port is only exposed on the host and put behind reverse proxy
bind_addresses: ['0.0.0.0']
# Previous
# bind_addresses: ['::1', '127.0.0.1']
type: http
x_forwarded: true
resources:
- names: [client, federation]
compress: false
We change from sqlite
to postgres
.
# Database configuration
database:
name: psycopg2
args:
user: synapse
# From your docker-compose.yml
password: YOUR_PASSWORD_HERE
database: synapse
# This hostname is accessible through the docker network and is set
# by docker-compose. If you change the name of the service it will be different
host: postgres
We'll enable registration to be able to test. You can change this later on.
# Enable registration for new users.
enable_registration: True
That should be it. I do recommend reading through the config and perhaps another guide to checkout all the options but for now let's try and start up our services...
cd /opt/matrix
docker-compose up -d
docker-compose ps
... and you should get something like this.
Name Command State Ports
--------------------------------------------------------------------------------------------------------------------
matrix_nginx_1 nginx -g daemon off; Up 80/tcp
matrix_postgres_1 docker-entrypoint.sh postgres Up 5432/tcp
matrix_synapse_1 /start.sh autostart Up 0.0.0.0:3478->3478/tcp, 0.0.0.0:5349->5349/tcp, 8448/tcp
If the services are not up
have a look at the logs with docker-compose logs
(start with docker-compose logs synapse
if the wall of text is too much).
Register account and login
If everything looks good, you can now use Riot to create an account and login. You need to select "Advanced" and then change Homeserver URL to your own.
Final notes
SRV Record
You should also add a SRV record to support older homeservers.
_matrix._tcp.example.com. IN SRV 10 5 443 synapse.example.com.
Troubleshooting
If it seems like people on other homeservers can't see your messages, or the other way around, your federation might be broken. Matrid Federation Tester is a good first place to check. If you want to see the actual data from the tester, use this link instead but replace the hostname.
Hosting Riot
If you want your own Riot you can use this guide I've written. It should also possible be to add Riot to the setup above with some modifications to your docker-compose.yml
(add riot.example.com
to traefik.frontend.rule
) and your nginx.conf
(add a new location
and directory to nginx/www/
).
Thanks!
If you have any questions or feedback please comment below or hit me up on Twitter 🙌