Element Server Suite on Docker Compose
  • Shell 99.7%
  • Dockerfile 0.3%
Find a file
wmair c41256d29b tests: validate Caddyfile syntax for the new Authelia vhost blocks
Scenarios PD and PSA (added in the previous two commits) asserted the
Authelia vhost's content but never ran it through real Caddy syntax
validation, unlike Scenario P's Caddyfile.production. Added
assert_valid_caddyfile to both — confirmed via a live test_deploy.sh
run (Docker now available) that every other generated Caddyfile in the
suite passes `caddy validate` cleanly; these two new call sites should
too, pending a rerun.

Also: ran the full live suite (real Docker, real containers, live
endpoint checks) for the first time since #33/#34 and the OIDC/Authelia
cleanup landed. 454/455 passed. The one failure (Scenario M, Synapse
metrics port 9000) is unrelated — that test predates this session
entirely, and the run shows heavy concurrent container churn (5
bridges crash-looping, MAS mid-restart) right before a single-shot,
no-retry curl check with a fixed 30s warmup, which is consistent with
a timing flake under load rather than a real regression. Every
scenario touched by this session's changes (P, PD, PS, PSA, S, AL)
passed clean, including real `caddy validate` runs against every
generated Caddyfile.
2026-09-12 10:56:58 +02:00
compose-variants Add Prometheus/Grafana monitoring, Discord/Slack megabridges, hookshot, and synapse_auto_compressor 2026-05-11 10:10:39 +02:00
postgres/init Initial commit: Complete Matrix Stack with SSO and all bugfixes 2025-10-29 14:46:30 +01:00
synapse Add Synapse extensibility via Dockerfile + requirements.txt 2026-04-20 17:06:13 +02:00
synapse_auto_compressor Fix synapse_auto_compressor build: add make for jemalloc compilation 2026-05-11 11:32:01 +02:00
templates Replace element-admin with Ketesa and add FluffyChat integration 2026-05-11 09:42:36 +02:00
.gitignore Copy Caddy/Authelia compose files to project root in distributed mode 2026-09-12 10:20:18 +02:00
.gitlab-ci.yml Add TLD identity support, integration tests, and CI pipeline 2026-03-02 19:30:17 +01:00
BRIDGE_SETUP_GUIDE.md Add docs, SKIP_DOCKER test mode, and harden SKIP_START path 2026-05-11 11:20:05 +02:00
BUGFIXES.md docs: note Synapse security releases since last BUGFIXES.md update 2026-09-12 10:52:25 +02:00
deploy.sh Copy Caddy/Authelia compose files to project root in distributed mode 2026-09-12 10:20:18 +02:00
docker-compose.yml Fix synapse_auto_compressor flags: use short form, add required -n 2026-06-10 21:17:14 +02:00
MULTI_MACHINE_CONFIG_SNIPPETS.md Simplify compose file structure: Use docker-compose.yml as default 2025-10-29 19:05:03 +01:00
PRODUCTION_DEPLOYMENT.md Fix open registration: add SMTP prompt, default require_email to false (closes #18) 2026-04-15 09:48:23 +02:00
QUICK_REFERENCE.md Add docs, SKIP_DOCKER test mode, and harden SKIP_START path 2026-05-11 11:20:05 +02:00
quickstart.sh Fix registry check silent abort and missing Authelia vhost in single-server Caddyfile 2026-09-11 22:43:22 +02:00
README.md README: cross-link to nixmatrix (NixOS sibling of this stack) 2026-05-31 09:58:16 +02:00
setup-bridges.sh Fix telegram bridge database URI pattern for Go rewrite 2026-05-10 15:18:56 +02:00
SETUP.md Add custom Docker registry and hardened image support 2026-03-02 09:55:18 +01:00
test_deploy.sh tests: validate Caddyfile syntax for the new Authelia vhost blocks 2026-09-12 10:56:58 +02:00

Matrix Server - Docker Compose Setup

A self-hosted Matrix server stack with modern OIDC authentication, web clients, optional video calling, messaging bridges, and observability.

Run NixOS? See nixmatrix — the same stack as a single declarative NixOS flake (deploy to a fresh VPS with nixos-anywhere). This Docker Compose project is the right choice for running on an existing Docker host; nixmatrix is the right choice if you prefer NixOS.

What's Included

Core (always on)

Optional: FluffyChat (--profile fluffychat)

  • FluffyChat — Alternative Matrix web client with a friendly UI
    • Also registers FluffyChat as an OIDC client in MAS, which fixes the cross-signing reset "continue" button

Optional: Element Call (--profile element-call)

  • LiveKit — WebRTC SFU media server (self-hosted, media stays on your server)
  • lk-jwt-service — LiveKit token issuer
  • Element Call — Self-hosted video/voice calling frontend

Optional: Messaging Bridges

Always available (start with the stack, set up via setup-bridges.sh):

Optional (--profile hookshot):

  • matrix-hookshot — GitHub, GitLab, JIRA, RSS, and generic webhook integrations

Optional: Monitoring (--profile monitoring)

  • Prometheus — Metrics collection (scrapes Synapse at :9000/metrics)
  • Grafana — Dashboard visualization (Synapse dashboard pre-provisioned)

Optional: Upstream OIDC

  • Authelia — SSO / identity provider with 2FA (--profile authelia)
  • Any OIDC-compliant provider — Authentik, Keycloak, Zitadel, etc. (no extra containers)

Quick Start

Simple production deployment — four prompts, everything else is automatic:

./quickstart.sh

Asks for: your domain, a Let's Encrypt email, whether to enable Element Call, and whether to allow open registration. Generates all secrets and configs, starts the stack. Monitoring is always enabled.

Advanced deployment — local testing, SSO options, multi-machine setups, optional bridges and monitoring:

./deploy.sh

Bridges are set up separately after the core stack is running:

./setup-bridges.sh

Architecture

Browser
  |
Caddy (HTTPS, Let's Encrypt)
  |
  +-- matrix.example.com  -->  Synapse :8008
  |     /.well-known       -->  (served inline by Caddy)
  |     /login, /logout    -->  MAS :8080
  +-- auth.example.com    -->  MAS :8080
  +-- element.example.com -->  Element Web :80
  +-- chat.example.com    -->  FluffyChat :80        (optional)
  +-- admin.example.com   -->  Ketesa :8080
  +-- monitoring.example.com --> Grafana :3000       (optional)
  +-- call.example.com    -->  Element Call :8080    (optional)
  +-- rtc.example.com     -->  lk-jwt-service :8080  (optional)
                               LiveKit :7880          (optional)

All services communicate over an internal Docker network. The database is not exposed.

Deployment Options

Simple production — single machine, Let's Encrypt, four prompts:

./quickstart.sh

Advanced deployment — three modes via interactive menu:

./deploy.sh
Mode Description
Local testing Self-signed certs, *.example.test domains, /etc/hosts entries
Production (single-server) Let's Encrypt, all services on one machine
Production (distributed) Caddy / Authelia / Matrix on separate hosts, generates caddy/Caddyfile.production

SSO options (prompted during deploy.sh):

  1. None — MAS handles passwords directly
  2. Authelia — full SSO with 2FA via --profile authelia
  3. Other OIDC — Authentik, Keycloak, Zitadel, or any OIDC-compliant provider (no extra containers)

Element Call

When enabled, all three components are self-hosted. Media streams never leave your server (they route through your LiveKit SFU). The Element Call frontend is served from your own call. subdomain.

Required open ports in addition to 80 and 443:

  • TCP 7881 (WebRTC signaling)
  • UDP 50100–50200 (media streams)

Bridges

setup-bridges.sh configures WhatsApp, Signal, Discord, and Slack automatically. Telegram requires API credentials from my.telegram.org — add them to .env before running:

TELEGRAM_API_ID=your_id
TELEGRAM_API_HASH=your_hash

All bridges use Go megabridge implementations (Discord, Slack, WhatsApp, Signal) or the current Python bridge (Telegram). Bridges use double puppet support (messages appear from your actual Matrix user, not a bridge bot) and have encryption disabled for compatibility with MAS.

See BRIDGE_SETUP_GUIDE.md for details, including Discord, Slack, and matrix-hookshot setup.

Monitoring

When the monitoring profile is enabled, Prometheus scrapes Synapse metrics every 15 seconds and Grafana is provisioned with:

  • A Prometheus datasource pointing to the internal prometheus:9090 endpoint
  • The official Synapse dashboard (ID 10046) downloaded at deploy time

Synapse exposes metrics at :9000/metrics via a separate metrics.yaml config file loaded alongside homeserver.yaml (Synapse directory config mode).

Database Maintenance

synapse_auto_compressor runs continuously alongside Postgres and compresses the state_groups_state table — the primary source of Synapse database bloat. It requires no configuration and runs automatically whenever Postgres is healthy.

Synapse Extensions

Add Python packages to synapse/requirements.txt (one per line) to install them into the Synapse image at build time — useful for storage providers, LDAP modules, or custom auth handlers. An empty file is a no-op.

Air-gapped / Custom Registry

deploy.sh optionally prefixes all image references with a custom registry URL (for internal mirrors or air-gapped environments) and optionally switches Redis, PostgreSQL, and Caddy to hardened variants from dhi.io. Both settings are written to .env and picked up automatically by Docker Compose.

Requirements

  • Docker and Docker Compose v2
  • A domain with DNS control
  • Ports 80 and 443 accessible from the internet
  • For Element Call: ports 7881/TCP and 50100–50200/UDP open

Common Operations

# Status
docker compose ps

# Logs
docker compose logs -f [service]

# Restart a service
docker compose restart synapse

# Update all images
docker compose pull && docker compose up -d

# Bridge logs
docker compose logs mautrix-whatsapp
docker compose logs mautrix-discord

# Monitoring
docker compose --profile monitoring logs -f prometheus
docker compose --profile monitoring logs -f grafana

Data Directories

postgres/data/    database (back this up)
synapse/data/     media store, signing keys
mas/data/         MAS sessions
.env              all secrets and domain config

Backup:

tar -czf matrix-backup-$(date +%Y%m%d).tar.gz postgres/data synapse/data mas/data .env

Documentation

License

  • Synapse: Apache 2.0
  • Matrix Authentication Service: Apache 2.0
  • Element Web / Element Call: Apache 2.0
  • Ketesa: MIT
  • FluffyChat: AGPL 3.0
  • PostgreSQL: PostgreSQL License
  • Caddy: Apache 2.0
  • LiveKit: Apache 2.0
  • Prometheus: Apache 2.0
  • Grafana: AGPL 3.0