· DevOps  · 9 Min. Lesezeit

Eigene Fernwartung mit RustDesk und eigenem Schlüssel

Fernwartung ohne fremde Cloud, mit einem selbst betriebenen RustDesk-Server OSS. Was hbbs und hbbr tun, welche Ports wirklich nötig sind, warum die Schlüsselpflicht nicht voreingestellt ist und wie Sie jeden Schritt nachweisbar prüfen.

Fernwartung ohne fremde Cloud, mit einem selbst betriebenen RustDesk-Server OSS. Was hbbs und hbbr tun, welche Ports wirklich nötig sind, warum die Schlüsselpflicht nicht voreingestellt ist und wie Sie jeden Schritt nachweisbar prüfen.

Fernwartung läuft bei den meisten Werkzeugen über die Server des Anbieters. RustDesk lässt sich stattdessen selbst hosten. Die offizielle Doku bezeichnet die Hardwareanforderungen als sehr gering und nennt einen minimalen Cloud-Server oder einen Raspberry Pi als ausreichend.

Der Punkt, der über die Vertraulichkeit der Sitzungen entscheidet, ist nicht die Installation. Es ist die Schlüsselpflicht. Die offizielle Compose-Datei startet beide Dienste ohne Schlüsselparameter, und das offizielle Image hat als Voreinstellung ENCRYPTED_ONLY=0. Wer nichts weiter tut, betreibt einen Rendezvous- und Relay-Dienst, der beliebige Clients annimmt. Dieser Beitrag zeigt den Weg vom leeren Server bis zum verbundenen Client, mit einem Prüfbefehl nach jedem Schritt.

Stand der Betrachtung ist RustDesk Server 1.1.16 vom 20. Juli 2026. Dieses Release schließt eine Lücke, über die unauthentifizierte UDP-Punch-Hole-Anfragen für Reflection- und Amplification-Missbrauch nutzbar waren.

Erst die Entscheidung: OSS oder Pro

Die Doku beschreibt den Lieferumfang der Open-Source-Variante knapp und ohne Marketing.

AnforderungRustDesk Server OSSHinweis der Doku
ID-, Rendezvous- und Signalisierungsdienstenthalten (hbbs)Kernfunktion
Relay bei fehlender Direktverbindungenthalten (hbbr)wird meist gar nicht gebraucht
Web-Konsolenicht enthaltenPort 21114 ist nur in Pro nutzbar
API-Zugriff, OIDC, LDAP, 2FAnicht enthaltenVerweis auf RustDesk Server Pro
Geräteverwaltung, zentrale Administrationnicht enthaltenVerweis auf RustDesk Server Pro
SupportCommunityDokumentation und Discord

Das Auswahlkriterium formuliert die Doku selbst: OSS ist richtig, wenn Sie Kernfunktionen für den Selbstbetrieb wollen und Deployment, Netz und Upgrades selbst verantworten. Zur Dimensionierung: Hole Punching ist laut Doku in der Mehrzahl der Fälle erfolgreich, der Relay wird dann nie benutzt. Sein Bandbreitenbedarf ist ein Worst-Case-Wert, kein Regelbetrieb.

Die zwei Rollen und ihre Ports

Beide Dienste teilen sich einen festen Portbereich. Die Zuordnung steht in der Selbsthosting-Übersicht der Dokumentation:

PortProtokollRolleZweck
21114TCPhbbsWeb-Konsole, nur Pro
21115TCPhbbsZusatzport für den NAT-Typ-Test
21116TCP und UDPhbbsUDP für ID-Registrierung und Heartbeat, TCP für Hole Punching und Verbindungsaufbau
21117TCPhbbrRelay
21118TCPhbbsWebSocket für den Web-Client
21119TCPhbbrWebSocket für den Web-Client

Zwei Punkte daraus sind betriebsrelevant. Laut Doku sind nur TCP 21115 bis 21117 das Minimum, alles andere ist optional oder Pro. Und 21116 muss zwingend für TCP und UDP offen sein, weil die UDP-Seite ID-Registrierung und Heartbeat trägt. Fehlt sie, erscheint kein Client online, obwohl TCP einwandfrei funktioniert.

Schritt 1: Server per Docker aufsetzen

Die Doku empfiehlt Docker, weil dieser Weg am einfachsten reproduzierbar, aktualisierbar und umziehbar ist. Er besteht aus genau drei Befehlen:

bash <(wget -qO- https://get.docker.com)
wget rustdesk.com/oss.yml -O compose.yml
sudo docker compose up -d

Die heruntergeladene compose.yml definiert beide Dienste mit dem Image rustdesk/rustdesk-server:latest, dem Volume ./data:/root, network_mode: "host", restart: unless-stopped und den Kommandos hbbs beziehungsweise hbbr ohne weitere Argumente. Zwei Details lohnen den zweiten Blick. network_mode: "host" funktioniert laut Doku nur unter Linux und sorgt dafür, dass beide Dienste die echte eingehende IP sehen statt der Container-IP 172.17.0.1. Und ./data:/root passt zum klassischen Image mit Arbeitsverzeichnis /root. Dort landen Schlüssel und Datenbank.

Prüfung: docker logs hbbs und docker logs hbbr. Beim allerersten Start meldet das Log das Anlegen des Schlüsselpaars (Private/public key written to ...). Bei jedem weiteren Start muss dort Private key comes from id_ed25519 stehen. Dieser Unterschied ist Ihr wichtigstes Diagnosemittel.

Schritt 2: Die Ports freigeben

Die Dokumentation gibt die UFW-Regeln wörtlich vor:

ufw allow 21114:21119/tcp
ufw allow 21116/udp
sudo ufw enable

Bevor Sie ufw enable ausführen, vergewissern Sie sich, dass Ihre SSH-Regel steht. Und beachten Sie eine Einschränkung, die die Doku an derselben Stelle nennt: Ohne Web-Client sollen 21118 und 21119 geschlossen bleiben. Die Bereichsfreigabe ist damit die bequeme, nicht die engste Variante. Ohne Web-Client ist ufw allow 21115:21117/tcp die passendere erste Regel.

Prüfung:

ufw status

Beide Regelarten müssen erscheinen, die TCP-Freigabe und die eigenständige UDP-Regel für 21116. Fehlt Letztere, ist der Server erreichbar und trotzdem funktionslos.

Schritt 3: Die Schlüsselpflicht aktiv setzen

Hier weicht die Praxis von der Voreinstellung ab, und das ist der Kern dieses Beitrags. Weder die offizielle oss.yml noch die Compose-Beispiele der Doku setzen einen Schlüsselparameter.

Die Mechanik steht im Quellcode. Die CLI-Hilfe von hbbs beschreibt -k, --key=[KEY] mit den Worten Only allow the client with the same key. hbbr kennt denselben Parameter und nimmt alternativ die Umgebungsvariable KEY entgegen. Das offizielle Container-Image bildet die Schlüsselpflicht auf eine eigene Variable ab. Sein Startskript enthält:

PARAMS=
[ "${ENCRYPTED_ONLY}" = "1" ] && PARAMS="-k _"
/usr/bin/hbbs -r $RELAY $PARAMS

Das zugehörige Dockerfile setzt ENV ENCRYPTED_ONLY=0. Die Schlüsselpflicht ist also nicht voreingestellt, sie muss aktiv gesetzt werden. Daher stammt auch der Aufruf -k _, den die Doku für einen separaten Relay zeigt.

Welcher Weg greift, hängt vom Image ab. Das klassische Image setzt WORKDIR /root und wird über Kommandoargumente gesteuert, das s6-basierte Image im Repository setzt WORKDIR /data und steuert über RELAY und ENCRYPTED_ONLY. Für den kommandogesteuerten Weg ersetzen Sie in der compose.yml genau die beiden command-Zeilen, alles andere bleibt unverändert:

    # im Dienst hbbs
    command: hbbs -r rustdesk.lab.rz.jabi-it.de -k _

    # im Dienst hbbr
    command: hbbr -k _

Danach sudo docker compose up -d erneut ausführen, damit die Container mit den neuen Argumenten anlaufen.

Eine Warnung aus der FAQ gehört hierher: Rufen Sie hbbs -k mit einem konkreten Wert auf, muss das der private Schlüssel sein. Der öffentliche gehört ausschließlich in den Client.

Prüfung: Beide Dienste müssen dasselbe Schlüsselpaar sehen. Die Doku gibt für einen korrekt gestarteten hbbr diese Ausgabe an:

INFO [src/common.rs:121] Private key comes from id_ed25519
INFO [src/relay_server.rs:581] Key: XXXXXXXXXXXXXXXXXXXXX
INFO [src/relay_server.rs:81] Listening on tcp :21117

Vergleichen Sie die Key:-Zeile beider Dienste. Weichen die Werte ab, arbeiten sie auf verschiedenen Datenverzeichnissen.

Schritt 4: Den öffentlichen Schlüssel auslesen

Der Schlüssel entsteht beim ersten Start von hbbs und liegt als id_ed25519.pub im Datenverzeichnis. Genau dieser Wert gehört in das Key-Feld des Clients, auszulesen mit cat ./data/id_ed25519.pub.

Prüfung: Der Server bringt rustdesk-utils mit, das Schlüsselpaare validieren kann:

rustdesk-utils validatekeypair "$(cat ./data/id_ed25519.pub)" "$(cat ./data/id_ed25519)"

Erwartet wird Key pair is VALID.

Schritt 5: Den Client einrichten

Die Doku verlangt nicht, dass Sie drei Adressfelder ausfüllen. Sie sagt: Tragen Sie den hbbs-Host oder dessen IP im Feld ID Server ein, auf beiden Seiten der Verbindung. Die anderen beiden Adressen bleiben leer, RustDesk leitet sie selbst ab. Der Weg dorthin steht in der Client-Konfiguration für selbst gehostete Server: Menü [ ⋮ ] neben Ihrer ID, dann Network, dann mit erhöhten Rechten entsperren.

ID Server:     rustdesk.lab.rz.jabi-it.de
Relay Server:  (leer)
API Server:    (leer)
Key:           <Inhalt von id_ed25519.pub>

Ein Hinweis, den die Doku eigens gibt: Dieser Key ist der öffentliche Schlüssel für die Verbindungsverschlüsselung, nicht der Lizenzschlüssel der Pro-Version.

Prüfung: Der Client muss nach dem Speichern online gehen und eine ID anzeigen. Tut er das nicht, prüfen Sie zuerst die UDP-Seite von 21116, denn darüber läuft die ID-Registrierung.

Schritt 6: Die Erreichbarkeit von außen nachweisen

rustdesk-utils bringt dafür den Unterbefehl doctor mit. Führen Sie ihn von einem externen Host aus, nicht auf dem Server selbst:

rustdesk-utils doctor rustdesk.lab.rz.jabi-it.de

Der Befehl prüft die TCP-Ports einzeln (21114 für die API, 21115, 21116, 21117 sowie die WebSocket-Ports 21118 und 21119) und löst zusätzlich Reverse-DNS auf. Für einen OSS-Server ohne Web-Client ist ein ERROR bei 21114, 21118 und 21119 das gewünschte Ergebnis, kein Problem.

Die drei folgenreichsten Stolpersteine

1. Kein Client wird jemals online

Symptom: Der Server läuft, TCP-Verbindungen funktionieren, aber es taucht nie ein Client online auf.

Ursache: Port 21116 wurde nur für TCP freigegeben. Über 21116/UDP laufen jedoch ID-Registrierung und Heartbeat.

Prüfung: ufw status, beide Regeln müssen erscheinen. Für die TCP-Seite von außen zusätzlich rustdesk-utils doctor <hostname>.

Lösung: Neben der TCP-Freigabe zwingend ufw allow 21116/udp setzen.

2. Der Schlüssel überlebt den Neustart nicht

Symptom: Nach jedem Neustart des Containers sind alle Clients ausgesperrt. Der Schlüssel hat sich geändert, die Datenbank ist leer.

Ursache: Das Volume ist falsch gemappt. id_ed25519, id_ed25519.pub und db.sqlite3 landen im Container statt im Host-Verzeichnis und werden bei jedem Start neu erzeugt. Die FAQ beschreibt genau diesen Fall.

Prüfung: Zeitstempel vor und nach einem Neustart vergleichen. Sie dürfen sich nicht ändern, und im Log muss Private key comes from id_ed25519 stehen, nicht Private/public key written to.

ls -l ./data/id_ed25519*
docker compose restart hbbs
ls -l ./data/id_ed25519*
docker logs hbbs | grep -i "key"

Lösung: Das Mapping der offiziellen oss.yml verwenden, also ./data:/root beim klassischen Image. Beim s6-basierten Image liegt das Verzeichnis dagegen auf /data. Welches Ihr Image nutzt, klärt docker exec hbbs pwd.

3. Gefälschte Client-IPs in den Logs

Symptom: IP-basierte Sperren und Rate-Limits greifen nicht, die in den Logs vermerkten Adressen sind unglaubwürdig.

Ursache: Die WebSocket-Ports 21118 und 21119 sind direkt aus dem Internet erreichbar. hbbs und hbbr vertrauen dort den Headern X-Real-IP und X-Forwarded-For ungeprüft. Die Installationsanleitung benennt die Konsequenz ausdrücklich: Wer diese Ports direkt erreicht, kann mit gefälschten Headern eine beliebige IP vortäuschen, IP-basiertes Rate-Limiting umgehen und die Protokolle verfälschen.

Prüfung: Von einem externen Host rustdesk-utils doctor <hostname> ausführen. Für 21118 und 21119 muss dort ERROR stehen, sofern Sie den Web-Client nicht anbieten.

Lösung: Ohne Web-Client bleiben 21118 und 21119 geschlossen. Mit Web-Client stellen Sie einen Reverse Proxy davor, der X-Real-IP selbst setzt, und begrenzen die beiden Ports per Firewall auf diesen Proxy.

Die vollständige Sammlung der Stolpersteine

Diese drei Punkte treffen eine Neuinstallation an ihren empfindlichsten Stellen, also Erreichbarkeit, Schlüsselbestand und Aussagekraft der Logs. Sie sind aber nicht alles. Die vollständige Sammlung aller Stolpersteine steht im eigenen Beitrag RustDesk-Server: alle Stolpersteine im Überblick, jeweils im selben Schema aus Symptom, Ursache, Prüfung und Lösung. Dort finden Sie zusätzlich Key mismatch durch zwei parallel laufende Serverprozesse, fehlenden NAT Loopback im eigenen LAN, Host-Networking außerhalb von Linux, den Portkonflikt mit einem lokal installierten Client, den zweiten Relay auf separatem Host, den Offline-Overflow vor 1.1.16 und den Serverbetrieb unter Windows. Arbeitet Ihr Server nicht wie beschrieben, schlagen Sie dort nach.

Grenzen

Die Open-Source-Variante ist genau das, was die Tabelle oben beschreibt, und nicht mehr. Wer eine Nutzerverwaltung mit Anbindung an ein Verzeichnis braucht, muss zur Pro-Variante greifen.

Auch beim Betrieb bleibt Arbeit bei Ihnen. Die Doku weist Deployment, Netz und Upgrades ausdrücklich dem Betreiber zu. Sie verfolgen also die Release-Notes selbst, und Sie sichern id_ed25519, id_ed25519.pub und db.sqlite3 vor jedem Eingriff. Wie ein tragfähiges Sicherungskonzept aussieht, steht im Beitrag Die 3-2-1-Regel für Backups.

Release 1.1.15 vom 12. Januar 2026 definiert die HOME-Variable für rootless-Betrieb, passend zu einem rootless betriebenen Docker, und protokolliert auf Wunsch fehlgeschlagene Authentifizierungen, damit fail2ban oder CrowdSec darauf ansetzen können.

Ich halte die Schlüsselpflicht für den einen Schritt, den man bei diesem Dienst nicht auslassen darf. Ein offener Rendezvous- und Relay-Dienst im Internet ist kein Komfortmerkmal, sondern eine fremdnutzbare Infrastruktur auf Ihre Kosten. Dass die Voreinstellung ENCRYPTED_ONLY=0 lautet, macht das zu einer bewussten Entscheidung, nicht zu einem Automatismus.

Sie wollen Fernwartung, bei der die Verbindung nicht über fremde Server läuft? Ich richte einen eigenen Fernwartungs-Server mit eigenem Schlüssel ein, sauber abgeschottet und dokumentiert. Wie ich laufende Betreuung aufsetze, lesen Sie unter IT-Betreuung & Managed IT, das Erstgespräch ist unverbindlich.

Alex Jabi, Jabi IT

Alex Jabi

Ich betreue IT, Informationssicherheit und Datenschutz für KMU und Praxen an der Bergstraße und im Odenwald, persönlich, dokumentiert und ohne Cloud-Zwang.

Mehr über mich
Zurück zum Blog

Passende Artikel

Alle Artikel »
RustDesk-Server: alle Stolpersteine im Überblick

RustDesk-Server: alle Stolpersteine im Überblick

Die vollständige Fallsammlung zum selbst betriebenen RustDesk-Server OSS. Zehn dokumentierte Fehlerbilder von der fehlenden UDP-Freigabe über verlorene Schlüssel bis zum Offline-Overflow, jeweils mit Symptom, Ursache, Prüfbefehl und Lösung.