In 2020 I first setup a Matrix [1] server. Matrix is a full featured instant messaging protocol which requires a less stringent definition of “instant”, messages being delayed for minutes aren’t that uncommon in my experience. Matrix is a federated service where the servers all store copies of the room data, so when you connect your client to it’s home server it gets all the messages that were published while you were offline, it is widely regarded as being IRC but without a need to be connected all the time. One of it’s noteworthy features is support for end to end encryption (so the server can’t access cleartext messages from users) as a core feature.

Matrix was designed for bridging with other protocols, the most well known of which is IRC.

The most common Matrix server software is Synapse which is written in Python and uses a PostgreSQL database as it’s backend [2]. My tests have shown that a lightly loaded Synapse server with less than a dozen users and only one or two active users will have noticeable performance problems if the PostgreSQL database is stored on SATA hard drives. This seems like the type of software that wouldn’t have been developed before SSDs became commonly affordable.

The matrix-synapse is in Debian/Unstable and the backports repositories for Bullseye and Buster. As Matrix is still being very actively developed you want to have a recent version of all related software so Debian/Buster isn’t a good platform for running it, Bullseye or Bookworm are the preferred platforms.

Configuring Synapse isn’t really hard, but there are some postential problems. The first thing to do is to choose the DNS name, you can never change it without dropping the database (fresh install of all software and no documented way of keeping user configuration) so you don’t want to get it wrong. Generally you will want the Matrix addresses at the top level of the domain you choose. When setting up a Matrix server for my local LUG I chose the top level of their domain as the DNS name for the server.

If you don’t want to run a server then there are many open servers offering free account.

Server Configuration

Part of doing this configuration required creating the URL with the following contents so clients know where to connect. Note that you should not setup Jitsi sections without first discussing it with the people who run the Jitsi server in question.

  "m.homeserver": {
    "base_url": ""
  "jitsi": {
    "preferredDomain": ""
  "im.vector.riot.jitsi": {
    "preferredDomain": ""

Also the URL for other servers to know where to connect:

  "m.server": ""

If the base_url or the m.server points to a name that isn’t configured then you need to add it to the web server configuration. See section 3.1 of the documentation about well known Matrix client fields [3].

The SE Linux specific parts of the configuration are to run the following commands as Bookworm and Bullseye SE Linux policy have support for Synapse:

setsebool -P httpd_setrlimit 1
setsebool -P httpd_can_network_relay 1
setsebool -P matrix_postgresql_connect 1

To configure apache you have to enable proxy mode and SSL with the command “a2enmod proxy ssl proxy_http” and add the line “Listen 8443” to /etc/apache2/ports.conf and restart Apache.

The command “chmod 700 /etc/matrix-synapse” should probably be run to improve security, there’s no reason for less restrictive permissions on that directory.

In the /etc/matrix-synapse/homeserver.yaml file the macaroon_secret_key is a random key for generating tokens.

To use the server as a “trusted key server” and not receive warnings put the following line in the config file:

suppress_key_server_warning: true

A line like the following is needed to configure the baseurl:


To have Synapse directly accept port 8448 connections you have to change bind_addresses in the first section of listeners to the global listen IPv6 and IPv4 addresses.

The registration_shared_secret is a password for adding users. When you have set that you can write a shell script to add new users such as:

# usage: matrix_new_user USER PASS

synapse_register_new_matrix_user -u $1 -p $2 -a -k THEPASSWORD

You need to set tls_certificate_path and tls_private_key_path to appropriate values, usually something like the following:

tls_certificate_path: "/etc/letsencrypt/live/"
tls_private_key_path: "/etc/letsencrypt/live/"

For the database section you need something like the following which matches your PostgreSQL setup:

  name: "psycopg2"
    user: WWWWWW
    password: XXXXXXX
    database: YYYYYYY
    host: ZZZZZZ
    cp_min: 5
    cp_max: 10

You need to run psql commands like the following to set it up:

create role WWWWWW login password 'XXXXXXX';
create database YYYYYYY with owner WWWWWW ENCODING 'UTF8' LOCALE 'C' TEMPLATE 'template0';

For the Apache configuration you need something like the following for the port 8448 web server:

<VirtualHost *:8448>
  SSLEngine on

  AllowEncodedSlashes NoDecode
  ProxyPass /_matrix nocanon
  ProxyPassReverse /_matrix
  AllowEncodedSlashes NoDecode
  ProxyPass /_matrix nocanon
  ProxyPassReverse /_matrix

Also you must add the ProxyPass section to the port 443 configuration (the server that is probably doing other more directly user visible things) for most (all?) end-user clients:

  ProxyPass /_matrix nocanon

This web page can be used to test listing rooms via federation without logging in [4]. If it gives the error “Can’t find this server or its room list” then you must set allow_public_rooms_without_auth and allow_public_rooms_over_federation to true in /etc/matrix-synapse/homeserver.yaml.

The Matrix Federation Tester site [5] is good for testing new servers and for tests after network changes.


The Element (formerly known as Riot) client is the most common [6]. The following APT repository will allow you to install Element via “apt install element-desktop” on Debian/Buster.

deb default main

The Debian backports repository for Buster has the latest version of Quaternion, “apt install quaternion” should install that for you. Quaternion doesn’t support end to end encryption (E2EE) and also doesn’t seem to have good support for some other features like being invited to a room.

My current favourite client is Schildi Chat on Android [7], which has a notification message 24*7 to reduce the incidence of Android killing it. Eventually I want to go to PinePhone or Librem 5 for all my phone use so I need to find a full featured Linux client that works on a small screen.

Comparing to Jabber

I plan to keep using Jabber for alerts because it really does instant messaging, it can reliably get the message to me within a matter of seconds. Also there are a selection of command-line clients for Jabber to allow sending messages from servers.

When I first investigated Matrix there was no program suitable for sending messages from a script and the libraries for the protocol made it unreasonably difficult to write one. Now there is a Matrix client written in shell script [8] which might do that. But the delay in receiving messages is still a problem. Also the Matrix clients I’ve tried so far have UIs that are more suited to serious chat than to quickly reading a notification message.


Here is a list of bridges between Matrix and other protocols [9]. You can run bridges yourself for many different messaging protocols including Slack, Discord, and Messenger. There are also bridges run for public use for most IRC channels.

Here is a list of integrations with other services [10], this is for interacting with things other than IM systems such as RSS feeds, polls, and other things. This also has some frameworks for writing bots.

More Information

The Debian wiki page about Matrix is good [11].

The site allows searching for public rooms [12].

5 comments to Matrix

  • Dan

    Hi Russell,

    besides not being able to change the DNS name afterwards, you can also never delete users[*]. That is because, in the end, matrix is not a messaging protocol but a general purpose syncing protocol based on an immutable event DAG.
    That is also one of the reasons why there are not many that self-host matrix servers, because of the resources that it needs. If one of your users is a member of a channel on another instance where gigabytes or terabytes of video material is posted, then all of that is synced to your own instance. That is by design and cannot be configured away.


  • This is epic and not in a good way!

    So what happens if terabytes of video are synced? I guess the user can unsubscribe to make the server free the space.

  • Typo:

    > add the line “Listen 8443” to /etc/apache2/ports.conf

    but then you use 8448 everywhere else.

  • Marcos: you are correct that port 8448 should be added too.

  • I prefer to reduce synapse to an ad-hoc contact system (sqlite instead of postgreSQL, no fediverse features, etc) due to the complexity of the (somewhat ill-designed) protocol, which I have a hard time trusting.

    I find this reduced-matrix to be the easiest way to selfhost E2E chat platform and with most high risk parts disabled it’s also easier to manage.