Create a Chat Server Using Matrix Synapse and Element on Ubuntu 22.04

Updated on November 21, 2023
Create a Chat Server Using Matrix Synapse and Element on Ubuntu 22.04 header image

Introduction

Matrix is a set of open APIs for decentralized and end-to-end encrypted communication. It works across a collection of federation servers to deliver Instant messages, Voice over IP (VoIP), and Internet of Things (IoT) communication in real time. It uses homeservers to store the account information and chat history. Federation works like email, which means you can either use a server hosted by somebody or host your Matrix server that provides greater control over your data. The decentralized nature of servers ensures that if one server hosting a chat goes offline, the communication continues on other servers.

Synapse is a popular homeserver implementation of Matrix written in Python and created by the Matrix.org team. This guide will teach you to install Matrix Synapse and Element web client on a Ubuntu 22.04 server.

Prerequisites

1. Configure Firewall

Matrix Synapse needs HTTP and HTTPS ports to work.

Open them using the Uncomplicated Firewall (UFW).

$ sudo ufw allow http
$ sudo ufw allow https

Open port 8448, as required by Matrix.

$ sudo ufw allow 8448

Check the firewall status to confirm.

$ sudo ufw status

2. Install Matrix Synapse

Download and import the GPG key.

$ sudo wget -O /usr/share/keyrings/matrix-org-archive-keyring.gpg https://packages.matrix.org/debian/matrix-org-archive-keyring.gpg

Add the Matrix official APT repository.

$ echo "deb [signed-by=/usr/share/keyrings/matrix-org-archive-keyring.gpg] https://packages.matrix.org/debian/ $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/matrix-org.list

Update the system repositories list.

$ sudo apt update

Install Matrix Synapse.

$ sudo apt install matrix-synapse-py3

Enter your Matrix domain name during installation as the server name. You can change it later in the /etc/matrix-synapse/conf.d/server_name.yaml file. Enter N to stop the reporting of anonymized statistics.

3. Install and Configure PostgreSQL

Synapse supports SQLite database by default which isn't suitable for a production environment because of performance issues.

Install PostgreSQL server.

$ sudo apt install postgresql postgresql-contrib

Log in to the PostgreSQL shell.

$ sudo -su postgres psql

Create a Synapse SQL user.

# CREATE ROLE syanpse LOGIN PASSWORD 'yourpassword`;

Create a Synapse Database.

# CREATE DATABASE synapsedb OWNER synapse LOCALE 'C' ENCODING 'UTF-8' TEMPLATE template0;

Exit the shell.

# exit

4. Install Nginx

Ubuntu 22.04 ships with an older version of Nginx. Add the official Nginx repository to install the latest version.

$ curl https://nginx.org/keys/nginx_signing.key | gpg --dearmor \
| sudo tee /usr/share/keyrings/nginx-archive-keyring.gpg >/dev/null

$ echo "deb [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg arch=amd64] \
http://nginx.org/packages/ubuntu `lsb_release -cs` nginx" \
sudo tee /etc/apt/sources.list.d/nginx.list

Update the system repository list.

$ sudo apt update

Install Nginx.

$ sudo apt install nginx

Start the Nginx server.

$ sudo systemctl start nginx

5. Install SSL

Issue the following commands to ensure that you have the latest version of snapd required to install Certbot.

$ sudo snap install core
$ sudo snap refresh core

Install Certbot.

$ sudo snap install --classic certbot

Create a symlink for Certbot to the /usr/bin directory.

$ sudo ln -s /snap/bin/certbot /usr/bin/certbot

Issue the SSL Certificate.

$ sudo certbot certonly --nginx --agree-tos --no-eff-email --staple-ocsp --preferred-challenges http -m name@example.com -d matrix.example.com

Generate a Diffie-Hellman group certificate.

$ sudo openssl dhparam -dsaparam -out /etc/ssl/certs/dhparam.pem 4096

Do a dry run of the SSL renewal process to ensure it works.

$ sudo certbot renew --dry-run

6. Configure Synapse

You can configure Snypase using the /etc/matrix-synapse/homeserver.yaml file, but you shouldn't use it in a production environment because it gets overwritten during an APT update.

You should configure Synapse by creating files in /etc/matrix-synapse/conf.d/ directory.

Create a database configuration file.

$ sudo nano /etc/matrix-synapse/conf.d/database.yaml

Paste the following lines in the editor. Replace yourpassword with the database user set in Step 3.

database:
  name: psycopg2
  args:
    user: synapse
    password: 'yourpassword'
    database: synapsedb
    host: localhost
    cp_min: 5
    cp_max: 10

Save the file by pressing Ctrl+X, then Y.

Create a registration key and store it in the /etc/matrix-synapse/conf.d/registration_shared_secret.key file.

$ echo "registration_shared_secret: '$(cat /dev/urandom | tr -cd '[:alnum:]' | fold -w 256 | head -n 1)'" | sudo tee /etc/matrix-synapse/conf.d/registration_shared_secret.yaml

Create a new Matrix user. Type yes to set it as administrator.

