Run your end-to-end encrypted chat server using Matrix and Riot

Are you are a journalist, activist, bug bounty hunter or working at a tech company? You probably need to work together with your colleagues frequently and exchange lots of sensitive data.

You must be using one of the most popular platforms such as Slack or HipChat to collaborate then. The problem is that these chat platforms retain conversation histories for a long time, which may end up in wrong hands. The privacy of your conversations are not guaranteed, so it is time to look into better solutions.

In the first half of this tutorial, we will explain what privacy and security issues that affect the most preferred collaboration platforms.

In the second section, we show you the step-by-step instructions for installing and configuring zero-knowledge collaboration platform named Matrix and Riot. By the end of this tutorial, you will have your Matrix server running, and hosting end-to-end encrypted chat rooms ready to collaborate.

Conversation histories are not private

One major problem with the most popular chat services is that every single conversation you have ever had appears in clear-text on the server-side. These chat logs are typically retained indefinitely in an unencrypted form. This makes your chat history available to third-parties you would not expect.

We have learned from the Gawker versus Hulk Hogan trial that conversation log retention practices can backfire hard. Lawyers were skimming through the internal chat logs and cherry-picked offensive conversations that supported their case. Lame jokes and bad memes have caused the downfall of Gawker Media in the end.

Campfire chat log

In addition, conversation histories can be exposed if the admin panel gets hacked. For example, if a Slack administrator's password gets stolen by phishing, hackers may retrieve the conversation history of the whole Slack team through the admin panel.

Self-hosting alone is not the solution

Why do not we just run the chat platform on our own server, so we have full ownership and control over the chat logs? Rocket.Chat and Mattermost have put a lot of effort into developing platforms that provide a similar experience as Slack.

However, chat logs still appear in clear-text on the server-side and may be retained for various purposes. If the chat server is hacked or seized as part of an investigation, logs will be exposed to a third-party.

A word about zero-knowledge platforms

Finally, there is a new wave of zero-knowledge collaboration platforms (e.g. Semaphor, ArmorText, ClearChat).

Although these implement full end-to-end encryption, the server-side is still operated by a third-party. Secondly, the client applications are not open source in many cases. Things like a software bug may expose your chat history again.

What makes Matrix different?

The ideal solution to these concerns is a platform that combines the best of both worlds: it is end-to-end encrypted and self-hosted.

The Matrix ecosystem is a set of applications that provide a similar experience as well-known collaboration platforms. Web, desktop and smartphone applications are all available to connect.

Riot main window

Unlike Slack, however, this platform is free and open source. This means that you, your team, or your company can easily host your Matrix servers so that all information that passes through there can remain within the control of your organisation instead of a third party.

Matrix also provides native support for encrypted chat rooms. If you set it up, chat channels on your server can be end-to-end encrypted. Anyone on your server can verify its fingerprints with each other out-of-channel to make sure that the people in the room are the ones you want there.

Strictly speaking, Matrix is merely a protocol (just like XMPP): various servers and clients implement the standard. While Synapse is the server-side application, the Riot project develops the desktop (Windows, Linux, macOS) and mobile (iOS, Android) applications.

Matrix server installation guide

In the following section, we show how you can install your Matrix reference server and connect to it with the first users

You will need two simple things to run your private Matrix service:

  • A domain name (e.g. from GoDaddy)
  • A virtual server running Debian 8 on a cloud service (AWS, DigitalOcean, etc.) or a physical server
  • Basic knowledge of the Linux CLI

We will use as the server name throughout the guide.

DNS settings

Firstly, you have to register a domain name and fire up your DNS admin panel. You need to create a DNS record like the following:    300   IN  A  

Note (2017-05-21): We previously suggested to create an SRV record as well. As @richvhd pointed out, this is unnecessary

Installing Synapse

The following guide will set up Synapse, which is Matrix's reference home server implementation.

Preparing your server

First: launch a virtual machine running Debian 8 on your favourite cloud provider and SSH into the host. The instructions below assume that you are root on the server.

As Matrix/Synapse package lives in a non-standard repository, we are going to add the repo to our machine's package repository:

# echo 'deb jessie-backports main' >> /etc/apt/sources.list

And then we are going to make sure that Debian knows that the repo is there:

# apt-get update && apt-get dist-upgrade -y

Next, we need to install a few packages that will help us later. Our VMs are very barebones by default. Run the following:

# apt-get install -y apt-transport-https lsof curl python python-pip
# apt-get install -y certbot -t jessie-backports

At this point, we need to add another software repository. Create /etc/apt/sources.list.d/matrix.list and open this up in your favourite text editor.

Inside /etc/apt/sources.list.d/matrix.list, add the following two lines:

deb jessie main  
deb-src jessie main  

Installing Synapse

With that out of the way, it's time to actually install Matrix. Run the following:

# curl | apt-key add -
# apt-get update
# apt-get install matrix-synapse -y

If the package has installed without any hiccups, jump to the next section ("Adding encryption support").

If python-cffi is broken

You might get a python-cffi package conflict error at this point which will cause the matrix-synapse install to fail.

Simply run this command to install python-cffi from backports:

# apt install python-cffi/jessie-backports

