Jitsi Meet für Videoanrufe selbst hosten
Folge dem auf deinem eigenen Server. Kostenlos starten, keine Karte nötig
Zoom und Google Meet begrenzen beide kostenlose Anrufe nach Zeit oder Teilnehmerzahl, und die bezahlten Stufen rechnen pro Host, pro Monat ab, unabhängig davon, ob du sie in diesem Monat tatsächlich nutzt. Jitsi Meet ist Open-Source-Videokonferenzsoftware, die denselben Kernjob macht, browserbasierte Anrufe mit Bildschirmfreigabe ohne Installation, als selbst gehostete Software: vier Container, eine Domain, und keine Gebühr pro Minute oder Sitzplatz, sobald es läuft. Diese Anleitung richtet es auf einem leeren Server mit den offiziellen Images ein, mit Caddy, das HTTPS davor übernimmt, und erklärt das eine Teil (ein einzelner UDP-Port), das entscheidet, ob Anrufe tatsächlich zustande kommen, sobald mehr als eine Person in einem anderen Netzwerk ist.
Am Ende läuft eine funktionierende Jitsi-Meet-Instanz auf deiner eigenen Domain, du verstehst, warum dieser UDP-Port wichtig ist, und kennst den ehrlichen Stand von Railyards Ein-Klick-Weg für diese spezielle App.
Was du brauchst
- Einen Server mit echtem Spielraum. Ein einzelner Testanruf zwischen zwei Personen im selben lokalen Netzwerk passt auf einen Hetzner CX23 (2 vCPU, 4 GB RAM, 5,99 €/Monat exkl. MwSt.), aber länger laufende Team-Meetings wollen mehr: ein CX33 (4 vCPU, 8 GB RAM, 8,99 €/Monat) ist die sicherere Basis, sobald mehrere Personen sich tatsächlich täglich darauf verlassen.
- Eine Domain mit einem DNS-A-Record, der auf den Server zeigt (diese Anleitung nutzt
meet.example.com). - Die öffentliche IPv4-Adresse des Servers, vorab bekannt, nicht nur zugewiesen (du brauchst sie für NAT-Traversal in Schritt 3).
- SSH-Zugang und etwa 20 Minuten.
Schritt 1: Den Server provisionieren und Docker installieren
Lege den Server mit Ubuntu 24.04 an, zeig DNS darauf und installiere Docker:
ssh root@203.0.113.30
apt update && apt upgrade -y
curl -fsSL https://get.docker.com | sh
systemctl enable --now docker
docker --version
docker compose version
Schritt 2: Die offiziellen Konfigurationsverzeichnisse holen
Jitsis eigene Doku weist dich an, ein getaggtes Release herunterzuladen, statt das Repository direkt zu klonen, da die Compose-Datei auf dem Default-Branch dem voraus sein kann, was die veröffentlichten Images tatsächlich unterstützen. Diese Anleitung nutzt das aktuelle Release, stable-11248-1:
mkdir -p ~/.jitsi-meet-cfg/{web,transcripts,prosody/config,prosody/prosody-plugins-custom,jicofo,jvb}
chmod 777 ~/.jitsi-meet-cfg/transcripts
Diese Verzeichnisse halten Jitsis eigene generierte Konfiguration und bleiben über Upgrades hinweg erhalten; sie zu verlieren bedeutet, Passwörter und jede Anpassung neu zu generieren.
Schritt 3: Die Umgebungsdatei schreiben
CONFIG=~/.jitsi-meet-cfg
HTTP_PORT=8000
HTTPS_PORT=8443
JVB_PORT=10000
PUBLIC_URL=https://meet.example.com
DISABLE_HTTPS=1
ENABLE_LETSENCRYPT=0
ENABLE_HTTP_REDIRECT=0
XMPP_DOMAIN=meet.jitsi
XMPP_AUTH_DOMAIN=auth.meet.jitsi
XMPP_MUC_DOMAIN=muc.meet.jitsi
XMPP_INTERNAL_MUC_DOMAIN=internal-muc.meet.jitsi
XMPP_GUEST_DOMAIN=guest.meet.jitsi
XMPP_SERVER=xmpp.meet.jitsi
JICOFO_COMPONENT_SECRET=
JICOFO_AUTH_PASSWORD=
JVB_AUTH_PASSWORD=
JVB_ADVERTISE_IPS=203.0.113.30
ENABLE_GUESTS=1
TZ=Etc/UTC
Generiere die drei leeren Secrets mit:
for v in JICOFO_COMPONENT_SECRET JICOFO_AUTH_PASSWORD JVB_AUTH_PASSWORD; do
echo "$v=$(openssl rand -hex 16)"
done
Füge jeden Wert in .env an Stelle des leeren ein. DISABLE_HTTPS=1 und ENABLE_LETSENCRYPT=0 sind hier besonders wichtig, weil Caddy hier HTTPS übernimmt statt der eigenen eingebauten Option des Web-Containers, die sonst mit Caddy um Port 443 konkurrieren würde. JVB_ADVERTISE_IPS ist die Einstellung, die die meisten Self-Hosting-Anleitungen für Jitsi vergraben: es ist die öffentliche IP des Servers, dem Videobridge explizit mitgeteilt, damit es Teilnehmern hinter NAT eine erreichbare Adresse ankündigen kann, statt nur seiner privaten Docker-Netzwerkadresse.
Schritt 4: Die Docker-Compose-Datei schreiben
services:
caddy:
image: caddy:2
restart: unless-stopped
ports:
- "80:80"
- "443:443"
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile
- caddy-data:/data
- caddy-config:/config
depends_on:
- web
web:
image: ghcr.io/jitsi/web:stable-11248-1
restart: unless-stopped
volumes:
- ${CONFIG}/web:/config
- ${CONFIG}/transcripts:/usr/share/jitsi-meet/transcripts
env_file:
- .env
depends_on:
- jvb
prosody:
image: ghcr.io/jitsi/prosody:stable-11248-1
restart: unless-stopped
expose:
- "5222"
- "5269"
- "5347"
- "5280"
volumes:
- ${CONFIG}/prosody/config:/config
- ${CONFIG}/prosody/prosody-plugins-custom:/prosody-plugins-custom
env_file:
- .env
jicofo:
image: ghcr.io/jitsi/jicofo:stable-11248-1
restart: unless-stopped
volumes:
- ${CONFIG}/jicofo:/config
env_file:
- .env
depends_on:
- prosody
jvb:
image: ghcr.io/jitsi/jvb:stable-11248-1
restart: unless-stopped
ports:
- "${JVB_PORT:-10000}:${JVB_PORT:-10000}/udp"
volumes:
- ${CONFIG}/jvb:/config
env_file:
- .env
depends_on:
- prosody
volumes:
caddy-data:
caddy-config:
Der jvb-Dienst ist der eine mit einem echten, direkt veröffentlichten Host-Port, 10000/udp, statt hinter Caddy versteckt. Das ist keine Vereinfachung; HTTPS kann proxyt werden, aber der eigentliche Audio- und Video-Medienstrom nicht, da WebRTC einen direkten UDP-Pfad braucht. Validiere, bevor du startest:
docker compose config
Schritt 5: Die Caddyfile schreiben
meet.example.com {
reverse_proxy web:8000
}
Schritt 6: Hochfahren und die Firewall öffnen
docker compose up -d
docker compose ps
Du solltest alle fünf Dienste (caddy, web, prosody, jicofo, jvb) als running sehen. Öffne den UDP-Port explizit, falls eine Firewall auf dem Server aktiv ist:
ufw allow 10000/udp
ufw allow 80/tcp
ufw allow 443/tcp
Öffne https://meet.example.com; du solltest Jitsi Meets eigene Landing-Page mit gültigem Zertifikat sehen. Starte ein Meeting und tritt von zwei verschiedenen Netzwerken aus bei, nicht zwei Tabs auf derselben Maschine, da ein Test im selben Netzwerk ein NAT- oder Firewall-Problem mit dem UDP-Port nicht aufdecken würde.
Die Abkürzung: mit Railyard, ehrlich gesagt
Railyard hat eine Jitsi-Meet-Stack-Vorlage, die alle vier Anwendungscontainer (web, prosody, jicofo, jvb) zusammen provisioniert: wähle Jitsi Meet im Vorlagenkatalog. Es lohnt sich, direkt zu sein, wo das heute steht: Railyards Deployment-Manifest hat noch keinen Weg, einen UDP-Port zu veröffentlichen oder die öffentliche IP eines Servers einem Container anzukündigen, so wie JVB_ADVERTISE_IPS und das Host-UDP-Mapping in Schritt 4 das tun. Die Container kommen hoch und die Weboberfläche lädt, aber Anrufe zwischen Teilnehmern in unterschiedlichen Netzwerken bekommen keinen funktionierenden Medienpfad, bis das gelöst ist. Brauchst du Jitsi Meet schon heute für echte Anrufe, sind die Schritte 1 bis 6 oben der echte Weg; die Railyard-Vorlage ist als bekannte Lücke verfolgt statt übertüncht.
Troubleshooting
Die Seite lädt, aber Anrufe kommen zwischen zwei verschiedenen Netzwerken nie zustande. Das ist fast immer JVB_ADVERTISE_IPS, das nicht gesetzt ist oder auf die private Adresse des Servers zeigt statt auf seine öffentliche, kombiniert mit einem UDP-Port, der in der Firewall nicht tatsächlich offen ist. Bestätige beides; ein Anruf zwischen zwei Browser-Tabs auf derselben Maschine funktioniert auch mit diesem Fehler, deshalb ist das kein gültiger Test.
HTTPS lädt nicht, oder Caddy loggt einen Port-Konflikt. Prüfe, dass DISABLE_HTTPS=1 und ENABLE_LETSENCRYPT=0 tatsächlich in .env gesetzt sind; ohne sie versucht das eigene eingebettete Nginx des web-Containers ebenfalls, 443 zu binden.
Ein Teilnehmer hat Audio aber kein Video, oder umgekehrt. Meist ein restriktives Netzwerk auf der Seite dieses einen Teilnehmers (Firmen-Firewall, Hotel-WLAN) statt der Server; lass ihn ein anderes Netzwerk probieren, bevor du davon ausgehst, dass der Server fehlkonfiguriert ist.
Speicherknappheit mit mehr als einer Handvoll Teilnehmer. Jitsis Videobridge routet Medien für jeden Teilnehmer, und das ist echte CPU- und Speicherarbeit, die mit der Personenzahl skaliert, keine feste Kostenstelle. docker stats jvb während eines laufenden Anrufs zeigt, ob das die Einschränkung ist; ein CX33 oder größer hat mehr Spielraum als ein CX23.
Änderungen an .env wirken sich nicht aus. Die meisten Jitsi-Umgebungsvariablen werden nur einmal gelesen, beim Containerstart; docker compose up -d nach einer .env-Änderung erstellt einen schon laufenden, unveränderten Container nicht immer neu. Erzwinge es mit docker compose up -d --force-recreate.
FAQ
Kann ich Meetings aufnehmen? Ja, über Jibri, eine separate Aufnahme-Komponente, die diese Anleitung nicht einrichtet; sie braucht ihren eigenen Container und mehr Serverressourcen, und lohnt sich erst, sobald das Basis-Setup oben bestätigt funktioniert.
Wie viele Leute kann ein Server bewältigen? Das hängt mehr von der Videoqualität und Servergröße ab als von einer festen Zahl; ein CX33 bewältigt komfortabel die regelmäßigen Meetings eines kleinen Teams, und die CPU auf dem jvb-Container ist das, was mit wachsender Teilnehmerzahl zu beobachten ist.
Brauche ich TURN, damit das funktioniert? Meistens nicht, da JVB_ADVERTISE_IPS plus ein offener UDP-Port den üblichen Fall abdeckt. Ein TURN-Server hilft speziell, wenn ein Teilnehmer hinter einer Firewall sitzt, die direktes UDP komplett blockiert, was ein kleinerer Teil realer Netzwerke ist, als es früher war.
Ist Jitsi Meet wirklich kostenlos zu betreiben? Die Software ist es; der Server und seine Bandbreite sind die echten Kosten, und Videoanrufe nutzen erheblich mehr Bandbreite als eine typische Web-App, das lohnt sich einzukalkulieren, wenn ein Anbieter ausgehenden Traffic eng misst.
Wie ist die Mobile-Erfahrung? Jitsi hat native iOS- und Android-Apps, die mit jedem selbst gehosteten Server funktionieren; richte sie auf https://meet.example.com, genauso wie die Browser-Version.
Kann ich das hinter einem NAT-Router zuhause statt einem Cloud-Server betreiben? Ja, mit einem zusätzlichen Schritt: Leite sowohl den UDP-Medienport als auch TCP 443 vom Router zur Maschine weiter, auf der Docker läuft, und setze JVB_ADVERTISE_IPS auf die eigene öffentliche IP des Routers statt die lokale Adresse der Maschine, denn das ist, was die Videobridge an entfernte Teilnehmer ausgeben muss.
Jitsi Meet ist hier speziell eine der ehrlicheren Self-Hosting-Geschichten, weil das eine Ding, das tatsächlich zählt, ob ein Anruf über zwei Netzwerke zustande kommt, auf einen korrekt gesetzten UDP-Port und eine korrekt gesetzte IP-Adresse hinausläuft, kein Mysterium. Bekommst du diese zwei Dinge richtig, ist der Rest vier Container und ein Reverse-Proxy, die Anrufe laufen lassen, ohne dass jemand Minuten zählt.
Warum Leute sich dafür Railyard entscheiden
- Dein eigenes Cloud-Konto. Deploye auf DigitalOcean, Hetzner, Vultr, AWS, OVHcloud oder jedem Linux-Server per SSH, direkt von deinem Anbieter abgerechnet, ohne Aufschlag.
- Ein fester Preis pro Team. Free ist für immer kostenlos: ein Server plus ein Datenbankserver, drei Apps, keine Karte. Pro kostet 19 $ im Monat für bis zu fünf Server und unbegrenzte Apps. Team kostet 49 $ im Monat mit unbegrenzten Servern. Keine Kosten pro App, pro Deployment, pro Sitz oder pro Gigabyte.
- Templates mit einem Klick. Deploye Open-Source-Apps, wie Datenbanken, Analytics und Dev-Tools, mit einem Klick auf deinem eigenen Server.
- Verwaltete Datenbanken. Postgres, MySQL und Redis mit geplanten, wiederherstellungsgeprüften Backups und Point-in-Time-Recovery.
- Push-to-Deploy. Deploye von GitHub, GitLab oder der CLI, mit automatischem HTTPS und Releases ohne Ausfallzeit.