Setting up Matrix and Riot with docker
2020-03-20In an effort to no longer depend on Facebook Messenger, WhatsApp, and other Hangouts, I have been using Matrix and Riot as much as possible for a while now.
I have been using their public instance, and it's fine most of the time, but it can be quite laggy at rush hour.
The coronavirus epidemic, with everyone stuck at home, certainly hasn't helped either...
It's been on my list of things to try for a long time, and now I finally did it: I setup my own instance with both Synapse and Riot!
Here is a guide, in hope it can be useful to someone, even if this someone might just be future-me. (hi! 👋)
Disclaimer: all the following worked at the time I wrote this, for Synapse v1.11.1 and Riot v1.5.13.
Please adapt as necessary for more recent versions...
Reverse proxy (caddy)
The startup order of all the services might not be too important, but preparing the reverse proxy first will prevent Synapse and Riot from outputting a lot of errors on startup if they can't access and be accessed from the urls they are expecting.
There is some official documentation on the topic of using a reverse proxy in front of Synapse, but I adapted it a bit because I encountered some issues with it and my dockerized setup. A third party Synapse admin web-app also failed to work with this configuration, calling non-existing api endpoints...
Note: I'm using caddy outside docker. To use a dockerized caddy, adapt as needed.
Caddy 1 configurations
Synapse
my.matrix.host {
# change: NOT /_matrix because otherwise,
# /_synapse does not work on this port and synapse-admin fails to work
proxy / http://127.0.0.1:18008 {
transparent
}
}
my.matrix.host:8448 {
proxy / http://127.0.0.1:18008 {
transparent
}
}
Riot
my.riot.host {
proxy / http://127.0.0.1:18010 {
transparent
}
}
Caddy 2 (beta 15) configurations
Synapse
my.matrix.host {
# change: NOT /_matrix because otherwise,
# /_synapse does not work on this port and synapse-admin fails to work
reverse_proxy 127.0.0.1:18008
}
my.matrix.host:8448 {
reverse_proxy 127.0.0.1:18008
}
Riot
my.riot.host {
reverse_proxy 127.0.0.1:18010
}
That's it!
Deploying Synapse
I chose not to use a dedicated database server. SQLite will do for now.
docker-compose.yml
:
version: "3.4"
services:
synapse:
container_name: "synapse"
image: "matrixdotorg/synapse:v1.11.1-py3"
restart: "unless-stopped"
ports:
- "127.0.0.1:18008:8008"
- "127.0.0.1:18448:8448"
volumes:
- "./data/:/data/"
Synapse will expect its /data
mount point to already have a valid configuration.
Synapse configuration file
Generating the initial configuration is documented here, but basically, you just have to run the following:
docker run -it --rm \
-v "/opt/matrix/synapse/data:/data" \
-e SYNAPSE_SERVER_NAME=my.matrix.host \
-e SYNAPSE_REPORT_STATS=yes \
matrixdotorg/synapse:v1.11.1-py3 generate
This will generate a homeserver.yaml
file on the container's /data
mount point, that should be reviewed and customized as needed.
I basically changed the following:
- uncommented and set a value for
public_baseurl
- uncommented and set a value for
user_ips_max_age
- uncommented and set a value for all the
smtp_*
properties, under theemail section
- uncommented and set
enable_notifs
totrue
- uncommented and set a value for
client_base_url
- I also had to add two properties in the
email
section, or my instance wouldn't start! (There is an open issue about it):notif_template_html: notif_mail.html
notif_template_text: notif_mail.txt
Then docker-compose up -d
everything, and you are done!
(Maybe check docker-compose logs -f
to make sure everything is all right...)
Deploying Riot
Riot is even easier to setup.
docker-compose.yml
:
version: "3.4"
services:
riot:
container_name: "riot"
image: "vectorim/riot-web:v1.5.13"
restart: "unless-stopped"
ports:
- "127.0.0.1:18010:80"
volumes:
- "./config.json/:/app/config.json"
Copy and adapt your config.json
from the sample one.
Then docker-compose up -d
, et voilà!
User provisioning
By default, new users registration is disabled.
Adding new users was surprisingly difficult, as there is absolutely no admin UI.
Creating an admin user
Synapse comes with a CLI tool (register_new_matrix_user
) to create users, but it's a bit cumbersome to use, and it cannot set a user's display name or email.
It's nonetheless necessary if only to create the first admin user...
Accessing the command inside the docker container can be done by opening an interactive shell: docker exec -it synapse sh
.
Executing register_new_matrix_user -c /data/homeserver.yaml https://my.matrix.host:8448
should then be enough.
The tool will prompt for a user name, password, and whether the new user should be an admin.
Creating other users
My goal was to be able to create a user, set its initial password, display name, and email.
At the time of writing, the third party Synapse admin web app cannot initialize a user's email.
The only thing that worked was curl
... 😶 (and even for that, the api documentation is hard to find)
The following examples are crafted with the help of https://matrix.org/docs/guides/client-server-api to first get an access_token
, and https://github.com/matrix-org/synapse/blob/master/docs/admin_api/user_admin_api.rst for the user admin api.
Getting an access_token
curl -XGET "https://my.matrix.host:8448/_matrix/client/r0/login"
# You should manually confirm it's a known and expected login flow:
{
"flows": [
{
"type": "m.login.password"
}
]
}
curl -XPOST -d \
'{"type":"m.login.password", "user":"myadminuser", "password":"mypassword"}' \
"https://my.matrix.host:8448/_matrix/client/r0/login"
# Should output something like this:
{
"access_token": "{ACCESS_TOKEN}",
"device_id": "DDKBZUMSNV",
"home_server": "my.matrix.host",
"user_id": "@myadminuser:my.matrix.host",
"well_known": {
"m.homeserver": {
"base_url": "https://my.matrix.host/"
}
}
}
Using the User Admin API
Once you have an admin access_token
, you can do the following:
List users
curl --header "Authorization: Bearer {ACCESS_TOKEN}" -XGET \
https://my.matrix.host:8448/_synapse/admin/v2/users?from=0&limit=10&guests=false
Query a user
curl --header "Authorization: Bearer {ACCESS_TOKEN}" -XGET \
https://my.matrix.host:8448/_synapse/admin/v2/users/@test:my.matrix.host
Modify or create a user
curl --header "Authorization: Bearer {ACCESS_TOKEN}" -XPUT -d \
'{"displayname":"Display Name", "password": "password", "threepids": [{"medium": "email", "address":"useremail@example.com"}] }' \
https://my.matrix.host:8448/_synapse/admin/v2/users/@newuser:my.matrix.host
Initializing other user values
I wanted to enable email notifications for all my new users, but unfortunately, there is no easy way to do that.
(BTW, is that a Matrix feature, or a Riot one? 🤔)
Based on what Riot does when enabling the feature from its UI, A POST
to https://my.matrix.host/_matrix/client/r0/pushers/set
should be enough, but I'm not sure about how to find all the relevant data the endpoint expects...
Since I don't plan on having too many users, I gave up, and logged in into Riot for each of them to manually enable the setting. 🙂
(Same for adding default rooms, etc. It would be nice, but it's currently easier to do it manually...)
What's next?
In the end, it wasn't too difficult. (but still difficult enough to warrant a guide)
Matrix and Riot are still rough around the edges, but they are getting better and better. I hope the tooling and documentation will follow.
Performance is correct, and without question a lot better than on the public Riot instance. (I'm running everything on a dedicated server powered by an Atom CPU and 2GB or RAM)
Synapse is currently using about 100MB, and Riot about 4MB. (according to docker stats
)
The server's load average hasn't changed much.
I wonder how long I will be able to keep my instance running without having to switch to a dedicated database engine...
I also need to setup some kind of automated backup for my data. I hope I will be able to write a post about that later...
Bonus
To check a Matrix/Synapse server version:
curl https://my.matrix.host/_synapse/admin/v1/server_version
# This will return something like that:
{
"python_version": "3.7.6",
"server_version": "1.11.1"
}
The comment is shown highlighted below in context.
JavaScript is required to see the comments. Sorry...