Once the backported package is installed, try installing Synapse again:

# apt-get install matrix-synapse -y

You will be asked to provide a hostname for your server, which in this tutorial is

Adding encryption support

Synapse should expose the Matrix service over SSL, so we need to request a new certificate. You may reuse your existing SSL certificate if you already one for Otherwise, you can get a new one from Let's Encrypt.

We will use certbot to generate a Let's Encrypt certificate.

# certbot certonly

Choose the "spin up a temporary web server" option.

The certificate is valid for three months. To configure auto-renewal, we need to add certbot to the system crontab file:

# crontab -e

Insert the following line:

@daily   certbot renew --quiet --post-hook "systemctl reload nginx"

Configuring nginx

To make this thing truly HTTPS-ready, we need to configure a reverse proxy. We will use nginx for this, so install it:

# apt-get install nginx -y

Then add the following configuration to /etc/nginx/conf.d/matrix.conf:

server {  
    listen 443 ssl;

    ssl_certificate     /etc/letsencrypt/live/;
    ssl_certificate_key /etc/letsencrypt/live/;
    ssl_protocols       TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers         HIGH:!aNULL:!MD5;

    location /_matrix {
        proxy_pass http://localhost:8008;
        proxy_set_header X-Forwarded-For $remote_addr;

Make sure you replace with the relevant server name.

Once that's saved, restart nginx by running:

# systemctl restart nginx

Fine-tuning Synapse

Add a shared secret to the config file at /etc/matrix-synapse/homeserver.yaml:

registration_shared_secret: <add random characters here, whatever you want your secret to be>  

Synapse caches conversation information in RAM where possible, and will use as much as you give it. For small implementations, (>50 users), you probably only need about 512MB of RAM.

You can configure this by adding the SYNAPSE_CACHE_FACTOR environment variable to /etc/default/matrix-synapse


Run Synapse

Apply the settings by enabling and restarting the Synapse service:

# systemctl restart matrix-synapse
# systemctl enable matrix-synapse

Register your first Matrix user

One of the things you probably want out of this chat server is to, y'know, chat with people.

To do that, we need some user accounts, starting with your own. Create a new user by running the following, and answering the prompts:

# register_new_matrix_user -c /etc/matrix-synapse/homeserver.yaml https://localhost

- New user localpart [root]: {add your name/handle here}
- Password:
- Confirm password:
- Make admin [no]: yes
- Sending registration request…
- Success.

Enabling self-service user registrations

Optional: to save having to register new users via CLI on your server every time, you can enable GUI user registration through the Riot client by editing /etc/matrix-synapse/homeserver.yaml and changing the following setting:

enable_registration: true  

Otherwise, to register additional users, run register_new_matrix_user -c /etc/matrix-synapse/homeserver.yaml https://localhost again to manually configure more accounts.

Don't make them all admins, yeah?

Time to Riot

Riot is the fancypants front-end client for the server we just set up. If you don't have it already, you can download the app for your OS of choice at

Riot may try to auto-connect you to their default servers. If this happens, log out. We want the Riot login screen for the next part.

Let's connect Riot to the server we just configured.
Add your hostname (either your BYO hostname or the here's-what-we-prepared-earlier hostname on your handout):

Home server URL:
Identity server URL:

Riot login screen

Now log in with the user you configured in your server in the previous section of this doc.

Create a new secure room

  • Click on the gear icon to edit the room preferences

  • Turn on end-to-end encryption by ticking ‘Enable encryption’

  • Click ‘Save’

Security checkup

You may want to fine-tune the room settings to improve security:

  • Who can access this room? -> Only people who have been invited (default)
  • Who can read history? -> Members only (since they joined)
  • URL previews -> Disable URL previews
  • To invite users in the room -> Moderator

Further ahead

There's a bunch of stuff you can do with the Riot client. Here are some things to try:

  • Invite your friends to the room you just created
    • Compare key fingerprints before chatting in encrypted rooms
  • Have someone else create a room (or prevent someone else from creating a room)

There are a few things we skipped over to keep this tutorial compact. We recommend to look into the following settings later on:

  • Deploy the Riot web client
  • Deploy a firewall with iptables
  • Configure OS-level auto-updates with unattended-upgrades
  • Protect SSH login on your Debian server with two-factor authentication
  • Replace SQLite database with PostgreSQL if you are expecting lots of users
  • Configure email notifications (check enable_notifs in /etc/matrix-synapse/homeserver.yaml) - beware, emails may leak sensitive data!
  • Add room integrations:
    • GitHub bot
    • RSS bot
    • Giphy
  • Add go-neb chatbot
  • Add TURN support for audio/video calls


You can find all of the docs you could ever need (and the Matrix community itself) right here:

Happy chatting!

Interested in learning more?

Why not join one of our Meetup groups nearby? We organise hands-on workshops and talks on a regular basis:

Make sure to check out our friends' website:

Authors: Lilly Ryan and Gabor Szathmari. This tutorial is based on the workshop tutorial written for BSides Canberra security conference.

Special thanks for the additional feedback: uhoreg
Cover image is courtesy of Ben Cadet

This material is distributed under a CC BY-SA 4.0 license