# How to build your own [matrix] server
[matrix] is an open protocol, not a product. Nobody owns it — not even us. Kubínska Scéna
runs on exactly the same software you can install yourself, on your own machine,
for free. This is a short, honest guide to doing it. None of it is a secret.
If you ever leave the Scene, your accounts and rooms on another server keep working — [matrix]
is not a walled garden. That is the whole point of an open protocol.
## What you’ll need
- A server with a public IP address (the cheapest VPS will do, about €5 a month — Hetzner, DigitalOcean,
OVH, or even an old computer at home that’s reachable from the internet)
- Your own domain (e.g. `your-server.com`)
- Docker and Docker Compose installed on the server
- 20 minutes, and some patience the first time you start it up
## 1. DNS
Point the domain (or a subdomain, e.g. `matrix.your-domain.com`) at the server’s IP address
with an A record. Check it:
```bash
dig +short matrix.your-domain.com
```
## 2. Docker Compose
Create a folder and put a `docker-compose.yml` in it:
```yaml
services:
postgres:
image: postgres:16-alpine
restart: unless-stopped
environment:
POSTGRES_USER: synapse
POSTGRES_PASSWORD: change_this_password
POSTGRES_DB: synapse
POSTGRES_INITDB_ARGS: "--encoding=UTF-8 --lc-collate=C --lc-ctype=C"
volumes:
- ./data/postgres:/var/lib/postgresql/data
synapse:
image: matrixdotorg/synapse:latest
restart: unless-stopped
depends_on: [postgres]
environment:
SYNAPSE_SERVER_NAME: your-domain.com
SYNAPSE_REPORT_STATS: "no"
volumes:
- ./synapse:/data
ports:
- "127.0.0.1:8008:8008"
caddy:
image: caddy:2-alpine
restart: unless-stopped
ports:
- "80:80"
- "443:443"
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile
- ./caddy-data:/data
```
## 3. Generate the basic configuration
```bash
docker run -it --rm \
-v "$(pwd)/synapse:/data" \
-e SYNAPSE_SERVER_NAME=your-domain.com \
-e SYNAPSE_REPORT_STATS=no \
matrixdotorg/synapse:latest generate
```
This command creates `homeserver.yaml` and a signing key in the `synapse/` folder.
In `homeserver.yaml`, switch the database connection to Postgres (by default it uses
the simpler SQLite, which isn’t enough for production):
```yaml
database:
name: psycopg2
args:
user: synapse
password: change_this_password
database: synapse
host: postgres
cp_min: 5
cp_max: 10
```
## 4. Reverse proxy with automatic TLS
`Caddyfile`:
```
your-domain.com {
reverse_proxy /_matrix/* synapse:8008
reverse_proxy /_synapse/client/* synapse:8008
}
```
Caddy gets its own certificate from Let’s Encrypt — no manual work with TLS.
## 5. Start it
```bash
docker compose up -d
```
## 6. Check federation (optional)
If you want your server to talk to other [matrix] servers (federation),
check your setup at . If you want a closed
server — exactly like Kubínska Scéna — switch federation off in `homeserver.yaml`:
```yaml
federation_domain_whitelist: []
```
## 7. Create your first account
```bash
docker exec -it -synapse-1 register_new_matrix_user \
-c /data/homeserver.yaml http://localhost:8008
```
## 8. Connect
Download [Element](https://element.io/download) (or FluffyChat, Cinny — you choose
the client), and when you sign in, enter your own domain as the server, not matrix.org.
## Backups
The database is backed up like any other Postgres:
```bash
docker exec -postgres-1 pg_dump -U synapse synapse | gzip > backup.sql.gz
```
Set it up as a daily cron job. Don’t forget to back up the `synapse/` folder too (it holds
the server’s signing key — without it, the server loses its identity).
---
This is exactly the same software, and essentially the same procedure, that Kubínska
Scéna runs on. No secret sauce. If you want to know more, the official Synapse documentation is at
.
*Kubínska Scéna, [matrix].kubinska-scena.life*
*This is an English translation of the Slovak guide `/matrix/navod-vlastny-matrix-server.md`.*