Skip to content

jpcshka/matrix-compose

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

72 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Matrix Server based on Synapse

A ready-to-use configuration for deploying a Matrix homeserver via Docker Compose.

Also available in: Русский

Table of Contents

  1. Stack
  2. Repository Structure
  3. Requirements
  4. DNS Setup
  5. Quick Start
  6. Components
  7. Operations

Stack

  • Matrix Synapse: The main homeserver, developed by Element Creations Ltd in Python.
  • Caddy: Reverse proxy server, issues and manages Let's Encrypt certificates. Developed by Matt Holt in Go.
  • LiveKit: Media server for MatrixRTC, written in Go by LiveKit Inc.
  • lk-jwt-service: Authorization service for MatrixRTC, developed by Element Creations Ltd in Go.
  • Prometheus: Metrics collection service, developed by Cloud Native Computing Foundation in Go.
  • Grafana OSS: Observability and data visualization platform, developed by Grafana Labs in Go.
  • Node Exporter: System metrics exporter, developed by Cloud Native Computing Foundation in Go.

Repository Structure

.
├── caddy/              # Caddy configuration (Caddyfile)
├── livekit/            # LiveKit configuration example (livekit.yaml.example)
├── prometheus/         # Prometheus configuration (prometheus.yml)
├── static/             # Static files for the placeholder page (html, css, js)
├── synapse/            # Synapse with S3 support (Dockerfile, homeserver.example.yaml)
├── .env.example        # Environment variables example
└── compose.yaml        # Main compose file

Requirements

  • Linux server (Debian 13 recommended)
  • A domain name
  • Open ports:
    • 80/tcp
    • 443/tcp
    • 443/udp
    • 7881/tcp (optional)
    • 50100-50101/udp (optional)

The list of required ports depends on your MatrixRTC (LiveKit) configuration.

Recommended Server Configuration

Resource Recommendation
CPU 2-4 vCPU
RAM 2-8 GB
Disk 20+ GB
Network Public IPv4

At least 4 GB RAM is recommended for MatrixRTC.


DNS Setup

Create A records for your Matrix homeserver and MatrixRTC domains pointing to your server's IP address.

example.com          A    203.0.113.1
matrix.example.com   A    203.0.113.1
livekit.example.com  A    203.0.113.1
grafana.example.com  A    203.0.113.1

All services run on the same server, so all DNS records should point to the same IP address.


Quick Start

  1. Copy and fill in the environment variables:
cp .env.example .env
  1. Read the Components section and configure each service according to the documentation.

  2. Start:

docker compose up -d

Make sure your DNS records are configured and ports are open before starting — Caddy won't issue certificates without external access.


Components

Synapse

Matrix homeserver based on the official matrixdotorg/synapse image with the synapse-s3-storage-provider module added for storing media in S3-compatible storage.

Configuration files, keys, and media are stored in /var/lib/matrix-compose/data.

Create the directory:

mkdir -p /var/lib/matrix-compose/data

Generate configuration files:

docker run -it --rm \
    --mount type=bind,src=/var/lib/matrix-compose/data,dst=/data \
    -e SYNAPSE_SERVER_NAME=example.com \
    -e SYNAPSE_REPORT_STATS=no \
    matrixdotorg/synapse:latest generate

You can also use the configuration example from the repository as a starting point: synapse/homeserver.example.yaml.

Add the following line to homeserver.yaml:

public_baseurl: "https://matrix.example.com/"

You also need to configure the Postgres connection:

database:
  name: psycopg2
  args:
    user: synapse_user
    password: your_strong_password
    dbname: synapse
    host: 1.2.3.4
    port: 5432
    cp_min: 5
    cp_max: 10
    keepalives_idle: 10
    keepalives_interval: 10
    keepalives_count: 3

To enable MatrixRTC calls, you need to enable federation or openid:

listeners:
  - port: 8008
    resources:
    - compress: false
      names:
      - client
#      - federation
      - openid # <---
    tls: false
    type: http
    x_forwarded: true

You also need to enable MSCs (Matrix spec proposals) and specify the LiveKit server domain:

experimental_features:
  msc4222_enabled: true
  msc4354_enabled: true

max_event_delay_duration: 24h
rc_message:
  per_second: 0.5
  burst_count: 30
rc_delayed_event_mgmt:
  per_second: 1
  burst_count: 20

matrix_rtc:
  transports:
  - type: livekit
    livekit_service_url: https://livekit.example.com/livekit/jwt

To enable S3 storage, configure the storage provider:

media_storage_providers:
- module: s3_storage_provider.S3StorageProviderBackend
  store_local: True
  store_remote: True
  store_synchronous: True
  config:
    bucket: <S3_BUCKET_NAME>
    region_name: <S3_REGION_NAME>
    endpoint_url: <S3_LIKE_SERVICE_ENDPOINT_URL>
    access_key_id: <S3_ACCESS_KEY_ID>
    secret_access_key: <S3_SECRET_ACCESS_KEY>
    session_token: <S3_SESSION_TOKEN>

See also:


Caddy

Reverse proxy based on the official caddy image. Issues and manages TLS certificates for each subdomain, serves .well-known endpoints for Matrix, redirects all other requests to example.com, and serves static files.

By default, Caddy does not set a limit on request body size. An explicit limit of 300MB is configured:

request_body {
  max_size 300MB
}

The limit must match the limit in homeserver.yaml:

max_upload_size: 300M

For QUIC (HTTP/3) and LiveKit WebRTC traffic to work correctly, you need to increase the UDP buffers at the kernel level.

Apply immediately (until reboot):

sudo sysctl -w net.core.rmem_max=7500000
sudo sysctl -w net.core.wmem_max=7500000

To persist after reboot, add to /etc/sysctl.conf:

