How to Self-Host Matrix and Element (Docker Compose)

Self-Hosting Oct 10, 2021

Version 2

This is a complete guide on setting up Matrix (Synapse) and Element on a fresh Ubuntu 20.04, Debian 11, CentOS or Fedora server.

Need a Server?
Hetzner - €20 credit on us (ref) - Free Arm instance for 4 months!
Vultr - $100 credit on us (ref) - Expires after 30 days

Contents
What is Matrix?
Server Setup
Install UFW
Setup Sudo User
Install Docker
Install Matrix and Element
Create New Users
Reverse Proxy
Login

If your server is already setup feel free to skip.

What is Matrix?

Matrix is an open standard and communication protocol for real-time communication. It aims to make real-time communication work seamlessly between different service providers, just like standard Simple Mail Transfer Protocol email does now for store-and-forward email service, by allowing users with accounts at one communications service provider to communicate with users of a different service provider via online chat, voice over IP, and videotelephony. Such protocols have been around before such as XMPP but Matrix is not based on that or another communication protocol. From a technical perspective, it is an application layer communication protocol for federated real-time communication. It provides HTTP APIs and open source reference implementations for securely distributing and persisting messages in JSON format over an open federation of servers. It can integrate with standard web services via WebRTC, facilitating browser-to-browser applications. Wikipedia

Server Setup

  1. Update
    Ubuntu/Debian: sudo apt update && sudo apt upgrade
    CentOS/Fedora: sudo dnf upgrade

  2. Install automatic updates
    Ubuntu/Debian: sudo apt install unattended-upgrades
    CentOS/Fedora: sudo dnf install -y dnf-automatic

  3. Change SSH Port: sudo nano /etc/ssh/sshd_config

Remove the # infront of Port 22 and then change it (30000-50000 is ideal).

This is security though obsucurity which is not ideal but port 22 just gets abused by bots.

  1. Setup SSH Keys

  2. Restart SSH: sudo systemctl restart sshd

  3. Install fail2ban
    Ubuntu/Debian: sudo apt install fail2ban
    CentOS/Fedora: sudo dnf install fail2ban

Install UFW Firewall

  1. Install
    Ubuntu/Debian: sudo apt install ufw
    CentOS/Fedora: sudo dnf install ufw

  2. Replace SSH-PORT to your SSH port: sudo ufw allow <SSH-PORT>/tcp

  3. Allow HTTP/s traffic:

sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
  1. Enable Firewall: sudo ufw enable

Setup a sudo user

  1. adduser <USERNAME>
  2. Add user to sudoers sudo adduser <USERNAME> sudo
  3. Login as the new user su - <USERNAME>

Install Docker

Official Docs:
Ubuntu
Debian
CentOS
Fedora

Install Matrix and Element

  1. Create docker network, this is so Matrix and Element can be on their own isolated network:
    sudo docker network create --driver=bridge --subnet=10.10.10.0/24 --gateway=10.10.10.1 matrix_net

  2. Create Matrix directory: sudo mkdir matrix && cd matrix

  3. Use the following template:
    sudo nano docker-compose.yaml

version: '2.3'
services:
  postgres:
    image: postgres:14
    restart: unless-stopped
    networks:
      default:
        ipv4_address: 10.10.10.2
    volumes:
     - ./postgresdata:/var/lib/postgresql/data

    # These will be used in homeserver.yaml later on
    environment:
     - POSTGRES_DB=synapse
     - POSTGRES_USER=synapse
     - POSTGRES_PASSWORD=STRONGPASSWORD
     
  element:
    image: vectorim/element-web:latest
    restart: unless-stopped
    volumes:
      - ./element-config.json:/app/config.json
    networks:
      default:
        ipv4_address: 10.10.10.3
        
  synapse:
    image: matrixdotorg/synapse:latest
    restart: unless-stopped
    networks:
      default:
        ipv4_address: 10.10.10.4
    volumes:
     - ./synapse:/data

