{"id":50926020,"url":"https://github.com/junkerderprovinz/matrix","last_synced_at":"2026-06-16T23:02:57.880Z","repository":{"id":356411722,"uuid":"1232381195","full_name":"junkerderprovinz/matrix","owner":"junkerderprovinz","description":"Plug-and-play Matrix homeserver for Unraid: Synapse + coturn + Element Web + Synapse-Admin in one container","archived":false,"fork":false,"pushed_at":"2026-06-03T11:36:09.000Z","size":512,"stargazers_count":5,"open_issues_count":1,"forks_count":1,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-03T12:22:47.655Z","etag":null,"topics":["community-applications","coturn","docker","element","ghcr","homeserver","matrix","self-hosted","synapse","unraid"],"latest_commit_sha":null,"homepage":"https://github.com/junkerderprovinz/matrix","language":"Shell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/junkerderprovinz.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null},"funding":{"buy_me_a_coffee":"junkerderprovinz"}},"created_at":"2026-05-07T21:54:49.000Z","updated_at":"2026-06-03T11:36:13.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/junkerderprovinz/matrix","commit_stats":null,"previous_names":["junkerderprovinz/matrix"],"tags_count":4,"template":false,"template_full_name":null,"purl":"pkg:github/junkerderprovinz/matrix","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/junkerderprovinz%2Fmatrix","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/junkerderprovinz%2Fmatrix/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/junkerderprovinz%2Fmatrix/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/junkerderprovinz%2Fmatrix/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/junkerderprovinz","download_url":"https://codeload.github.com/junkerderprovinz/matrix/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/junkerderprovinz%2Fmatrix/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34426745,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-16T02:00:06.860Z","response_time":126,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["community-applications","coturn","docker","element","ghcr","homeserver","matrix","self-hosted","synapse","unraid"],"created_at":"2026-06-16T23:02:57.005Z","updated_at":"2026-06-16T23:02:57.870Z","avatar_url":"https://github.com/junkerderprovinz.png","language":"Shell","funding_links":["https://buymeacoffee.com/junkerderprovinz"],"categories":[],"sub_categories":[],"readme":"﻿\u003ca href=\"https://matrix.org\"\u003e\n  \u003cimg src=\"https://raw.githubusercontent.com/junkerderprovinz/matrix/main/.github/assets/matrix-banner.png\" alt=\"Matrix\" width=\"100%\"\u003e\n\u003c/a\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://github.com/junkerderprovinz/matrix/actions/workflows/build.yml\"\u003e\u003cimg src=\"https://img.shields.io/github/actions/workflow/status/junkerderprovinz/matrix/build.yml?branch=main\u0026label=Build\u0026style=for-the-badge\u0026logo=githubactions\u0026logoColor=white\" alt=\"Build\" height=\"36\"\u003e\u003c/a\u003e\u0026nbsp;\n  \u003ca href=\"https://github.com/junkerderprovinz/matrix/actions/workflows/lint.yml\"\u003e\u003cimg src=\"https://img.shields.io/github/actions/workflow/status/junkerderprovinz/matrix/lint.yml?branch=main\u0026label=Lint\u0026style=for-the-badge\u0026logo=githubactions\u0026logoColor=white\" alt=\"Lint\" height=\"36\"\u003e\u003c/a\u003e\u0026nbsp;\n  \u003ca href=\"https://hub.docker.com/r/junkerderprovinz/matrix\"\u003e\u003cimg src=\"https://img.shields.io/docker/pulls/junkerderprovinz/matrix?style=for-the-badge\u0026logo=docker\u0026logoColor=white\u0026label=Pulls\u0026color=1d99f3\" alt=\"Docker Pulls\" height=\"36\"\u003e\u003c/a\u003e\u0026nbsp;\n  \u003ca href=\"https://hub.docker.com/r/junkerderprovinz/matrix\"\u003e\u003cimg src=\"https://img.shields.io/docker/image-size/junkerderprovinz/matrix/latest?style=for-the-badge\u0026logo=docker\u0026logoColor=white\u0026label=Size\u0026color=1d99f3\" alt=\"Image Size\" height=\"36\"\u003e\u003c/a\u003e\u0026nbsp;\n  \u003ca href=\"https://github.com/junkerderprovinz/matrix/pkgs/container/matrix\"\u003e\u003cimg src=\"https://img.shields.io/badge/Arch-amd64%20%7C%20arm64-success?style=for-the-badge\u0026logo=linux\u0026logoColor=white\" alt=\"Arch\" height=\"36\"\u003e\u003c/a\u003e\u0026nbsp;\n  \u003ca href=\"https://github.com/element-hq/synapse\"\u003e\u003cimg src=\"https://img.shields.io/badge/Synapse-homeserver-0dbd8b?style=for-the-badge\u0026logo=matrix\u0026logoColor=white\" alt=\"Synapse\" height=\"36\"\u003e\u003c/a\u003e\u0026nbsp;\n  \u003ca href=\"https://element.io\"\u003e\u003cimg src=\"https://img.shields.io/badge/Element-web%20client-0dbd8b?style=for-the-badge\u0026logo=element\u0026logoColor=white\" alt=\"Element\" height=\"36\"\u003e\u003c/a\u003e\u0026nbsp;\n  \u003ca href=\"https://unraid.net\"\u003e\u003cimg src=\"https://img.shields.io/badge/Unraid-Template-f15a2c?style=for-the-badge\u0026logo=unraid\u0026logoColor=white\" alt=\"Unraid\" height=\"36\"\u003e\u003c/a\u003e\u0026nbsp;\n  \u003ca href=\"LICENSE\"\u003e\u003cimg src=\"https://img.shields.io/badge/License-MIT-yellow?style=for-the-badge\u0026logo=opensourceinitiative\u0026logoColor=white\" alt=\"License\" height=\"36\"\u003e\u003c/a\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\nA complete, plug-and-play Docker image for running your own \u003cb\u003eMatrix homeserver\u003c/b\u003e on Unraid.\nNo manual config file editing, no SSH access to the container required —\njust enter your domain and database credentials and the container handles the rest.\n\u003c/p\u003e\n\n\u003cbr\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://buymeacoffee.com/junkerderprovinz\"\u003e\n    \u003cimg src=\".github/assets/button-buy-me-a-coffee.svg\" alt=\"Buy me a coffee\" width=\"220\"\u003e\n  \u003c/a\u003e\n\u003c/p\u003e\n\n\u003cbr\u003e\n\n## ⚠️ Before You Start — Two Things You Must Do\n\nThe container itself is plug-and-play, but two things outside the container must be set up\ncorrectly or Synapse will not work:\n\n**1. Create the PostgreSQL database with the right locale** (UTF8 + `C` collation).\nIn your Postgres container console (`psql -U postgres`):\n\n```sql\nCREATE USER admin WITH PASSWORD 'yoursecretpassword';\nCREATE DATABASE matrix\n    ENCODING 'UTF8' LC_COLLATE='C' LC_CTYPE='C'\n    TEMPLATE template0 OWNER admin;\n```\n\nAny other locale and Synapse refuses to start. Full details in [section 3](#4-setting-up-postgresql).\n\n**2. Add NPM Advanced config** to your `matrix.yourdomain.tld` proxy host.\nNPM → your proxy host → **Edit** → **Advanced** tab → paste this complete block into\n*Custom Nginx Configuration*:\n\n```nginx\n# Matrix media uploads can be large\nclient_max_body_size 100M;\n\n# Long-polling sync needs generous timeouts\nproxy_read_timeout 600s;\nproxy_send_timeout 600s;\n\n# Forward real client IP (matches x_forwarded: true in homeserver.yaml)\nproxy_set_header X-Forwarded-For $remote_addr;\nproxy_set_header X-Forwarded-Proto $scheme;\nproxy_set_header Host $host;\n\n# WebSocket / HTTP-1.1 upgrade for /_matrix/client/*/sync\nproxy_http_version 1.1;\nproxy_set_header Upgrade $http_upgrade;\nproxy_set_header Connection \"upgrade\";\n```\n\nWithout these, media uploads fail and Sync requests time out. Details and the\nfederation `well-known` snippet are in [section 4](#5-npm-configuration-nginx-proxy-manager) and [section 5](#6-enabling-federation).\n\n\u003cbr\u003e\n\n## Table of Contents\n\n1. [What Is This?](#1-what-is-this)\n2. [Screenshots](#2-screenshots)\n3. [Quick Start on Unraid](#3-quick-start-on-unraid)\n4. [Setting Up PostgreSQL](#4-setting-up-postgresql)\n5. [NPM Configuration (Nginx Proxy Manager)](#5-npm-configuration-nginx-proxy-manager)\n6. [Enabling Federation](#6-enabling-federation)\n7. [Monitoring (Prometheus)](#7-monitoring-prometheus)\n8. [Adding Bridges](#8-adding-bridges)\n9. [Creating the First Admin User](#9-creating-the-first-admin-user)\n10. [Generating Registration Tokens](#10-generating-registration-tokens)\n11. [Updates](#11-updates)\n12. [Troubleshooting](#12-troubleshooting)\n13. [Contributing / License](#13-contributing--license)\n14. [Support this project](#14-support-this-project)\n\u003cbr\u003e\n\n## 1. What Is This?\n\nThis image is a **wrapper around the official Synapse image** from Element (`ghcr.io/element-hq/synapse`).\nIt extends bare Synapse with all the components needed for a fully functional\nMatrix homeserver:\n\n| Component | Purpose | Port |\n|---|---|---|\n| **Synapse** | Matrix homeserver (core component) | 8008 |\n| **coturn** | TURN/STUN server for voice and video calls | 3478, 5349 |\n| **Element Web** | Modern Matrix client (web UI) | 8080/element/ |\n| **Synapse-Admin** | Admin interface (users, rooms, tokens) | 8080/admin/ |\n| **lighttpd** | Lightweight web server for Element, Admin, and well-known | 8080 |\n| **Prometheus metrics** | Internal Synapse metrics endpoint | 9090 |\n\n**Why a wrapper instead of building from scratch?**\nThe official Synapse image receives security patches immediately and is tested against every new\nSynapse release. We build *on top of it* rather than alongside it — meaning: always up to date,\nwithout maintaining our own Synapse build pipeline. The GitHub Actions workflow checks for new\nSynapse releases every hour and rebuilds the image automatically.\n\n**PostgreSQL is external** — this image does not include its own database. Synapse requires PostgreSQL\nwith specific locale settings (see section 3), and keeping it external gives you full control over\nbackups, connections, and performance.\n\n\u003cbr\u003e\n\n## 2. Screenshots\n\nElement is the recommended web client for Synapse (separate Unraid template, e.g. LSIO's `element-web`).\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\".github/assets/screenshots/matrix-1.jpg\" alt=\"Element web client — first login on this Synapse server\" width=\"90%\"\u003e\n  \u003cbr\u003e\u003cem\u003eFirst login — Element home view served by your own Synapse homeserver.\u003c/em\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\".github/assets/screenshots/matrix-2.jpg\" alt=\"Element — Create a Space dialog\" width=\"90%\"\u003e\n  \u003cbr\u003e\u003cem\u003ePublic vs. private Spaces — group rooms and people by topic or team.\u003c/em\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\".github/assets/screenshots/matrix-3.jpg\" alt=\"Element — Preferences with language and timezone settings\" width=\"90%\"\u003e\n  \u003cbr\u003e\u003cem\u003ePreferences — application language, room list, Spaces, time format, presence.\u003c/em\u003e\n\u003c/p\u003e\n\n\u003cbr\u003e\n\n## 3. Quick Start on Unraid\n\n### Step 1 — Create the PostgreSQL database\n\nBefore installing the Matrix template, the database must be ready (UTF8 + `LC_COLLATE='C'`).\nSee [section 3](#4-setting-up-postgresql) for the exact SQL — Synapse will not start without it.\n\n### Step 2 — Install the template\n\n**Option A: Community Applications (recommended)**\n\n1. In Unraid, open: **Apps → Community Applications**\n2. Search for `Matrix All-in-One`\n3. Click **Install**\n\n**Option B: Manual template URL**\n\n1. Unraid → **Docker → Add Container**\n2. Click **Template URLs** in the top right\n3. Paste the following URL:\n   ```\n   https://raw.githubusercontent.com/junkerderprovinz/unraid-docker-templates/main/matrix/matrix.xml\n   ```\n4. Click **Save**, then select **Matrix** from the template list\n\n### Step 3 — Fill in the required fields\n\nIn the template form, you must configure the following fields:\n\n| Field | Example value | Note |\n|---|---|---|\n| `SERVER_NAME` | `matrix.yourdomain.tld` | **Can never be changed!** |\n| `POSTGRES_HOST` | `192.168.1.10` | Unraid host IP (see \"Why IP?\" below) |\n| `POSTGRES_USER` | `admin` | Must exist in PostgreSQL |\n| `POSTGRES_PASSWORD` | `yoursecretpassword` | Stored masked |\n| `POSTGRES_DB` | `matrix` | Must exist with correct locale settings |\n\n\u003e **Important:** `SERVER_NAME` is the foundation of your Matrix identity. All user IDs take the form\n\u003e `@username:SERVER_NAME`. This setting **cannot be changed after the first run** without dropping\n\u003e the entire database.\n\n### Step 4 — Start the container and check the logs\n\n1. Click **Apply** → the container starts\n2. In Unraid, open: **Docker → Matrix → Logs**\n3. You should see: `[init] INFO: Container initialization complete. Starting services ...`\n4. After approximately 30–60 seconds, Synapse is ready\n\n### Step 5 — Configure NPM\n\nFollow [section 4](#5-npm-configuration-nginx-proxy-manager) to make Synapse accessible over HTTPS.\n**Don't forget the Advanced tab** — `client_max_body_size 100M;` and `proxy_read_timeout 600s;`\nare required for media uploads and Sync to work.\n\n\u003cbr\u003e\n\n## 4. Setting Up PostgreSQL\n\nSynapse has **strict requirements** for the PostgreSQL database:\n- Encoding: `UTF8`\n- LC_COLLATE: `C`\n- LC_CTYPE: `C`\n\nWithout these exact settings, Synapse will refuse to start with an error such as\n`database encoding is not UTF8` or `collation mismatch`.\n\n### Connecting to the PostgreSQL console\n\n**In Unraid via Docker terminal:**\n\n1. Open **Docker → PostgreSQL15 → Console**\n2. Enter:\n\n```bash\npsql -U postgres\n```\n\n### Creating the user and database\n\nThe SQL below uses `admin` as the database user and `matrix` as the database name —\nthese are the **template defaults** documented here. You are free to choose different\nnames; just make sure the `POSTGRES_USER` and `POSTGRES_DB` fields in the Unraid\ntemplate match whatever values you actually create.\n\n```sql\n-- Create the Synapse database user\n-- (you may use any username; 'admin' is the template default)\nCREATE USER admin WITH PASSWORD 'yoursecretpassword';\n\n-- Create the database with the locale settings required by Synapse\n-- IMPORTANT: use template0, not template1 — only template0 allows\n--            overriding LC_COLLATE and LC_CTYPE\nCREATE DATABASE matrix\n    ENCODING 'UTF8'\n    LC_COLLATE='C'\n    LC_CTYPE='C'\n    TEMPLATE template0\n    OWNER admin;\n\n-- Grant permissions\nGRANT ALL PRIVILEGES ON DATABASE matrix TO admin;\n\n-- Test the connection\n\\c matrix admin\n-- If no error appears: everything is correct\n\\q\n```\n\n### Why IP instead of container name?\n\nBy default, Unraid runs all containers on the standard `bridge` network. On this network,\n**container name resolution does not work** — Docker only resolves container names to IPs\nwhen both containers are on the same *custom* Docker network.\n\nUsing your Unraid host IP + the published PostgreSQL port works on any network type:\n\n```\nPOSTGRES_HOST = 192.168.1.10\nPOSTGRES_PORT = 5432\n```\n\nThis avoids \"connection refused\" errors that often happen when using the container name\n(`PostgreSQL15`) on the default bridge network.\n\n**If you prefer container names:** create a custom Docker network in Unraid\n(*Settings → Docker → IPv4 custom network subnet* → enable), start both containers on it,\nand set `POSTGRES_HOST` to the PostgreSQL container name.\n\n\u003cbr\u003e\n\n## 5. NPM Configuration (Nginx Proxy Manager)\n\nMatrix clients require HTTPS. The Matrix container itself does not handle TLS —\nthat is delegated to Nginx Proxy Manager as the reverse proxy.\n\nYou need **two proxy hosts** in NPM:\n\n### 4.1 Proxy host: Matrix API (matrix.yourdomain.tld)\n\n**NPM → Hosts → Add Proxy Host**\n\n| Field | Value |\n|---|---|\n| Domain Names | `matrix.yourdomain.tld` |\n| Scheme | `http` |\n| Forward Hostname/IP | `192.168.1.10` (your Unraid host IP) |\n| Forward Port | `8008` |\n| Websockets Support | **enabled** |\n| Block Common Exploits | enabled |\n\n\u003e **Why IP instead of container name?**  \n\u003e Container names only resolve inside custom Docker networks. Using `192.168.1.10:8008`\n\u003e (Unraid host IP + published container port) works reliably on bridge networks too.\n\n**SSL tab:** Issue a Let's Encrypt certificate → enable Force SSL\n\n**Custom Nginx configuration** (Advanced tab) — paste as one block:\n\n```nginx\n# Matrix media uploads can be large\nclient_max_body_size 100M;\n\n# Long-polling sync needs generous timeouts\nproxy_read_timeout 600s;\nproxy_send_timeout 600s;\n\n# Forward real client IP (matches x_forwarded: true in homeserver.yaml)\nproxy_set_header X-Forwarded-For $remote_addr;\nproxy_set_header X-Forwarded-Proto $scheme;\nproxy_set_header Host $host;\n\n# WebSocket / HTTP-1.1 upgrade for /_matrix/client/*/sync\nproxy_http_version 1.1;\nproxy_set_header Upgrade $http_upgrade;\nproxy_set_header Connection \"upgrade\";\n```\n\n### 4.2 Proxy host: Element Web + Admin (optional custom domain)\n\nIf you want Element Web accessible under its own domain (e.g. `element.yourdomain.tld`):\n\n| Field | Value |\n|---|---|\n| Domain Names | `element.yourdomain.tld` |\n| Scheme | `http` |\n| Forward Hostname/IP | `192.168.1.10` (your Unraid host IP) |\n| Forward Port | `8080` |\n\nElement is then available at `https://element.yourdomain.tld/element/`.\n\n\u003cbr\u003e\n\n## 6. Enabling Federation\n\nMatrix federation lets your users chat with people on other Matrix servers\n(like `@user:matrix.org`). It is **enabled by default** and controlled by the\n`Enable Federation` template variable. Set it to `false` if you want to run\na private island server instead.\n\nFor federation to work, other servers must be able to discover where your\nSynapse runs. This is done via two well-known JSON endpoints that the\ncontainer hosts automatically:\n\n- `/.well-known/matrix/server` — tells other Matrix servers where to reach you\n- `/.well-known/matrix/client` — tells Matrix clients which homeserver to use\n\nBoth files are generated on every container start from your `SERVER_NAME` and\nserved by the built-in lighttpd on port 8080 — you do not need to write any\nJSON yourself.\n\n### Reverse-proxy setup (one host, no second proxy needed)\n\nYou only need **one proxy host** in NPM — the same one that already proxies\nSynapse on `matrix.yourdomain.tld`. Add two custom locations to it:\n\n**NPM → `matrix.yourdomain.tld` proxy host → Edit → Custom locations tab:**\n\n| Location | Forward Scheme | Forward Host/IP | Forward Port |\n|---|---|---|---|\n| `/.well-known/matrix/server` | `http` | *Unraid IP* | `8080` |\n| `/.well-known/matrix/client` | `http` | *Unraid IP* | `8080` |\n\nThat's it. Save and reload NPM.\n\n#### Alternative: paste this into Advanced → Custom Nginx Configuration\n\nIf you prefer a single block of config instead of two custom-location entries,\npaste this into the `Advanced → Custom Nginx Configuration` field of the\n`matrix.yourdomain.tld` proxy host (replace `192.168.1.10` with your Unraid IP):\n\n```nginx\nlocation /.well-known/matrix/server {\n    proxy_pass http://192.168.1.10:8080/.well-known/matrix/server;\n    proxy_set_header Host $host;\n}\n\nlocation /.well-known/matrix/client {\n    proxy_pass http://192.168.1.10:8080/.well-known/matrix/client;\n    proxy_set_header Host $host;\n}\n```\n\n### Verifying\n\nAfter saving the proxy host, test the endpoints:\n\n```bash\ncurl -s https://matrix.yourdomain.tld/.well-known/matrix/server\n# expected: {\"m.server\": \"matrix.yourdomain.tld:443\"}\n\ncurl -s https://matrix.yourdomain.tld/.well-known/matrix/client\n# expected: {\"m.homeserver\": {\"base_url\": \"https://matrix.yourdomain.tld\"}}\n```\n\nThen run the federation tester:\n\n[https://federationtester.matrix.org/](https://federationtester.matrix.org/)\n\nEnter `matrix.yourdomain.tld`. All checks should be green and `FederationOK: true`.\n\n**Common errors:**\n\n- `No .well-known found` → the two custom locations above are not active yet\n- `context deadline exceeded` on port 8448 → normal when well-known points to\n  port 443; the tester just falls back to direct 8448. Once well-known is set up,\n  this error becomes irrelevant\n- `Certificate error` → SSL certificate not valid for the domain\n\n\u003cbr\u003e\n\n## 7. Monitoring (Prometheus)\n\nThe container exposes Synapse's internal **Prometheus metrics** on port **9090**, bound to\n`0.0.0.0` so Prometheus can reach them from the host network.\n\n- **Port:** `9090`\n- **Path:** `/_synapse/metrics`\n- **Bind:** `0.0.0.0` (all interfaces)\n\n\u003e Keep port 9090 on a private network — these metrics expose detailed internal Synapse state\n\u003e and should not be publicly accessible.\n\n### Prometheus scrape_config example\n\nAdd this to your `prometheus.yml`:\n\n```yaml\nscrape_configs:\n  - job_name: 'synapse'\n    metrics_path: /_synapse/metrics\n    static_configs:\n      - targets: ['192.168.1.10:9090']\n        labels:\n          instance: 'matrix.yourdomain.tld'\n```\n\n### Grafana dashboard\n\nThe Synapse project maintains an official Grafana dashboard at:\n[https://github.com/element-hq/synapse/tree/develop/contrib/grafana](https://github.com/element-hq/synapse/tree/develop/contrib/grafana)\n\nImport the JSON dashboard into Grafana and point it at your Prometheus datasource to get\na full view of federation lag, event processing rates, cache hit ratios, and more.\n\n\u003cbr\u003e\n\n## 8. Adding Bridges\n\n**Bridges** connect your Matrix homeserver to other messaging platforms — WhatsApp, Telegram,\nSignal, Discord, iMessage, and more. They appear as bots in your Matrix rooms and relay\nmessages transparently between networks.\n\n### Bridges are not bundled in this image\n\nThis image deliberately does not include any bridges. Keeping the core image focused on\nSynapse, coturn, and the web UIs ensures a smaller attack surface and simpler upgrades.\nEach bridge has its own release cycle and dependencies that are better managed separately.\n\n### Recommended approach: mautrix bridges as separate containers\n\nThe [mautrix bridge collection](https://docs.mau.fi/bridges/) is the most actively maintained\nset of Matrix bridges and covers WhatsApp, Telegram, Signal, Discord, Meta (Instagram/Facebook),\nGoogle Chat, and more. Run each bridge as its own Docker container alongside this one.\n\n**General workflow:**\n\n1. Run the bridge container once to generate its `config.yaml`\n2. Edit `config.yaml` to point at your Synapse homeserver URL and PostgreSQL database\n3. Run the bridge with `--generate-registration` to produce a `registration.yaml` file\n4. Copy `registration.yaml` into `/data/appservices/` inside the Matrix container\n5. Restart the Matrix container — Synapse will automatically load all `.yaml` files from\n   `/data/appservices/` at startup\n\nThe `/data/appservices/` directory on your Unraid host maps to\n`/mnt/user/appdata/matrix/appservices/`. Create it manually if it does not yet exist.\n\n### Bridge documentation\n\nFull installation guides for every supported platform:\n**[https://docs.mau.fi/bridges/](https://docs.mau.fi/bridges/)**\n\n\u003cbr\u003e\n\n## 9. Creating the First Admin User\n\nAfter the first run there are no users yet. Since open registration is disabled,\nthe first admin user must be created. There are two ways to do this.\n\n### Method 1: Auto-create via template variables (recommended)\n\nThe template ships with two optional environment variables:\n\n| Variable         | Description                                      |\n| ---------------- | ------------------------------------------------ |\n| `ADMIN_USER`     | Localpart of the admin account, e.g. `admin`     |\n| `ADMIN_PASSWORD` | Password for the auto-created admin account      |\n\n1. Edit the Matrix container in Unraid\n2. Set `ADMIN_USER` and `ADMIN_PASSWORD`\n3. Apply — the container restarts and creates the admin user automatically\n\nOn the next boot, after Synapse is ready, the bootstrap service registers the\nuser as an admin and writes a marker file (`/data/.admin_created`) so the\noperation is never repeated. **You can safely clear both variables afterwards.**\n\nThe resulting Matrix ID is `@\u003cADMIN_USER\u003e:\u003cSERVER_NAME\u003e`, e.g. `@admin:matrix.yourdomain.tld`.\n\n### Method 2: Manually via the Unraid container console\n\n1. Unraid → **Docker → Matrix → Console**\n2. Run the following command (replace the placeholder values):\n\n```bash\nregister_new_matrix_user \\\n  -c /data/homeserver.yaml \\\n  -u YOUR_USERNAME \\\n  -p YOUR_PASSWORD \\\n  --admin \\\n  http://localhost:8008\n```\n\nYou will be prompted for a username, password, and admin status interactively if you omit the\n`-u` and `-p` flags.\n\n\u003e **Security note:** The password is stored in the shell history when passed as a flag. For\n\u003e production use, omit the flags and enter credentials interactively.\n\n### Signing in\n\nOpen `http://UNRAID-IP:8080/element/` in your browser.\n\n1. Click **Sign In**\n2. Click **Edit** next to the homeserver\n3. Enter `https://matrix.yourdomain.tld`\n4. Sign in with your username and password\n\n\u003cbr\u003e\n\n## 10. Generating Registration Tokens\n\nRegistration tokens let you invite specific users to register without enabling open registration\nfor everyone.\n\n### Method 1: Synapse-Admin (recommended)\n\n1. Open `http://UNRAID-IP:8080/admin/`\n2. Sign in with the admin user\n3. **Registration Tokens → Create Token**\n4. Configure: maximum uses, expiry date\n5. Copy the token and share it with the invited user\n\n### Method 2: Admin API (curl)\n\n```bash\n# First, obtain an access token for the admin user:\ncurl -XPOST \\\n  'https://matrix.yourdomain.tld/_matrix/client/v3/login' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\"type\":\"m.login.password\",\"user\":\"ADMIN_USER\",\"password\":\"ADMIN_PASSWORD\"}'\n\n# Copy the token from the response, then:\ncurl -XPOST \\\n  'https://matrix.yourdomain.tld/_synapse/admin/v1/registration_tokens/new' \\\n  -H 'Authorization: Bearer YOUR_ACCESS_TOKEN' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\"uses_allowed\": 1}'\n```\n\n### Enabling token-based registration\n\nFor users to register with a token, the following must be set in `/data/homeserver.yaml`\n(or in `/data/homeserver-overrides.yaml`):\n\n```yaml\nenable_registration: true\nregistration_requires_token: true\n```\n\nThen restart the container: **Docker → Matrix → Restart**\n\n\u003cbr\u003e\n\n## 11. Updates\n\n### Automatic image updates (GitHub Actions)\n\nThe GitHub Actions workflow checks **every hour** for a new Synapse release.\nWhen one is found, the image is automatically rebuilt for `linux/amd64` and `linux/arm64`\nand pushed to `junkerderprovinz/matrix` on Docker Hub (mirrored to `ghcr.io/junkerderprovinz/matrix`).\n\n### Updating the container on Unraid\n\n1. Unraid → **Docker → Matrix**\n2. Click the container icon → **Update available** appears when a new version is out\n3. Click **Update** → Unraid pulls the new image and restarts the container\n\n**Or use Unraid's bulk update:** Unraid → **Docker → Update All Containers**\n\n\u003e Updates do not affect data in `/data` — your homeserver.yaml, media files, and signing keys\n\u003e are preserved. Synapse database migrations run automatically on startup.\n\n\u003cbr\u003e\n\n## 12. Troubleshooting\n\n### Error: \"database encoding is not UTF8\" or \"LC_COLLATE mismatch\"\n\n**Cause:** The PostgreSQL database was created without the correct locale settings.\n\n**Fix:**\n```sql\n-- Drop and recreate the database (data loss!)\nDROP DATABASE matrix;\nCREATE DATABASE matrix\n    OWNER admin\n    ENCODING 'UTF8'\n    LC_COLLATE='C'\n    LC_CTYPE='C'\n    TEMPLATE template0;\nGRANT ALL PRIVILEGES ON DATABASE matrix TO admin;\n```\n\n### Error: \"Permission denied\" on /data\n\n**Cause:** Files in `/mnt/user/appdata/matrix/` are owned by a different user than `PUID:PGID`.\n\n**Fix in the Unraid terminal:**\n```bash\nchown -R 99:100 /mnt/user/appdata/matrix/\n```\n\n### Error: Container won't start — \"SERVER_NAME not set\"\n\n**Cause:** The `SERVER_NAME` environment variable is empty or missing in the template.\n\n**Fix:** Unraid → **Docker → Matrix → Edit** → fill in `SERVER_NAME` → Apply\n\n### Error: \"Connection refused\" to PostgreSQL\n\n**Cause:** The Matrix container cannot reach the PostgreSQL container.\n\n**Checklist:**\n1. Is the PostgreSQL container running? → Check the Unraid Docker tab\n2. Correct `POSTGRES_HOST`? → Use the Unraid host IP (e.g. `192.168.1.10`) instead of a container name\n3. Correct `POSTGRES_PORT`? → Default is `5432`\n4. Is PostgreSQL listening on `0.0.0.0`? → In PostgreSQL: `listen_addresses = '*'` in `postgresql.conf`\n5. Does `pg_hba.conf` allow connections from the Matrix container?\n\n### Federation test failing\n\n**Common causes:**\n\n| Error | Cause | Fix |\n|---|---|---|\n| `No SRV or well-known` | well-known missing | Follow section 5 |\n| `TLS certificate error` | Certificate invalid | Renew SSL certificate in NPM |\n| `Connection timeout` | Port 443/8448 blocked | Check router port forwarding |\n| `Invalid JSON` | well-known config malformed | Restart container to re-render well-known files |\n\n### Viewing logs\n\n**In Unraid:**\n- Docker → Matrix → icon → Logs\n\n**Via terminal:**\n```bash\ndocker logs matrix --follow --tail 100\n```\n\n**Synapse's own logs** (if configured in /data/logs/):\n```bash\ntail -f /mnt/user/appdata/matrix/logs/homeserver.log\n```\n\n### TURN/video calls not working\n\n1. Open ports 3478 (TCP+UDP) in your router and forward them to the Unraid IP\n2. Verify that `turn_uris` is correctly set in `homeserver.yaml` (this happens automatically)\n3. The TURN shared secret in `homeserver.yaml` and `turnserver.conf` must match\n   (both are populated from `/data/.turn_secret` — check container logs if there are issues)\n4. `denied-peer-ip` in `turnserver.conf` blocks private IP ranges — this may affect LAN testing\n   but is not relevant for calls over the internet\n\n#### TURN over TLS (optional)\n\nTo enable TURN over TLS on port 5349, mount a directory containing `fullchain.pem` and\n`privkey.pem` to `/data/certs/` inside the container. The filenames must be exactly:\n\n- `/data/certs/fullchain.pem`\n- `/data/certs/privkey.pem`\n\n**Tip:** NPM stores Let's Encrypt certificates in\n`/mnt/user/appdata/NginxProxyManager/letsencrypt/live/npm-X/`. You can symlink or copy them:\n\n```bash\nmkdir -p /mnt/user/appdata/matrix/certs\ncp /mnt/user/appdata/NginxProxyManager/letsencrypt/live/npm-1/fullchain.pem \\\n   /mnt/user/appdata/matrix/certs/fullchain.pem\ncp /mnt/user/appdata/NginxProxyManager/letsencrypt/live/npm-1/privkey.pem \\\n   /mnt/user/appdata/matrix/certs/privkey.pem\n```\n\nThen set the **TURN-TLS Certs** path in the Unraid template to `/mnt/user/appdata/matrix/certs`\n(mapped to `/data/certs` inside the container). If the cert files are missing, plain TURN on\nport 3478 still works — TLS is entirely optional.\n\n\u003cbr\u003e\n\n## 13. Contributing / License\n\n### Issues \u0026 feature requests\n\nFound a bug? Have a feature request? → [GitHub Issues](https://github.com/junkerderprovinz/matrix/issues)\n\n### Pull requests\n\nPRs are welcome. Please:\n1. Fork the repository\n2. Create a feature branch (`git checkout -b feature/my-feature`)\n3. Run shellcheck and hadolint locally (or rely on the lint workflow)\n4. Open a PR against `main`\n\n### License\n\nApache 2.0 — see [LICENSE](LICENSE)\n\nThis project is not officially affiliated with Element HQ, the Matrix Foundation, or\nthe Element project. Synapse, Element, and coturn are their respective\ntrademarks/projects and are used here unmodified as base images / packages.\n\n*Built with care for the Unraid community.*\n\n\u003cbr\u003e\n\n## 14. Support this project\n\nIf this template saves you a setup hassle or a debug night, consider buying me a coffee:\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://buymeacoffee.com/junkerderprovinz\"\u003e\n    \u003cimg src=\".github/assets/button-buy-me-a-coffee.svg\" alt=\"Buy me a coffee\" width=\"220\"\u003e\n  \u003c/a\u003e\n\u003c/p\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjunkerderprovinz%2Fmatrix","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjunkerderprovinz%2Fmatrix","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjunkerderprovinz%2Fmatrix/lists"}