net.core.rmem_max=7500000
net.core.wmem_max=7500000

The value 7500000 is recommended by the quic-go library used internally by Caddy.

See also:


LiveKit

Media server for MatrixRTC. LiveKit does not support environment variables for most configuration parameters, so all settings are defined directly in livekit/livekit.yaml. Copy the example and fill it in:

cp livekit/livekit.yaml.example livekit/livekit.yaml

Instead of opening dozens of ports, UDP mux is used. The number of ports must be no less than the number of CPU cores on the server:

rtc:
  udp_port: 50100-50101

You also need to expose these ports in compose.yaml:

livekit:
  ports:
    - "50100-50101:50100-50101/udp"

If you use multiple LiveKit servers, Redis is required.

See also:


lk-jwt-service

Authorization service for MatrixRTC based on the official image. Acts as middleware between the client and LiveKit: issues JWT tokens that authorize participation in a call. All parameters are passed via environment variables in .env — no separate configuration file is required.


Prometheus & Grafana

Monitoring stack based on official images: Prometheus collects metrics from all services, node-exporter — host metrics, Grafana — visualization.

To enable Synapse metrics, add to homeserver.yaml:

enable_metrics: true
listeners:
  # beginning of the new metrics listener
  - port: 9000
    type: metrics
    bind_addresses: ['0.0.0.0']

To enable LiveKit metrics, add to livekit/livekit.yaml:

prometheus_port: 6789

Caddy exposes metrics on port 2019 — this is already configured in Caddyfile and prometheus/prometheus.yml, no additional steps required.

Grafana is available via Caddy with basic_auth. To generate a password hash (argon2id):

docker compose exec -it caddy sh
caddy hash-password --algorithm argon2id --plaintext 'yourpassword'

See also:


Operations

Automated Deployment

Use GitHub Actions for automated deployment. Copy .github/workflows/deploy.yml into your repository — deployment will trigger automatically on a v*.*.* tag push or manually.

  1. Create a user on the server
sudo useradd -m -s /bin/bash gh-deploy
sudo mkdir -p /home/gh-deploy/.ssh
sudo chmod 700 /home/gh-deploy/.ssh
  1. Create the deploy script

Create the script and make it executable:

sudo touch /path/to/deploy.sh
sudo chmod +x /path/to/deploy.sh

Example script:

#!/bin/bash
set -e

cd /path/to/matrix-compose

echo "Pulling changes"
git fetch origin main

CADDYFILE_CHANGED=$(git diff HEAD origin/main -- caddy/Caddyfile)

git merge --ff-only origin/main

echo "Pulling images"
docker compose pull

echo "Starting services"
docker compose up -d

if [ -n "$CADDYFILE_CHANGED" ]; then
  echo "Caddyfile changed, reloading Caddy"
  docker compose exec caddy caddy reload --config /etc/caddy/Caddyfile
fi

echo "Done!"
  1. Grant sudo privileges
echo "gh-deploy ALL=(root) NOPASSWD: /path/to/deploy.sh" | sudo tee /etc/sudoers.d/gh-deploy
  1. Configure SSH access

Generate an SSH key for GitHub Actions and add the public key to /home/gh-deploy/.ssh/authorized_keys with a forced script execution on connection:

command="sudo /path/to/deploy.sh",no-pty,no-port-forwarding,no-X11-forwarding,no-agent-forwarding ssh-ed25519 AAAA...
sudo chmod 600 /home/gh-deploy/.ssh/authorized_keys
sudo chown -R gh-deploy:gh-deploy /home/gh-deploy/.ssh
  1. Add secrets to the repository

Settings → Secrets and variables → Actions → New repository secret

Get the server's public key for SSH_KNOWN_HOSTS:

ssh-keyscan -t ed25519 example.com
Secret Description
SSH_PRIVATE_KEY Private SSH key for connecting to the server
SSH_KNOWN_HOSTS Server public key (output of ssh-keyscan)
SSH_USER User on the server (gh-deploy)
SSH_HOST Server IP address or domain

Media Cleanup

With the S3 module enabled, Synapse still saves media files locally. To transfer already accumulated files to S3 and free up local storage, the plugin developers provide the s3_media_upload script.

  1. Download the script:
wget https://raw.githubusercontent.com/matrix-org/synapse-s3-storage-provider/main/scripts/s3_media_upload
chmod +x s3_media_upload
  1. Create a database.yaml file with Postgres connection details:
user: synapse_user
password: your-strong-password
dbname: synapse
host: 203.0.113.1
port: 5432
  1. Media files are owned by the user with uid 991 (synapse inside the container), so the script must be run as root:
sudo su
  1. Create a virtual environment and install dependencies:
python3 -m venv .venv
source .venv/bin/activate
pip install boto3 botocore humanize psycopg2-binary tqdm pyyaml
  1. Set AWS environment variables:
export AWS_ACCESS_KEY_ID="your-access-key"
export AWS_SECRET_ACCESS_KEY="your-secret-key"
export AWS_DEFAULT_REGION="your-region"
  1. Mark files older than 30 days as ready for upload:
./s3_media_upload update /var/lib/matrix-compose/data/media_store/ 30d
  1. Upload files to S3 and delete local copies:
./s3_media_upload upload /var/lib/matrix-compose/data/media_store/ your-bucket --endpoint-url https://s3.example.com --delete

A cache.db file will be created during the process — do not delete it: it will be updated on subsequent runs.

About

Ready-to-deploy Matrix homeserver stack with Synapse, Caddy, LiveKit, and monitoring via Prometheus and Grafana. Includes S3 storage support through a custom synapse-s3 Docker image published to GHCR.

Topics

Resources

License

Stars

3 stars

Watchers

0 watching

Forks

Packages

 
 
 

Contributors