Aufwendiger als gedacht, Matrix Server Einrichtung Docker — Mit Messenger LINE Anbindung, weitere Messenger sind möglich.
Warum Matrix ?!
Der Matrix-Messenger ist ein eigenständiges, verschlüsseltes System. Die Nachrichten liegen auf dem eigenen Server (dem von dir verwendeten Server), sofern sie direkt über Matrix verschickt werden.
Werden Nachrichten hingegen über Bridges erstellt – wie beispielsweise für LINE, WhatsApp, Telegram, den Facebook Messenger oder Signal –, verbleiben die Daten auf den entsprechenden Servern der jeweiligen Konzerne. Sie unterliegen damit deren Kontrolle, Zensur und den jeweiligen gesetzlichen Richtlinien.
So haben beispielsweise EU-Regulierungen weltweite Auswirkungen und Einschränkungen auf die Infrastruktur außerhalb der EU zur Folge. In den USA laufen bereits juristische Klagen, da diese Vorgaben die Meinungsfreiheit der US-Bürger einschränken und somit im Widerspruch zu amerikanischen Gesetzen stehen (wobei die USA hier nur als Beispiel dienen).
Wenn also deine gesamte Familie Nachrichten unkontrolliert über deinen eigenen Matrix-Server austauscht, genießt ihr die volle Privatsphäre. Matrix fungiert dabei als universeller Messenger: Du kannst Dienste wie LINE oder WhatsApp über Bridges einbinden und diese direkt im Matrix-Messenger nutzen. (Der Datenschutz bei WhatsApp und Co. obliegt natürlich weiterhin den jeweiligen Konzernen, aber du kannst die entsprechenden Apps von deinem Gerät löschen 😁)
Video: Matrix Server Einrichtung Docker
Sprache: 🇩🇪|🇬🇧
☝️ Benutze YouTube Untertitel für alle Sprachen.
Hinweis:
Dieses Tutorial behandelt ausschließlich die Installation des Matrix-Servers, einer Web-Oberfläche sowie einer ersten Bridge zum Messenger LINE.
Audio- und Videotelefonie, Zwei-Faktor-Authentifizierung (2FA), Backups und weitere Bridges werden in nachfolgenden Videos behandelt. Der Sinn dieses Beitrags ist es in erster Linie, das Matrix-System fehlerfrei und einsatzbereit ans Laufen zu bekommen. Erweiterungen sind danach jederzeit möglich.
Selbstgehosteter Matrix-Server mit LINE-Anbindung — ein Docker-Setup fürs echte Leben
Ich wollte einen eigenen Matrix-Homeserver betreiben, gebündelt mit Element Web als Client und einer Bridge, die meine LINE-Kontakte automatisch in Matrix-Räume spiegelt. Klang nach einem netten Sonntagnachmittag-Projekt. Es wurde deutlich mehr. In diesem Beitrag zeige ich das fertige, produktionstaugliche Docker-Setup — und, mindestens genauso wichtig, die komplette Liste der Fehler, über die ich gestolpert bin, damit ihr sie nicht wiederholen müsst. Es waren einige.
Das Setup läuft mit Docker Compose und ist AMD64-kompatibel — alle verwendeten Images (Postgres, Synapse, Element Web, Coturn, sowie die Go/Alpine-Basis-Images für den Bridge-Build) sind Multi-Arch-Images. Docker zieht automatisch die zur Host-Architektur passende Variante, ihr müsst an der docker-compose.yml nichts anpassen, egal ob euer Server ARM64 oder AMD64 ist.
Alle Geheimnisse und Einstellungen (Domain, Passwörter, TURN-Zugangsdaten) liegen zentral in einer .env-Datei — und fließen von dort auch tatsächlich automatisch in die laufenden Configs ein.
Architektur
| Komponente | Zweck |
| PostgreSQL | Datenbank — zwei getrennte Datenbanken: eine für Synapse, eine für die Bridge |
| Synapse | Matrix-Homeserver |
| Element Web | Web-Client |
| Coturn | STUN/TURN-Server für Sprach-/Videoanrufe |
| LINE-Bridge (beeper/line) | Spiegelt LINE-Konten als Matrix-Räume |
Alle Platzhalter in diesem Beitrag (matrix.example.com, Passwörter, IPs) sind anonymisiert — ersetzt sie durch eure eigenen Werte.
Ports & Protokolle — was am Router/Firewall freigegeben werden muss
| Port | Protokoll | Wofür | Muss von außen erreichbar sein? |
| 443 | TCP | Reverse Proxy/Tunnel → Element Web + Synapse Client-API (HTTPS) | Ja, zwingend |
| 8448 | TCP | Synapse Federation-API (falls andere Matrix-Server föderieren sollen) | Nur bei Federation |
| 3478 | UDP + TCP | Coturn STUN/TURN — Verbindungsaufbau für Anrufe | Ja, für Sprach-/Videoanrufe |
| 5349 | UDP + TCP | Coturn STUN/TURN über TLS | Empfohlen, für Sprach-/Videoanrufe |
| 49152–49172 | UDP | Coturn Relay-Portbereich — der eigentliche Medienstrom bei Anrufen | Ja, für Sprach-/Videoanrufe |
Intern (nur zwischen Containern) werden zusätzlich 8008 (Synapse Client-API) und 29322 (LINE-Bridge Appservice) verwendet — die dürfen und sollen nicht von außen erreichbar sein.
443 reicht für reines Chatten. Ohne die Coturn-Ports (3478, 5349, 49152–49172) funktionieren Sprach- und Videoanrufe zwischen Nutzern hinter unterschiedlichem NAT nicht zuverlässig.
Ein Wort zum Mount-Design
Der größte Zeitfresser war ein einziges, unscheinbares Docker-Verhalten: Wenn eine als Bind-Mount angegebene Datei auf dem Host noch nicht existiert, legt Docker automatisch ein leeres Verzeichnis mit diesem Namen an. Bei Dateien, die Container selbst zur Laufzeit erzeugen (homeserver.yaml, config.yaml, registration.yaml), führt das reproduzierbar zu is a directory-Fehlern.
Die Lösung: nur noch Verzeichnis-zu-Verzeichnis-Mounts für alles, was dynamisch generiert wird. setup.sh legt deshalb alle benötigten Verzeichnisse (synapse/, postgres_data/, line-bridge/data/) selbst vorher an — noch bevor irgendein Container sie anfassen könnte. Die einzige Ausnahme ist die statische Element-Konfiguration, die per eigenem Dockerfile fest ins Image kopiert wird.
docker-compose.yml
networks:
matrix-net:
driver: bridge
services:
postgres:
image: postgres:16-alpine
container_name: matrix-postgres
restart: unless-stopped
networks:
- matrix-net
environment:
POSTGRES_USER: ${POSTGRES_USER:-synapse}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
POSTGRES_DB: ${POSTGRES_DB:-synapse}
POSTGRES_INITDB_ARGS: "--encoding=UTF-8 --lc-collate=C --lc-ctype=C"
volumes:
- ./postgres_data:/var/lib/postgresql/data
- ./postgres-init:/docker-entrypoint-initdb.d:ro
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-synapse}"]
interval: 10s
timeout: 5s
retries: 5
synapse:
image: matrixdotorg/synapse:latest
container_name: matrix-synapse
restart: unless-stopped
# Läuft mit eurer Host-UID/GID (aus .env) — dazu gleich mehr.
user: "${HOST_UID}:${HOST_GID}"
networks:
- matrix-net
depends_on:
postgres:
condition: service_healthy
environment:
SYNAPSE_SERVER_NAME: ${MATRIX_DOMAIN}
SYNAPSE_REPORT_STATS: "no"
volumes:
- ./synapse:/data
- ./line-bridge/data:/line-bridge-data:ro
ports:
- "8008:8008"
- "8448:8448"
element:
build:
context: ./element
dockerfile: Dockerfile
container_name: matrix-element
restart: unless-stopped
networks:
- matrix-net
depends_on:
- synapse
ports:
- "8080:80"
coturn:
build:
context: ./coturn
dockerfile: Dockerfile
container_name: matrix-coturn
restart: unless-stopped
network_mode: host
environment:
PUBLIC_IP: ${PUBLIC_IP}
TURN_USER: ${TURN_USER:-turnuser}
TURN_PASSWORD: ${TURN_PASSWORD}
MATRIX_DOMAIN: ${MATRIX_DOMAIN}
line-bridge:
build:
context: ./line-bridge/matrix-line-messenger
dockerfile: Dockerfile
container_name: matrix-line-bridge
restart: unless-stopped
# Behebt eine bekannte Eigenart des Bridge-Images — dazu gleich mehr.
entrypoint:
- /bin/sh
- -c
- |
if [ -f /data/config ] && [ ! -f /data/config.yaml ]; then
mv /data/config /data/config.yaml
echo "[entrypoint-fix] /data/config -> /data/config.yaml umbenannt"
fi
exec /docker-run.sh
networks:
- matrix-net
depends_on:
- synapse
volumes:
- ./line-bridge/data:/data
Drei verschiedene UID-Konflikte unter Linux (nicht relevant unter Docker Desktop für Mac)
Das war die hartnäckigste Fehlerklasse im ganzen Projekt — gleich drei unterschiedliche Varianten desselben Grundproblems, jede mit eigenem Symptom:
1. Von Docker automatisch angelegte Verzeichnisse gehören root, wenn sie beim allerersten Bind-Mount noch nicht existierten. Fix: setup.sh legt synapse/, postgres_data/, line-bridge/data/ immer selbst vorher an.
2. Der dauerhaft laufende Synapse-Container braucht Schreibzugriff auf ./synapse, z. B. um media_store anzulegen — sonst PermissionError: [Errno 13] Permission denied: ‚/data/media_store‘. Grund: Synapse läuft standardmäßig mit einer image-internen UID, die nicht zum Besitzer des Host-Verzeichnisses passt. Fix: user: „${HOST_UID}:${HOST_GID}“ in docker-compose.yml, mit HOST_UID/HOST_GID, die setup.sh automatisch (per id -u/id -g) in die .env einträgt.
3. Von der LINE-Bridge erzeugte Dateien (config.yaml, registration.yaml) gehören einer dritten internen UID — die Bridge läuft intern tatsächlich als root. Das erklärt zwei Symptome: root kann problemlos überall schreiben (deshalb funktioniert die Bridge trotz restriktiver Verzeichnisrechte), aber Synapse kann die für sie schreibgeschützten Bridge-Dateien danach nicht mehr lesen (PermissionError beim Laden von registration.yaml). Fix: fix-permissions.sh, ein kleiner Helfer, der nach jedem Generierungsschritt die Dateien auf euren Nutzer zurücksetzt und für andere Container-UIDs lesbar macht.
fix-permissions.sh ist rein idempotent (setzt nur Besitzer/Rechte, verändert keine Inhalte) und darf jederzeit beliebig oft ausgeführt werden — nicht nur während der Ersteinrichtung. Faustregel: immer, wenn ein Container gerade etwas Neues in synapse/ oder line-bridge/data/ geschrieben hat und ihr (oder ein anderer Container) danach wieder darauf zugreifen wollt.
Eine echte Inkonsistenz im LINE-Bridge-Image selbst
Nach dem ersten Start der Bridge lief ein Neustart-Loop mit dieser Meldung:
/data/config already exists, please remove it if you want to generate a new example
Didn’t find a config file.
Copied default config file to /data/config.yaml
Nachforschung im tatsächlichen docker-run.sh verwandter Bridge-Projekte (gleicher Autor, gleiches Skript-Template) zeigt: Das Skript prüft auf /data/config.yaml, schreibt aber tatsächlich /data/config — eine Inkonsistenz im Originalprojekt, die Log-Meldung ist irreführend und von einem älteren Schwesterprojekt übernommen. Solange config.yaml nie existiert, kopiert das Skript bei jedem Neustart erneut die Vorlage.
Der Fix sitzt jetzt im Container-Start selbst (entrypoint-Override in docker-compose.yml, siehe oben) — kein manueller Schritt mehr, der vergessen werden kann. Eine Neustart-Schleife bleibt trotzdem übrig, solange config.yaml noch die unbearbeitete Vorlage ist: Der Service läuft mit restart: unless-stopped, startet also nach jedem Fehlschlag automatisch neu, bis ihr ihn stoppt, patcht und wieder startet (siehe Ablauf weiter unten).
Die Konfigurationsdateien im Überblick
.env — die zentrale Werte-Quelle:
MATRIX_DOMAIN=matrix.example.com
POSTGRES_USER=synapse
POSTGRES_PASSWORD=CHANGE_ME_STRONG_DB_PASSWORD
POSTGRES_DB=synapse
TURN_USER=turnuser
TURN_PASSWORD=CHANGE_ME_TURN_PASSWORD
PUBLIC_IP=YOUR_PUBLIC_IP
ADMIN_USER=admin
HOST_UID/HOST_GID NICHT selbst eintragen — die ergänzt setup.sh automatisch.
postgres-init/init-line-bridge.sql — legt automatisch eine zweite Datenbank an (CREATE DATABASE line_bridge;). Das Postgres-Image führt beim allerersten Start automatisch alles aus, was unter /docker-entrypoint-initdb.d/ liegt — kein separat aufzurufendes Skript. Der Grund, warum es diese zweite Datenbank überhaupt braucht: Synapse und die Bridge dürfen sich keine Datenbank teilen. Die Bridge erkennt das beim Start (the database contains foreign tables) und verweigert konsequent den Dienst.
element/config.json wird von generate-element-config.sh automatisch aus der .env erzeugt und von element/Dockerfile per COPY fest ins Image gebacken — nicht gemountet.
synapse/homeserver.yaml wird beim ersten Start generiert:
docker run -it --rm \
-u "$(id -u):$(id -g)" \
-v "$(pwd)/synapse:/data" \
-e SYNAPSE_SERVER_NAME=matrix.example.com \
-e SYNAPSE_REPORT_STATS=no \
matrixdotorg/synapse:latest generate
Direkt danach patcht apply-env.py homeserver automatisch: Datenbank (SQLite→Postgres), Bridge-Registrierung, deaktivierte Selbstregistrierung, TURN-Zugangsdaten, und public_baseurl (siehe Discovery-Abschnitt unten) — alles mit echten Werten aus der .env.
Ein Detail, das in einer früheren, manuellen Version Zeit gekostet hat: Der generierte Datenbank-Block nennt den Schlüssel database: — ältere Beispiele im Netz nennen ihn dbname:. psycopg2 versteht nur database; stehen beide gleichzeitig drin, bricht Synapse mit you can’t specify both ‚database‘ and ‚dbname‘ arguments ab. apply-env.py ersetzt den kompletten Block auf einmal, das Problem kann so nicht mehr auftreten.
line-bridge/data/config.yaml wird von der Bridge selbst generiert. Danach: python3 apply-env.py line-bridge — patcht automatisch Homeserver-Adresse/Domain, eigene Datenbank-URI, Berechtigungen, und drei besonders tückische Werte:
- appservice.hostname steht standardmäßig auf 127.0.0.1 — der Bridge-Prozess lauscht dann nur auf sein eigenes Loopback-Interface und ist für andere Container nicht erreichbar (Connection refused). Muss auf 0.0.0.0.
- appservice.address (wo Synapse die Bridge erreicht) muss der Docker-Servicename sein (http://line-bridge:29322), nicht localhost.
- encryption.allow steht standardmäßig auf false. Element und andere moderne Matrix-Clients legen neue Direktnachrichten aber standardmäßig verschlüsselt an — ohne diesen Wert scheitert der allererste Kontakt mit dem Bot mit room is encrypted, but bridge isn’t configured to support encryption, und die Nachricht kommt nie an. Muss auf true.
line-bridge/data/registration.yaml wird beim zweiten Bridge-Start automatisch erzeugt. Ein Detail, das besonders viel Zeit gekostet hat: Das generierte Namespace-Regex war fehlerhaft (@line_\.+:matrix.example.com — literaler Escape-Punkt statt Wildcard, ohne Anker). Dadurch passte kein einziger LINE-Kontakt, jede Nachricht scheiterte mit Invalid user localpart for this application service. Nach der Generierung prüfen, dass dort steht:
regex: ‚^@line_.*:matrix\.example\.com$‘
Dieser eine Wert wird aktuell nicht automatisch gepatcht, da er nur einmalig entsteht und je nach Bridge-Version leicht variieren kann.
Server-Discovery (.well-known) — für mobile Apps entscheidend
Selbst wenn Element Web und curl einwandfrei funktionieren, kann die mobile App mit einer vagen Meldung wie “Kontoanbieter nicht erreichbar” scheitern. Grund: Viele Apps fragen zuerst https://MATRIX_DOMAIN/.well-known/matrix/client ab, bevor sie sich verbinden. Ohne public_baseurl in homeserver.yaml liefert Synapse dort nur {„errcode“:“M_NOT_FOUND“}. apply-env.py setzt das automatisch:
public_baseurl: „https://matrix.example.com“
Testen:
curl https://matrix.example.com/.well-known/matrix/client
Sollte gültiges JSON mit base_url liefern (Synapse hängt beim Ausliefern übrigens ohnehin einen abschließenden Schrägstrich an, unabhängig vom hier gesetzten Wert — das ist normales Verhalten, kein Fehler).
Der TURN-Server
Coturn ist kein externer Dienst — ein eigener, selbst gehosteter Server im Stack. Ohne ihn funktioniert Text-Chat, aber Anrufe scheitern oft, sobald beide Teilnehmer hinter unterschiedlichem NAT sitzen.
coturn/turnserver.conf.template wird beim Container-Start automatisch mit echten .env-Werten gefüllt (per entrypoint.sh, ohne manuelle Bearbeitung):
listening-port=3478
tls-listening-port=5349
external-ip=__PUBLIC_IP__
min-port=49152
max-port=49172
lt-cred-mech
user=__TURN_USER__:__TURN_PASSWORD__
realm=__MATRIX_DOMAIN__
no-tcp-relay
no-multicast-peers
- user=…: kein Drittanbieter-Konto, sondern ein frei erfundenes, geteiltes Geheimnis zwischen Coturn und Synapse — via .env automatisch an beiden Stellen identisch.
- no-tcp-relay: Verbindungsaufbau zum TURN-Server erlaubt sowohl UDP als auch TCP (TCP als Fallback für restriktive Netzwerke). Diese Zeile schaltet aber gezielt nur den Medien-Relay über TCP ab — der eigentliche Audio-/Video-Datenstrom läuft damit ausschließlich über UDP (bessere Performance). Für maximale Kompatibilität mit sehr restriktiven Netzwerken diese Zeile entfernen.
Grenzen dieses Setups: Sprach- und Videoanrufe
Ganz ehrlich an dieser Stelle: Der TURN-Server ist zwar vollständig eingerichtet und automatisiert, aber Sprach- und Videoanrufe habe ich in diesem Setup noch nicht abschließend zum Laufen gebracht — das hebe ich mir für einen der nächsten Beiträge auf, wenn ich die Portweiterleitung und den kompletten Anruf-Pfad Ende-zu-Ende getestet und dokumentiert habe. Bis dahin würde ich Live-Anrufe über diesen Server noch nicht als verlässlich einstufen.
Sprachnachrichten (Voicemails) funktionieren dagegen bereits problemlos — die werden schlicht als Audiodatei übertragen, genau wie Bilder oder Videos, und brauchen keinen Live-Medienstrom über TURN. Für alles, was reiner Nachrichtenaustausch ist (Text, Bilder, Sprachnachrichten, Videodateien), ist der Stack also bereits voll funktionsfähig — nur der Live-Anruf selbst steht noch aus.
Zugriff von außen: Cloudflare Tunnel
Für Zugriff von überall (nicht nur im eigenen LAN) braucht ihr HTTPS unter der echten Domain — ich nutze dafür Cloudflare Tunnel. Ein paar Punkte, die in der Praxis Zeit gekostet haben:
Getrennte Hostnamen pro Dienst, nicht ein Hostname mit mehreren Zielen. Cloudflare Tunnel routet nach Hostname, nicht nach Port — ein Hostname kann nur zu einem Ziel zeigen:
- matrix.example.com → http://<Server-IP>:8008 (Synapse)
- element.example.com → http://<Server-IP>:8080 (Element Web)
Mehrere Einträge unter demselben Hostnamen für verschiedene Ports funktionieren nicht — nur einer “gewinnt”, der Rest sorgt für Gateway-Fehler.
TURN-Ports können nicht über den Tunnel laufen — Cloudflare Tunnel unterstützt kein öffentliches UDP. Für funktionierende Anrufe bleibt nur direkte Portweiterleitung am Router für 3478, 5349 und 49152–49172.
Falls die mobile App den Server trotz erfolgreicher curl-/Browser-Tests partout nicht findet: Public-Hostname-Eintrag im Cloudflare-Dashboard einmal löschen und neu anlegen. Das hat in der Praxis einen Fall gelöst, bei dem Web und curl einwandfrei liefen, die App aber dauerhaft scheiterte — vermutlich ein hängengebliebener interner Zustand, der sich von außen nicht diagnostizieren ließ.
Browser-Eigenheiten beim Testen
Zwei Dinge, die wie Server-Fehler aussehen, aber reine Browser-Restriktionen sind:
- Secure Context: Moderne Browser stellen die für Matrix nötige Web-Crypto-API nur über HTTPS oder localhost bereit. Eine LAN-IP über reines HTTP (http://192.168.x.x:…) erfüllt das nicht — Login scheitert mit stillem schwarzem Bildschirm und Konsolenfehlern wie Browser missing feature: ‚crypto‘. Für Tests von einem anderen Gerät führt kein Weg an echtem HTTPS vorbei.
- Privater/Inkognito-Modus: Safari und andere Browser deaktivieren dort IndexedDB komplett, was Element zwingend braucht — gleiches Symptom, schwarzer Bildschirm.
Admin-User anlegen, Registrierung abschalten
apply-env.py setzt enable_registration: false automatisch. Nutzer per CLI anlegen:
docker compose exec synapse register_new_matrix_user \
-c /data/homeserver.yaml http://localhost:8008
Fragt interaktiv nach Benutzername, Passwort, Admin ja/nein. Nutzt für den ersten Admin denselben Namen wie ADMIN_USER in der .env — passt dann zu den automatisch gesetzten Bridge-Berechtigungen.
LINE zum ersten Mal verbinden
- Chat mit @linebot:matrix.example.com starten (Name steht in registration.yaml unter sender_localpart)
- Nachricht login senden
- Login-Link/QR-Code folgen
- Im LINE-Konto muss vorher eine E-Mail-Adresse hinterlegt sein (LINE-App → Einstellungen → Account) — sonst schlägt der Login zuverlässig fehl
Zusätzlicher Praxis-Hinweis: LINE erlaubt offenbar nur eine aktive Chrome-Erweiterungs-Session gleichzeitig. Meldet ihr die Bridge bei LINE an, während parallel noch eine separat installierte LINE-Chrome-Erweiterung angemeldet ist, kann das die eine die andere Session automatisch abmelden (und umgekehrt). Wer beides parallel nutzen möchte, sollte das im Hinterkopf behalten, falls sich eine Seite unerwartet abmeldet.
Ablauf in Kurzform
Bekannte Neustart-Schleifen, die ihr an zwei Stellen aktiv abbrechen müsst: Der line-bridge-Service läuft mit restart: unless-stopped und startet nach jedem Fehlschlag automatisch neu, solange die Config noch nicht mit euren echten Werten gepatcht ist — sowohl nach der ersten Config-Erzeugung als auch nach der Registrierungs-Erzeugung. Beide Male: mit docker compose stop line-bridge explizit stoppen, bevor ihr weitermacht (unten als eigener Schritt markiert). Nutzt außerdem durchgehend -d (detached) — ohne -d hängt das Terminal im Vordergrund fest, und ihr müsstet mit Strg+C abbrechen, um überhaupt weiterzuarbeiten.
cp .env.example .env
# ALLE Werte eintragen (Domain, DB-Passwort, TURN-Zugangsdaten, öffentliche IP, Admin-Name)
chmod +x setup.sh apply-env.py fix-permissions.sh generate-element-config.sh
./setup.sh
# klont Bridge-Repo, legt Verzeichnisse an, trägt HOST_UID/GID ein,
# generiert & patcht homeserver.yaml, generiert element/config.json
docker compose up -d postgres synapse coturn
docker compose up -d --build line-bridge
# erzeugt Bridge-Config (dank Entrypoint-Fix korrekt benannt)
docker compose stop line-bridge # <- Neustart-Schleife hier aktiv abbrechen
./fix-permissions.sh
python3 apply-env.py line-bridge
# patcht u.a. auch encryption.allow: true — ohne das scheitert der allererste
# Kontakt mit dem Bot, weil moderne Clients neue Chats standardmäßig
# verschlüsselt anlegen
docker compose up -d --build line-bridge
# erzeugt jetzt registration.yaml — Namespace-Regex prüfen (siehe oben)
docker compose stop line-bridge # <- Neustart-Schleife hier erneut abbrechen
./fix-permissions.sh
docker compose restart synapse
docker compose up -d
Danach: Admin-User anlegen, Cloudflare-Tunnel-Hostnamen einrichten, LINE verbinden.
Fazit
Jeder einzelne Fehler in diesem Projekt ließ sich am Ende auf eines von vier Mustern zurückführen: Docker, das Ordner statt Dateien anlegt; drei verschiedene, sich überlagernde UID-Konflikte zwischen Host und mehreren Containern; eine echte Inkonsistenz im Bridge-Image selbst; und Browser-Sicherheitsregeln, die wie Server-Fehler aussehen. Wer diese vier Kategorien kennt, kommt deutlich schneller durch als ich.
Die vollständigen, referenzierten Dateien aus diesem Beitrag gibt es als ZIP zum Download.

Link zur Unterstützung / Spende für den Kanal
Wenn meine Beiträge hilfreich sind oder dir geholfen haben, würde ich mich über eine Unterstützung sehr freuen 🙏
#Synapse #Matrix #Docker #ChatKontrolle #HomeLab #SaveForEU #MessagingDezentral