$ register_new_matrix_user -c /etc/matrix-synapse/conf.d/registration_shared_secret.yaml http://localhost:8008

Synapse doesn't allow public registration by default. Create a configuration file to enable it.

$ sudo nano /etc/matrix-synapse/conf.d/registration.yaml

Paste the following line.

enable_registration: true

Synapse requires verification for new users. To enable email verification, paste the following lines.

registrations_require_3pid:
  - email

email:
  smtp_host: mail.example.com
  smtp_port: 587

  # If mail server has no authentication, skip these 2 lines
  smtp_user: 'noreply@example.com'
  smtp_pass: 'password'

  # Optional, require encryption with STARTTLS
  require_transport_security: true

  app_name: 'Example Chat'  # defines value for %(app)s in notif_from and email subject
  notif_from: "%(app)s <noreply@example.com>"

You can disable user verification using the following code.

enable_registration_without_verification: true

Save the file by pressing Ctrl+X, then Y.

Synapse shows the user's online status by default which can cause high CPU usage. To disable the status, create a new configuration file.

$ sudo nano /etc/matrix-synapse/conf.d/presence.yaml

Paste the following lines.

presence:
  enabled: false

Save the file by pressing Ctrl+X, then Y.

Restart Synapse to apply the changes.

$ sudo systemctl restart matrix-synapse

7. Configure Nginx

Open the Nginx configuration file.

$ sudo nano /etc/nginx/nginx.conf

