Relayium selbst hosten: eigener Datei- und Textübertragungs-Server
Zuletzt aktualisiert: 2026-08-06
Relayium ist AGPL-3.0-lizenziert und Open Source, und der Server ist ein einziges eigenständiges Image — keine externe Datenbank, kein Storage-Bucket eines Drittanbieters, nichts, wofür man sich anmelden müsste. Wenn du lieber alles selbst betreibst, statt dich auf relayium.com zu verlassen, bringt dich diese Anleitung mit Docker zu einem laufenden Server und richtet die CLI darauf aus.
Selbst hosten heißt, volle Kontrolle darüber zu haben, wo deine Daten liegen, eine eigene Domain und ein eigenes TLS-Zertifikat zu nutzen, und von den Betriebsentscheidungen anderer unabhängig zu sein. Alles Folgende stützt sich auf Dateien, die tatsächlich im Repository liegen — docker-compose.yml, server/.env.example und docs/self-hosting.md —, sodass hier kein Flag und keine Einstellung erwähnt wird, die es nicht wirklich gibt.
Warum selbst hosten
Relayiums Echtzeit-Übertragungen sind Ende-zu-Ende verschlüsselt. Ein selbst gehostetes TURN-Relay kann verschlüsselte Bytes transportieren und der Server verarbeitet Signalisierungsmetadaten, doch beide können Dateiklartext weder lesen noch entschlüsseln; weder Server noch Relay speichern eine serverseitige Kopie oder Historie von Echtzeitinhalten. Der Server hält aber dein Konto und — bei gespeicherten/link-basierten Übertragungen — verschlüsselte Blobs sowie eine kleine SQLite-Datenbank. Selbst hosten bedeutet, dass diese Daten auf Infrastruktur liegen, die du kontrollierst, unter deiner eigenen Domain, ohne dass fremde Betriebsentscheidungen mitspielen.
Da das Projekt AGPL-3.0-lizenziert und Open Source ist (github.com/relayium/relayium), kannst du genau nachlesen, was der Server tut, bevor du ihm irgendetwas anvertraust, und ihn frei forken oder verändern.
Schnellstart mit Docker
Was du vor Schritt 1 brauchst
- Einen Host mit Docker Engine und dem Compose-Plugin. docker compose version gibt eine Versionszeile aus; "docker: 'compose' is not a docker command" heißt, dass das Plugin fehlt.
- Einen Klon des Repositorys. Die Compose-Datei baut das Image aus genau diesem Quellbaum, braucht also das Dockerfile und web/ daneben — es gibt kein fertiges Image zum Ziehen.
- Platz für das benannte Volume relayium-data: die SQLite-Datenbank plus den Chiffretext gespeicherter Übertragungen, den du aufbewahrst.
- Eine Domain und einen TLS-terminierenden Reverse-Proxy, falls außer dir noch jemand den Server nutzt. Der Container spricht nur unverschlüsseltes HTTP und veröffentlicht standardmäßig ausschließlich auf dem Loopback-Interface.
- Sonst nichts. Keine externe Datenbank, kein Object-Storage-Bucket, kein Konto bei Dritten.
Im Repository-Root liegen ein Dockerfile und ein docker-compose.yml, die ein einziges eigenständiges Image bauen — ein statisches Go-Binary, das die vorgebaute Web-App ausliefert, sodass für den reinen Betrieb weder ein separates Node, eine Go-Toolchain noch nginx nötig ist.
Klone das Repository und wechsle hinein.
git clone https://github.com/relayium/relayium.gitcd relayiumBauen und starten. Das Platzhalter-Secret ist auch dann Pflicht, wenn das Relay aus ist: Compose prüft beim Parsen die Pflichtvariable des per Profil deaktivierten coturn-Dienstes mit, sodass ein blankes docker compose up die Arbeit verweigert.
RELAYIUM_TURN_SECRET=placeholder docker compose up -d --buildPrüfe, ob der Container oben geblieben ist und nicht in einer Neustartschleife hängt.
docker compose psFrag die Instanz, ob sie tatsächlich ausliefern kann. Nimm /readyz, nicht /healthz — der Unterschied ist der ganze Sinn dieser Prüfung, und der Erwartungskasten unten sagt, warum.
curl -s http://127.0.0.1:8080/readyzKopiere die Konfigurationsvorlage und trag deine öffentliche URL ein. RELAYIUM_BASE_URL baut die Links in ausgehenden E-Mails und entscheidet, ob Session-Cookies das Secure-Flag bekommen — es muss also deine echte https://-Adresse sein.
cp server/.env.example server/.envchmod 600 server/.envSetz nginx oder Caddy davor, das TLS für deine Domain terminiert und alles — /, /api, /ws, /admin — an Port 8080 weiterreicht. Danach neu starten, damit server/.env greift.
docker compose up -d
So sieht eine funktionierende Instanz aus
Der Container meldet Up, und beide Endpunkte antworten. Entscheidend ist ready: /healthz liefert bedingungslos ok, noch bevor irgendetwas geöffnet wurde, und geht deshalb auch auf einer Instanz durch, deren Datenbank oder Blob-Verzeichnis unbrauchbar ist. /readyz pingt die SQLite-Datenbank und das Blob-Verzeichnis an und antwortet mit 503, sobald eines von beiden kaputt ist.
$ docker compose ps
NAME IMAGE STATUS PORTS
relayium-server-1 relayium/relayium:local Up 12 seconds 127.0.0.1:8080->8080/tcp
$ curl -s http://127.0.0.1:8080/healthz
ok
$ curl -s http://127.0.0.1:8080/readyz
ready- Das ist bereits der gesamte Server, er lauscht auf :8080. Setze in Produktion nginx oder Caddy davor, um TLS zu übernehmen — docs/self-hosting.md beschreibt den Docker-Weg und was du proxyen musst; Relayiums eigene Produktions-nginx-Konfiguration ist nicht veröffentlicht.
- Die App-Konfiguration kommt aus einer optionalen server/.env-Datei plus dem environment:-Block in docker-compose.yml. Jede Einstellung hat einen passenden RELAYIUM_*-Key — kopiere server/.env.example als Ausgangspunkt.
- Die vier für eine einfache Bereitstellung wichtigen Keys: RELAYIUM_ADDR (Listen-Adresse), RELAYIUM_STATIC (Pfad zur gebauten Web-App), RELAYIUM_DB (SQLite-Dateipfad) und RELAYIUM_BLOB_DIR (wohin der Chiffretext gespeicherter Links geschrieben wird). docker-compose.yml setzt für alle vier bereits sinnvolle Standardwerte und persistiert sie in einem benannten Volume.
Ein TURN-Relay für netzwerkübergreifende Übertragungen hinzufügen
Übertragungen im selben Netzwerk (LAN) und SSH-basiertes push/pull funktionieren ohne irgendetwas Zusätzliches. Netzwerkübergreifende Echtzeit-Übertragungen (zwei Geräte hinter unterschiedlichen NATs) brauchen manchmal ein TURN-Relay, um einen Pfad herzustellen — das Relay sieht dabei stets nur Chiffretext, niemals deinen Dateiinhalt.
docker-compose.yml hat ein optionales relay-Profil, das zusammen mit dem Hauptserver coturn (den TURN-Server) und eine kleine Redis-Instanz für die Zählung der Relay-Bytes startet.
Das Secret muss an zwei verschiedene Stellen gelangen, und wenn das schiefgeht, scheitert es lautlos. coturn bekommt es über die Variablenersetzung von Compose, die nur aus der Shell oder einer .env im Projektwurzelverzeichnis aufgelöst wird. Der Server liest es aus seiner eigenen Umgebung — also aus server/.env — und ein leeres Secret schaltet TURN vollständig ab. Setzt du nur eines von beiden, läuft ein coturn, für das der Server nie Zugangsdaten ausstellt: Jeder Container meldet sich gesund, im Log steht nichts, und Übertragungen durch strenge NATs scheitern weiter genau wie vorher.
Erzeuge ein einziges langes Zufalls-Secret. Überall unten kommt derselbe Wert hin.
openssl rand -hex 32Trag dieses Secret und die Relay-Adressen, auf die deine Domain zeigt, in server/.env ein — erst damit schaltet der Server TURN überhaupt ein.
RELAYIUM_TURN_SECRET=<the value from step 1> RELAYIUM_TURN_URLS=turn:example.com:3478,turns:example.com:5349Exportiere dieselbe Datei in die Shell, damit die Ersetzung von Compose coturn dasselbe Secret übergeben kann. Sourcen hält die Quelle einzig und hält das Secret von der Kommandozeile fern, wo ps es sichtbar machen würde.
set -a; . ./server/.env; set +aStarte den Stack mit dem relay-Profil.
docker compose --profile relay up -d --buildÖffne die Relay-Ports in der Firewall des Hosts. coturn läuft im Host-Netzwerk, das sind also Host-Regeln und keine Docker-Regeln: UDP 3478 und 49152-65535, TCP 3478 und 5349.
Prüfe, ob der Server — nicht nur coturn — mit dem Secret hochgekommen ist. Genau diese Prüfung fängt den lautlosen Fall ab.
docker compose exec server env | grep RELAYIUM_TURN
So sieht ein funktionierendes Relay aus
Beide Schlüssel kommen aus dem Inneren des Server-Containers nicht leer zurück. Dass coturn läuft, sagt für sich genommen nichts — der Browser bekommt ausschließlich Relay-Zugangsdaten, die der Server ausgestellt hat.
$ docker compose exec server env | grep RELAYIUM_TURN
RELAYIUM_TURN_SECRET=3f7a…
RELAYIUM_TURN_URLS=turn:example.com:3478,turns:example.com:5349- coturn braucht die echte öffentliche IP des Hosts und einen offenen UDP-Portbereich, um zu funktionieren — docs/self-hosting.md beschreibt den Start über das Docker-relay-Profil; Relayiums eigene Produktions-coturn-Konfiguration (inklusive Installationsskript) ist nicht veröffentlicht.
- Ohne --profile relay und RELAYIUM_TURN_SECRET läuft der Server trotzdem einwandfrei — netzwerkübergreifende Übertragungen fallen dann nur auf reines STUN zurück, das bei einfacheren NAT-Typen funktioniert, aber nicht bei den strengsten.
Installiere die CLI auf deinem Rechner
Dieser letzte Schritt führt die relayium-CLI auf deinem eigenen Rechner aus (nicht auf dem Server), installiere sie dort also, falls noch nicht geschehen. Unter macOS oder Linux:
curl -fsSL https://relayium.com/install.sh | sh
- relayium.com/cli listet alle Installationswege — ein Windows-Binary, die Releases-Seite oder go build, wenn du Go hast.
- relayium --version bestätigt es. Ohne die CLI gibt der Befehl unten nur „command not found“ aus.
Die CLI auf deinen Server ausrichten
Die Relayium CLI verwendet für netzwerkübergreifendes send/receive und text standardmäßig den Rendezvous-Server auf relayium.com. Übergib --server, um stattdessen deinen eigenen zu nutzen.
Melde dich auf einem Rechner, der die CLI aus dem Abschnitt oben schon hat, an deinem eigenen Server an statt an relayium.com. Es erscheinen eine URL und ein Code; bestätige ihn in einem Browser, der an deiner Instanz angemeldet ist.
relayium login --server https://your-domainPrüfe, an welchen Server die gespeicherten Zugangsdaten gebunden sind. whoami nimmt keine Flags — es meldet, was die Anmeldung tatsächlich geschrieben hat, und genau das macht den Aufruf wertvoll.
relayium whoamiGib beim Senden dasselbe --server mit. Ohne es prägt die CLI den Pairing-Code auf relayium.com, und die Gegenseite findet ihn auf deiner Instanz nie.
relayium send ./report.pdf --server https://your-domainEmpfange auf dem anderen Rechner mit dem ausgegebenen Code und demselben --server. Textsitzungen laufen genauso.
relayium receive 483920 --server https://your-domainrelayium text --server https://your-domainrelayium text 483920 --server https://your-domain
Woran du merkst, dass sie mit deiner Instanz spricht
whoami gibt das Konto aus und dahinter in Klammern den Server, an den es gebunden ist. Steht dort deine eigene Domain und nicht relayium.com, ist es bestätigt.
$ relayium login --server https://your-domain
Open https://your-domain/device and enter code: WDJB-MJHT
logged in as you@example.com
$ relayium whoami
you@example.com (https://your-domain)- Egal welchen Server sie nutzt, die CLI ist kostenlos — --server ändert nur den Rendezvous-Server. send oder text ohne Code erzeugen dort einen Code, und Cloud-up speichert unter einem Konto auf ihm; melde dich daher zuerst mit relayium login --server https://your-domain an. receive, down und text mit dem ausgegebenen Code brauchen keine Anmeldung.
- Beide text-Gegenstellen müssen gleichzeitig online bleiben. Nachrichten laufen über eine eigene Ende-zu-Ende-verschlüsselte direkte P2P-Sitzung. CLI text ist rein direkt und nutzt nicht das TURN-Relay der Web-App. Weder Relayium noch dein selbst gehosteter Server speichern Nachrichteninhalte oder einen serverseitigen Verlauf; beide Terminals beziehungsweise der Empfänger können empfangenen Text jedoch kopieren oder aufbewahren.
- push/pull (über dein eigenes SSH) sowie serve + daemon-direct push relayium://host berühren relayium.com überhaupt nicht, selbst gehostet oder nicht — sie verbinden sich direkt mit der von dir angegebenen Gegenstelle.
Wenn es nicht funktioniert
Fünf Fehler decken fast jedes gescheiterte Selbst-Hosting ab. Zu jedem gibt es eine Zeile zum Lesen oder einen Befehl zum Ausführen, der die Sache entscheidet — und drei der fünf sehen wie Erfolg aus, bis du die Prüfung wirklich laufen lässt.
Symptom, Prüfung, Lösung
- docker compose up verweigert den Start komplett, bevor überhaupt etwas gebaut wird.
docker compose up -d --build # required variable RELAYIUM_TURN_SECRET is missing a valueCompose ersetzt die Variablen der ganzen Datei, bevor es nach Profilen filtert — die Pflichtvariable des abgeschalteten coturn-Dienstes wird also auch dann geprüft, wenn das Relay aus ist. Stell irgendeinen Platzhalter voran — RELAYIUM_TURN_SECRET=placeholder docker compose up -d --build — und ersetze ihn erst durch ein echtes Secret, wenn du das relay-Profil tatsächlich einschaltest.
- Der Container ist Up, aber ein Browser auf einem anderen Rechner erreicht ihn nicht.
docker compose ps # PORTS 127.0.0.1:8080->8080/tcpDiese Bindung ans Loopback ist die Voreinstellung, damit ein öffentlicher Host kein unverschlüsseltes HTTP ins Internet stellt. Lass sie im Produktivbetrieb so und terminiere TLS in einem Reverse-Proxy auf demselben Host. Für eine reine LAN-Kiste ohne Proxy veröffentlichst du weiter mit RELAYIUM_BIND=0.0.0.0 docker compose up -d — diese Variable liest compose, nicht der Server.
- /healthz sagt ok, aber die Registrierung schlägt fehl und gespeicherte Links tauchen nie auf.
curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:8080/readyz # 503/healthz antwortet bedingungslos mit ok und belegt nur, dass der Prozess lauscht. /readyz pingt die SQLite-Datenbank und das Blob-Verzeichnis an, eine 503 heißt also, dass eines von beiden unbrauchbar ist — prüfe, ob das Volume relayium-data gemountet ist und ob RELAYIUM_DB und RELAYIUM_BLOB_DIR hineinzeigen.
- relayium login gibt eine Bestätigungs-URL auf localhost aus, die du nicht öffnen kannst.
relayium login --server https://your-domain # Open http://localhost:8080/device and enter code: WDJB-MJHTDer Server baut diese URL aus RELAYIUM_BASE_URL, dessen Vorgabe http://localhost:8080 ist. Trag in server/.env deine echte https://-Adresse ein und starte neu. Der Wert entscheidet außerdem, ob Session-Cookies das Secure-Flag bekommen — ihn falsch zu lassen ist also nicht nur ein Schönheitsfehler.
- coturn läuft, aber netzwerkübergreifende Übertragungen durch strenge NATs scheitern weiter — und nichts wird geloggt.
docker compose exec server env | grep RELAYIUM_TURN # keine AusgabeDas Secret hat coturn über die Compose-Ersetzung erreicht, den Server aber nie, und dessen leeres Secret schaltet TURN vollständig ab. Trag RELAYIUM_TURN_SECRET und RELAYIUM_TURN_URLS in server/.env ein, source die Datei mit set -a; . ./server/.env; set +a, damit die Ersetzung denselben Wert sieht, und starte das relay-Profil neu. Beide Schlüssel müssen bei dieser Prüfung nicht leer zurückkommen.
Häufige Fragen
Muss ich TURN einrichten?
Nur, wenn netzwerkübergreifende Echtzeit-Übertragungen auch durch strenge NATs funktionieren sollen. Übertragungen im selben Netzwerk, SSH-basiertes push/pull und daemon-direct funktionieren alle ohne TURN — TURN dient ausschließlich der NAT-Traversal auf dem netzwerkübergreifenden Pairing-Code-Pfad.
Ist die CLI immer noch kostenlos, wenn ich selbst hoste?
Ja. Die CLI bleibt mit relayium.com wie mit deinem eigenen Server kostenlos. Ein Konto auf dem Zielserver brauchen send oder text ohne Code zum Erzeugen eines Codes sowie up zum Speichern einer Datei. receive, down und text mit dem ausgegebenen Code brauchen keine Anmeldung.
Kann ich meine eigene Domain und ein eigenes TLS-Zertifikat verwenden?
Ja. Das Docker-Image lauscht selbst auf reinem HTTP auf :8080; setze nginx oder Caddy mit deiner eigenen Domain und deinem Zertifikat davor (z. B. über certbot/Let's Encrypt). docs/self-hosting.md beschreibt, was zu proxyen ist; Relayiums eigene Produktions-nginx-Konfiguration ist nicht veröffentlicht, du musst also deine eigene schreiben.
Welche Daten speichert mein selbst gehosteter Server?
Eine SQLite-Datenbank (Konten, Sessions) unter RELAYIUM_DB und, bei gespeicherten/link-basierten Übertragungen, verschlüsselte Blobs unter RELAYIUM_BLOB_DIR, die der Server selbst nicht entschlüsseln kann. Der Server speichert keine Echtzeit-Dateien oder Nachrichteninhalte und leitet nur den Signaling-Handshake weiter; Empfangsgeräte können Dateien oder Text dennoch behalten.
Installiere die kostenlose Relayium CLI und richte sie mit --server auf deinen eigenen Server aus.
CLI holen