networks:
  default:
    external:
      name: matrix_net
  1. Create Element Config sudo nano element-config.json
    Copy and paste example contents into your file.

  2. Remove "default_server_name": "matrix.org" (top line) from element-config.json as this is deprecated

  3. Add our custom homeserver to the top of element-config.json:

    "default_server_config": {
        "m.homeserver": {
            "base_url": "https://matrix.example.com",
            "server_name": "matrix.example.com"
        },
        "m.identity_server": {
            "base_url": "https://vector.im"
        }
    },
  1. Generate Synapse Config:
sudo docker run -it --rm \
    -v "$HOME/matrix/synapse:/data" \
    -e SYNAPSE_SERVER_NAME=matrix.example.com \
    -e SYNAPSE_REPORT_STATS=yes \
    matrixdotorg/synapse:latest generate
  1. Comment out sqlite database (as we have setup postgres to replace this):
    sudo nano synapse/homeserver.yaml:
#database:
#  name: sqlite3
#  args:
#    database: /data/homeserver.db
  1. Add the Postgres config:
    sudo nano synapse/homeserver.yaml
database:
  name: psycopg2
  args:
    user: synapse
    password: STRONGPASSWORD
    database: synapse
    host: postgres
    cp_min: 5
    cp_max: 10
  1. Deploy: sudo docker compose up -d

Create New Users

  1. Access docker shell: sudo docker exec -it matrix_synapse_1 bash
  2. register_new_matrix_user -c /data/homeserver.yaml http://localhost:8008
  3. Follow the on screen prompts
  4. Enter exit to leave the container's shell

To allow anyone to register an account set 'enable_registration' to true in the homeserver.yaml. This is NOT recomended.

Install Reverse Proxy (Caddy)

Caddy will be used for the reverse proxy. This will handle incomming HTTPS connections and forward them to the correct docker containers. It a simple setup process and Caddy will automatically fetch and renew Let's Encrypt certificates for us!

  1. Follow this setup guide:
Caddy Server v2 Reverse Proxy Setup Guide
Last Updated: 07/06/2021 What is Caddy? Caddy has a wide range of use cases including: Web Server Reverse Proxy Sidecar Proxy Load Balancer API Gateway Ingress Controller System Manager Process Supervisor Task Scheduler Today we will be installing and setting up Caddy as a Reverse Proxy. This will
  1. Head to your user directory: cd
  2. Create Caddy file: sudo nano Caddyfile

Recommended Caddy Template:

  • Limited Matrix paths (based on docs)
  • Security Headers
  • No search engine indexing
matrix.example.com {
  reverse_proxy /_matrix/* 10.10.10.4:8008
  reverse_proxy /_synapse/client/* 10.10.10.4:8008
  
  header {
    X-Content-Type-Options nosniff
    Referrer-Policy  strict-origin-when-cross-origin
    Strict-Transport-Security "max-age=63072000; includeSubDomains;"
    Permissions-Policy "accelerometer=(), camera=(), geolocation=(), gyroscope=(), magnetometer=(), microphone=(), payment=(), usb=(), interest-cohort=()"
    X-Frame-Options SAMEORIGIN
    X-XSS-Protection 1
    X-Robots-Tag none
    -server
  }
}

element.example.com {
  encode zstd gzip
  reverse_proxy 10.10.10.3:80

  header {
    X-Content-Type-Options nosniff
    Referrer-Policy  strict-origin-when-cross-origin
    Strict-Transport-Security "max-age=63072000; includeSubDomains;"
    Permissions-Policy "accelerometer=(), camera=(), geolocation=(), gyroscope=(), magnetometer=(), microphone=(), payment=(), usb=(), interest-cohort=()"
    X-Frame-Options SAMEORIGIN
    X-XSS-Protection 1
    X-Robots-Tag none
    -server
  }
}

Matrix Reverse Proxy Docs

  1. Enable the config: caddy reload

Login

  1. Head to your element domain and login!

Don't forget to update frequently

Pull the new docker images and then restart the containers:
sudo docker compose pull && sudo docker compose up -d

Tags