Recent Posts
Archives
Categories
How to setup matrix server
Synapse Server Setup (Docker + Caddy)
This guide walks you through bringing up a Matrix Synapse homeserver behind Caddy with automatic HTTPS. It uses:
- Domain: chat.fahadalisarwar.com (replace with your own where noted)
- Docker volume for persistent data: matrix_synapse_data
- Caddy as the reverse proxy/terminating TLS
Security note: Enabling open registration is convenient for first-time setup, but you should disable it after creating your admin/user accounts.
0) Prerequisites
- A server with Docker and Docker Compose installed
- A DNS A/AAAA record for chat.yourdomain.com pointing to your server
- Caddy running on the same host (or reachable reverse proxy) with ports 80 and 443 open
1) Create the Synapse data volume & generate the config
This creates a named Docker volume and generates the initial Synapse config into it.
# Create and populate /data inside the volume
docker run -it --rm \
--mount type=volume,src=matrix_synapse_data,dst=/data \
-e SYNAPSE_SERVER_NAME=chat.yourdomain.com \
-e SYNAPSE_REPORT_STATS=yes \
matrixdotorg/synapse:latest generate
This will create homeserver.yaml and other files inside the volume, typically visible on the host at:
/var/lib/docker/volumes/matrix_synapse_data/_data
If your system shows homeserver.yml (one l) keep that naming consistent—Synapse accepts either; just use the generated filename everywhere below.
2) Enable (temporary) user registration
Edit the generated config file:
/var/lib/docker/volumes/matrix_synapse_data/_data/homeserver.yaml
Add (or set) the following:
enable_registration: true
enable_registration_without_verification: true
Later, once you’ve created your users (and admin), revert these to false.
3) Minimal docker-compose.yml
Create a docker-compose.yml next to your deployment files:
services:
synapse:
image: matrixdotorg/synapse:latest
container_name: synapse
restart: unless-stopped
volumes:
- matrix_synapse_data:/data
expose:
- "8008" # HTTP (Caddy will reverse_proxy to this)
# If you prefer to bind 8008 to host (not required when using Caddy on same Docker network):
# ports:
# - "127.0.0.1:8008:8008"
# networks:
# - web # put Caddy and Synapse on the same user-defined network
volumes:
matrix_synapse_data:
external: true
name: matrix_synapse_data
# networks:
# web:
# external: true
Bring it up:
docker compose up -d
4) Caddy site config
Point your domain to the Synapse container through Caddy. Example site block:
chat.yourdomain.com {
encode zstd gzip
# CORS for mobile apps fetching .well-known
header /.well-known/matrix/* Access-Control-Allow-Origin "*"
header /.well-known/matrix/* Content-Type "application/json"
# Federation discovery (if you terminate TLS on 443 at the proxy)
@server path /.well-known/matrix/server
respond @server `{"m.server": "chat.yourdomain.com:443"}` 200
# Client discovery: where apps should talk to your homeserver
@client path /.well-known/matrix/client
respond @client `{
"m.homeserver": { "base_url": "https://chat.yourdomain.com" }
}` 200
# Proxy actual Matrix endpoints to Synapse
reverse_proxy /_matrix/* synapse:8008
reverse_proxy /_synapse/client/* synapse:8008
}
Make sure Caddy can resolve synapse (the container name). If Caddy runs in Docker, put both Caddy and Synapse on the same Docker network (e.g., web) and use synapse:8008 as above. If Caddy runs on the host, either publish port 8008 on the synapse container or reverse proxy to localhost:8008 accordingly.
Reload Caddy to apply the config.
5) Quick validation
-
Check well-known endpoints (adjust domain if changed):
curl -s https://chat.yourdomain.com/.well-known/matrix/server | jq curl -s https://chat.yourdomain.com/.well-known/matrix/client | jq -
Check Synapse is serving via the proxy:
curl -I https://chat.yourdomain.com/_matrix/client/versionsYou should get HTTP/2 200.
6) Create users (and an admin)
While registration is enabled, you can sign up from a Matrix client (e.g., Element). Alternatively, create an admin from the container:
# Create a user interactively (set password when prompted)
docker exec -it synapse register_new_matrix_user -c /data/homeserver.yaml http://localhost:8008
# To make the user an admin, add: --admin
When done, disable open registration by reverting:
enable_registration: false
enable_registration_without_verification: false
Restart Synapse if you changed the config:
docker compose restart synapse
7) Upgrades & maintenance
-
Update Synapse:
docker compose pull synapse && docker compose up -d -
Backups: snapshot/backup the matrix_synapse_data volume regularly.
-
Logs:
docker logs -f synapse
8) Common pitfalls
- Caddy can’t reach synapse: ensure both are on a shared network, or publish port 8008 to the host and update the upstream.
- Wrong domain in SYNAPSE_SERVER_NAME: regenerate config or edit homeserver.yaml to match your public domain exactly.
- Federation issues: confirm /.well-known/matrix/server returns your domain with :443, and that 443 is reachable from the internet.
9) Appendix: Change domain
If you use a different domain, replace every instance of chat.yourdomain.com in this README and commands. Re-run the config generation step (or carefully edit homeserver.yaml) to match the new domain.