Add the following line before the line /etc/nginx/conf.d/*.conf.

server_names_hash_bucket_size 64;

Save the file by pressing Ctrl+X, then Y.

Create an Nginx configuration file for Synapse.

$ sudo nano /etc/nginx/conf.d/synapse.conf

Paste the following lines.

# enforce HTTPS
server {
    # Client port
    listen 80;
    listen [::]:80;
    server_name matrix.example.com;
    return 301 https://$host$request_uri;
}

server {
    server_name matrix.example.com;

    # Client port
    listen 443 ssl http2;
    listen [::]:443 ssl http2;

    # Federation port
    listen 8448 ssl http2 default_server;
    listen [::]:8448 ssl http2 default_server;

    access_log  /var/log/nginx/synapse.access.log;
    error_log   /var/log/nginx/synapse.error.log;

    # TLS configuration
    ssl_certificate /etc/letsencrypt/live/matrix.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/matrix.example.com/privkey.pem;
    ssl_trusted_certificate /etc/letsencrypt/live/matrix.example.com/chain.pem;
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_prefer_server_ciphers on;
    ssl_stapling on;
    ssl_stapling_verify on;
    ssl_dhparam /etc/ssl/certs/dhparam.pem;

    location ~ ^(/_matrix|/_synapse/client) {
            proxy_pass http://localhost:8008;
            proxy_http_version 1.1;

            proxy_set_header X-Forwarded-For $remote_addr;
            proxy_set_header X-Forwarded-Proto $scheme;
            proxy_set_header Host $host;

            # Nginx by default only allows file uploads up to 1M in size
            # Increase client_max_body_size to match max_upload_size defined in homeserver.yaml
            client_max_body_size 50M;
    }
}

Save the file by pressing Ctrl+X, then Y.

Verify the configuration file syntax.

$ sudo nginx -t

Restart the Nginx server.

$ sudo systemctl restart nginx

8. Install Coturn

You need to install a Traversal Using Relays around NAT (TURN) server to use video and voice calls.

Install Coturn.

$ sudo apt install coturn

Open the TURN and UDP ports.

$ sudo ufw allow 3478
$ sudo ufw allow 5349
$ sudo ufw allow 49152:65535/udp

Issue an SSL certificate for Coturn.

$ sudo certbot certonly --nginx -d coturn.example.com

Back up the default configuration file.

$ sudo mv /etc/turnserver.conf /etc/turnserver.conf.bak

Generate an authentication secret and store it in the configuration file.

$ echo "static-auth-secret=$(cat /dev/urandom | tr -cd '[:alnum:]' | fold -w 256 | head -n 1)" | sudo tee /etc/turnserver.conf

Open the Coturn configuration file.

$ sudo nano /etc/turnserver.conf

Paste the following lines below the authentication secret.

use-auth-secret
realm=coturn.example.com
cert=/etc/letsencrypt/live/coturn.example.com/fullchain.pem
pkey=/etc/letsencrypt/live/coturn.example.com/privkey.pem

# VoIP is UDP, no need for TCP
no-tcp-relay

# Do not allow traffic to private IP ranges
no-multicast-peers
denied-peer-ip=0.0.0.0-0.255.255.255
denied-peer-ip=10.0.0.0-10.255.255.255
denied-peer-ip=100.64.0.0-100.127.255.255
denied-peer-ip=127.0.0.0-127.255.255.255
denied-peer-ip=169.254.0.0-169.254.255.255
denied-peer-ip=172.16.0.0-172.31.255.255
denied-peer-ip=192.0.0.0-192.0.0.255
denied-peer-ip=192.0.2.0-192.0.2.255
denied-peer-ip=192.88.99.0-192.88.99.255
denied-peer-ip=192.168.0.0-192.168.255.255
denied-peer-ip=198.18.0.0-198.19.255.255
denied-peer-ip=198.51.100.0-198.51.100.255
denied-peer-ip=203.0.113.0-203.0.113.255
denied-peer-ip=240.0.0.0-255.255.255.255
denied-peer-ip=::1
denied-peer-ip=64:ff9b::-64:ff9b::ffff:ffff
denied-peer-ip=::ffff:0.0.0.0-::ffff:255.255.255.255
denied-peer-ip=100::-100::ffff:ffff:ffff:ffff
denied-peer-ip=2001::-2001:1ff:ffff:ffff:ffff:ffff:ffff:ffff
denied-peer-ip=2002::-2002:ffff:ffff:ffff:ffff:ffff:ffff:ffff
denied-peer-ip=fc00::-fdff:ffff:ffff:ffff:ffff:ffff:ffff:ffff
denied-peer-ip=fe80::-febf:ffff:ffff:ffff:ffff:ffff:ffff:ffff

# Limit number of sessions per user
user-quota=12
# Limit total number of sessions
total-quota=1200

Save the file by pressing Ctrl+X, then Y.

Restart Coturn to apply the settings.

$ sudo systemctl restart coturn

Create a Synapse configuration file for Coturn.

$ sudo nano /etc/matrix-synapse/conf.d/turn.yaml

Paste the following lines in the editor. Replace the turn_shared_secret value with the value of the static-auth-secret variable from the \etc\turnserver.conf file.

turn_uris: [ "turn:coturn.example.com?transport=udp", "turn:coturn.example.com?transport=tcp" ]
turn_shared_secret: 'static-auth-secret'
turn_user_lifetime: 86400000
turn_allow_guests: True

Save the file by pressing Ctrl+X, then Y.

Restart Synapse to apply the configuration.

$ sudo systemctl restart matrix-synapse

9. Use Matrix

You can use Synapse using any of the available Matrix clients. Element is the most popular client and is available as a web app, desktop, and mobile app.

Add your homeserver address https://matrix.example.com while logging in. Use the credentials you created in step 6. Create a secure backup for your encrypted messages and data using a security key or a phrase after logging in.

If you want to host your instance of Element web client, follow the instructions below.

10. Install Element

Install JSON text processor.

$ sudo apt install jq

Create a public directory for Element.

$ sudo mkdir -p /var/www/element

Switch to the directory.

$ cd /var/www/element

Grab the latest version of Element from its GitHub releases page.

$ latest="$(curl -s https://api.github.com/repos/vector-im/element-web/releases/latest | jq -r .tag_name)"

Download Element.

$ sudo wget https://github.com/vector-im/element-web/releases/download/${latest}/element-${latest}.tar.gz

Extract the archive.

$ sudo tar xf element-${latest}.tar.gz

Create another directory as a soft link.

$ sudo ln -s element-${latest} current

To update Element in the future, run the following command to update the soft link after extracting the archive.

$ sudo ln -nfs element-${latest} current

11. Configure Element

Switch to the current directory.

$ cd current

Create the Element configuration file using the sample.

$ sudo cp config.sample.json config.json

Open the configuration file.

$ sudo nano config.json

Edit the base_url and server_name attributes referencing your matrix subdomain and the base domain.

"m.homeserver": {
    "base_url": "https://matrix.example.com",
    "server_name": "matrix.element.com"
},

Change the brand name if you want to customize the website title.

"brand": "My Example Chat",

Edit the disable_guests variable to disallow Guests from using Element.

"disable_guests": true,

Save the file by pressing Ctrl+X, then Y.

Generate an SSL certificate for the Element client.

$ sudo certbot certonly --nginx -d element.example.com

Create and open the file /etc/nginx/conf.d/element.conf for editing.

$ sudo nano /etc/nginx/conf.d/element.conf

Paste the following lines in it.

server {
    listen 80;
    listen [::]:80;
    server_name element.example.com;
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;

    server_name element.example.com;

    root /var/www/element/current;
    index index.html;

    access_log  /var/log/nginx/element.access.log;
    error_log   /var/log/nginx/element.error.log;

    add_header Referrer-Policy "strict-origin" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header X-Frame-Options "SAMEORIGIN" always;

    # TLS configuration
    ssl_certificate /etc/letsencrypt/live/element.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/element.example.com/privkey.pem;
    ssl_trusted_certificate /etc/letsencrypt/live/element.example.com/chain.pem;
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_prefer_server_ciphers on;
    ssl_stapling on;
    ssl_stapling_verify on;
    ssl_dhparam /etc/ssl/certs/dhparam.pem;
}

Save the file by pressing Ctrl+X, then Y.

Verify the Nginx configuration file syntax.

$ sudo nginx -t

Restart the Nginx server.

$ sudo systemctl restart nginx

You can access Element via the URL https://element.example.com.

Conclusion

Following this guide, you have installed a Matrix Synapse server and an Element client on a Ubuntu 22.04 server. For more information, check out the following resources.