From 19fc04a4e0197ab3eb6080e43a7cc7f7470db60c Mon Sep 17 00:00:00 2001 From: Koree Smith Date: Mon, 6 Apr 2026 20:29:03 -0500 Subject: [PATCH] Updated README.md. --- README.md | 269 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 269 insertions(+) diff --git a/README.md b/README.md index e69de29..97f7dee 100644 --- a/README.md +++ b/README.md @@ -0,0 +1,269 @@ +# Matrix / Element Self-Hosted Server + +A Docker Compose setup for running a self-hosted [Matrix](https://matrix.org/) homeserver (Synapse) with the [Element Web](https://element.io/) client and a Synapse admin panel. + +## What's included + +| Service | Image | Default Port | Purpose | +|---|---|---|---| +| **Synapse** | `matrixdotorg/synapse:latest` | `8008` | Matrix homeserver | +| **Element Web** | `vectorim/element-web:latest` | `8080` | Web chat client | +| **Synapse Admin** | `awesometechnologies/synapse-admin:latest` | `8081` | Admin UI | +| **PostgreSQL** | `postgres:14` | `5432` | Database for Synapse | + +--- + +## Prerequisites + +- [Docker](https://docs.docker.com/get-docker/) and [Docker Compose](https://docs.docker.com/compose/install/) +- A domain name pointed at your server (e.g. `chat.example.com`) +- A reverse proxy (nginx, Caddy, Traefik, etc.) to handle TLS termination — the containers themselves do not manage HTTPS + +--- + +## Setup + +### 1. Clone the repository + +```bash +git clone +cd matrix +``` + +### 2. Configure environment variables + +Copy the example env file and edit it: + +```bash +cp .env.example .env +``` + +Open `.env` and set each value: + +```dotenv +# PostgreSQL +POSTGRES_DB=synapse +POSTGRES_USER=synapse +POSTGRES_PASSWORD= + +# Synapse — must match your public domain +SYNAPSE_SERVER_NAME=chat.example.com + +# Synapse Admin UI +REACT_APP_SERVER=https://chat.example.com +REACT_APP_REGISTRATION_ENABLED=false # set to true only if you want open registration +``` + +> **Security note:** Use a strong, unique password for `POSTGRES_PASSWORD`. Never commit `.env` to version control — it is already in `.gitignore`. + +### 3. Generate the Synapse configuration + +Synapse needs a `homeserver.yaml` generated before it can start. Run this once: + +```bash +docker run --rm \ + -e SYNAPSE_SERVER_NAME=chat.example.com \ + -e SYNAPSE_REPORT_STATS=yes \ + -v "$(pwd)/synapse-data:/data" \ + matrixdotorg/synapse:latest generate +``` + +Replace `chat.example.com` with your actual domain. This creates `synapse-data/homeserver.yaml`. + +### 4. Point Synapse at PostgreSQL + +Open `synapse-data/homeserver.yaml` and replace the default SQLite database block with: + +```yaml +database: + name: psycopg2 + args: + user: synapse + password: + database: synapse + host: postgres + cp_min: 5 + cp_max: 10 +``` + +Use the same credentials you set in `.env`. + +### 5. Configure the Element Web client + +Copy the example config and edit it: + +```bash +cp element-config.json.example element-config.json +``` + +Update every occurrence of `chat.example.com` to your domain: + +```json +{ + "default_server_config": { + "m.homeserver": { + "base_url": "https://chat.example.com", + "server_name": "chat.example.com" + } + }, + "disable_custom_urls": true, + "brand": "My Matrix Server", + "showLabsSettings": true, + "voip": { + "stun_servers": [ + { "urls": ["stun:turn.example.com:3478"] } + ], + "turn_servers": [ + { + "urls": [ + "turn:turn.example.com:3478?transport=udp", + "turn:turn.example.com:3478?transport=tcp", + "turns:turn.example.com:5349?transport=tcp" + ], + "secret": "", + "expiry": 86400000 + } + ] + } +} +``` + +If you do not have a TURN server, remove the `voip` and `webrtc` blocks entirely. Voice/video calls on the same local network will still work without them. + +### 6. Start the stack + +```bash +docker compose up -d +``` + +Verify all containers are running: + +```bash +docker compose ps +``` + +Check Synapse logs for errors: + +```bash +docker compose logs -f synapse +``` + +### 7. Create your first admin user + +Once Synapse is running, register an admin account: + +```bash +docker compose exec synapse register_new_matrix_user \ + -c /data/homeserver.yaml \ + -u \ + -p \ + -a \ + http://localhost:8008 +``` + +The `-a` flag grants admin privileges. You can omit it for regular users. + +--- + +## Reverse proxy / TLS + +The containers expose plain HTTP. You must front them with a reverse proxy that terminates TLS. A minimal **nginx** example: + +```nginx +server { + listen 443 ssl; + server_name chat.example.com; + + ssl_certificate /etc/letsencrypt/live/chat.example.com/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/chat.example.com/privkey.pem; + + # Element Web + location / { + proxy_pass http://127.0.0.1:8080; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + } + + # Synapse Matrix API and federation + location /_matrix { + proxy_pass http://127.0.0.1:8008; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + client_max_body_size 50M; + } + + location /_synapse { + proxy_pass http://127.0.0.1:8008; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + } +} +``` + +For automatic TLS with Let's Encrypt, use [Certbot](https://certbot.eff.org/) or [Caddy](https://caddyserver.com/). + +### Matrix federation (optional) + +If you want other Matrix homeservers to be able to communicate with yours, port `8448` must be reachable publicly. You can either: + +- Add a second `server { listen 8448 ssl; ... }` block that proxies to `http://127.0.0.1:8008`, or +- Add a `.well-known/matrix/server` file served from your domain pointing federation to port 443 + +--- + +## Accessing the services + +| URL | Service | +|---|---| +| `https://chat.example.com` | Element Web client | +| `https://chat.example.com:8081` | Synapse Admin panel | +| `https://chat.example.com/_matrix` | Matrix homeserver API | + +Log into the admin panel at port `8081` using the admin credentials you created in step 7. + +--- + +## Data persistence + +All persistent data is stored in local directories that are bind-mounted into the containers: + +| Directory | Contents | +|---|---| +| `postgres-data/` | PostgreSQL database files | +| `synapse-data/` | Synapse config, media uploads, signing keys | + +Both directories are excluded from git via `.gitignore`. **Back them up regularly.** + +--- + +## Upgrading + +Pull the latest images and recreate the containers: + +```bash +docker compose pull +docker compose up -d +``` + +Check the [Synapse changelog](https://github.com/element-hq/synapse/blob/master/CHANGES.md) before upgrading major versions — some releases require manual migration steps. + +--- + +## Troubleshooting + +**Synapse fails to start with a database error** +Make sure the credentials in `synapse-data/homeserver.yaml` match those in `.env`, and that the `postgres` service is fully healthy before Synapse starts. You can force the order with: +```bash +docker compose up -d postgres +# wait a few seconds, then: +docker compose up -d synapse element-web element-admin +``` + +**Element Web shows "Homeserver is not reachable"** +Verify that `base_url` in `element-config.json` uses `https://` and points to the domain your reverse proxy serves (not `localhost`). + +**"M_FORBIDDEN" when registering users** +Open registration is disabled by default. Either use the `register_new_matrix_user` command (step 7) or set `enable_registration: true` in `homeserver.yaml` and restart Synapse. + +**Port conflicts** +If any default port is already in use on your host, change the left side of the port mapping in `docker-compose.yml` (e.g. `"8082:80"` for Element Web) and update your reverse proxy accordingly.