Ce tutoriel explique comment héberger son propre serveur RustDesk (hbbs + hbbr) dans un conteneur LXD, avec le script d'installation techahold/rustdeskinstall. C'est la méthode 2 de la documentation officielle.
Les adresses, noms et clés de ce tutoriel sont des exemples. Remplace-les par tes propres valeurs.
Valeurs utilisées dans ce tutoriel
| Élément | Valeur d'exemple |
|---|---|
| Hôte | serveur.example.com (Ubuntu 24.04) |
| IP publique de l'hôte | 203.0.113.10 |
| Interface réseau publique | eno1 |
| Bridge LXD | lxdbr0 – 10.10.10.1/24 |
| Conteneur | rustdesk (Debian 12) |
| IP fixe du conteneur | 10.10.10.50 |
| Dossier d'installation | /opt/rustdesk |
| Services | rustdesksignal (hbbs), rustdeskrelay (hbbr) |
| Clé publique | <CLE_PUBLIQUE> (générée à l'installation) |
| Poste client | utilisateur@poste |
Prérequis
- Un serveur avec LXD installé et initialisé (
lxd init) - Un accès SSH avec les droits sudo
- Une IP publique fixe (ou un nom de domaine qui pointe dessus)
Principe
Le conteneur est sur un réseau privé (lxdbr0). Les ports RustDesk sont redirigés depuis l'IP publique de l'hôte vers le conteneur par des proxy devices LXD en mode nat=true.
Ce mode est essentiel : il préserve l'IP réelle des clients. Le serveur ID (hbbs) en a besoin pour établir des connexions directes entre postes (hole punching). Sans lui, tout le trafic passe par le relais.
1. Connexion au serveur
utilisateur@poste:~$ ssh utilisateur@serveur.example.com
utilisateur@serveur.example.com's password:
Welcome to Ubuntu 24.04.4 LTS (GNU/Linux 6.8.0-87-generic x86_64)
utilisateur@serveur:~$
2. Création du conteneur
utilisateur@serveur:~$ lxc launch images:debian/12 rustdesk
Creating rustdesk
Starting rustdesk
utilisateur@serveur:~$ lxc list
+----------+---------+----------------------+-----------------------------------------------+-----------+-----------+
| NAME | STATE | IPV4 | IPV6 | TYPE | SNAPSHOTS |
+----------+---------+----------------------+-----------------------------------------------+-----------+-----------+
| rustdesk | RUNNING | 10.10.10.120 (eth0) | fd42:e702:d7b9:a433:216:3eff:fe1a:5683 (eth0) | CONTAINER | 0 |
+----------+---------+----------------------+-----------------------------------------------+-----------+-----------+
Le conteneur obtient d'abord une IP dynamique attribuée par le DHCP de LXD : 10.10.10.120.
3. Attribution d'une IP fixe
L'IP fixe est obligatoire pour les proxy devices en mode
nat=true.
- Repérer le sous-réseau du bridge :
utilisateur@serveur:~$ lxc network get lxdbr0 ipv4.address
10.10.10.1/24
- Lister les IP déjà utilisées pour éviter un conflit :
utilisateur@serveur:~$ lxc list -c n4
- Fixer l'IP du conteneur dans ce sous-réseau :
utilisateur@serveur:~$ lxc config device override rustdesk eth0 ipv4.address=10.10.10.50
Device eth0 overridden for rustdesk
- Redémarrer le conteneur :
utilisateur@serveur:~$ lxc restart rustdesk
- Vérification :
utilisateur@serveur:~$ lxc list rustdesk
+----------+---------+----------------------+-----------------------------------------------+-----------+-----------+
| NAME | STATE | IPV4 | IPV6 | TYPE | SNAPSHOTS |
+----------+---------+----------------------+-----------------------------------------------+-----------+-----------+
| rustdesk | RUNNING | 10.10.10.50 (eth0) | fd42:e702:d7b9:a433:216:3eff:fe1a:5683 (eth0) | CONTAINER | 0 |
+----------+---------+----------------------+-----------------------------------------------+-----------+-----------+
4. Identification de l'IP publique
utilisateur@serveur:~$ ip -4 addr show scope global
2: eno1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
altname enp4s0f0
inet 203.0.113.10/24 metric 100 brd 203.0.113.255 scope global dynamic eno1
valid_lft 78107sec preferred_lft 78107sec
18: lxdbr0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
inet 10.10.10.1/24 scope global lxdbr0
valid_lft forever preferred_lft forever
32: lxcbr0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default qlen 1000
inet 10.0.3.1/24 brd 10.0.3.255 scope global lxcbr0
valid_lft forever preferred_lft forever
L'IP publique est 203.0.113.10, sur l'interface externe eno1. Ne pas confondre avec lxdbr0 (bridge LXD) ou lxcbr0 (ancien bridge LXC, souvent inactif).
5. Redirection des ports (proxy devices LXD)
| Port | Protocole | Rôle |
|---|---|---|
| 21115 | TCP | Test NAT (hbbs) |
| 21116 | TCP + UDP | Serveur ID (hbbs) |
| 21117 | TCP | Relais (hbbr) |
Ports à ne pas rediriger :
- 21114 : API, réservée à la version Pro.
- 21118 / 21119 : WebSocket pour le client web. Exposés directement, ils permettent d'usurper l'IP source. À n'ouvrir que derrière un reverse proxy.
Sur l'hôte :
utilisateur@serveur:~$ lxc config device add rustdesk rd-tcp proxy \
listen=tcp:203.0.113.10:21115-21117 connect=tcp:10.10.10.50:21115-21117 nat=true
Device rd-tcp added to rustdesk
utilisateur@serveur:~$ lxc config device add rustdesk rd-udp proxy \
listen=udp:203.0.113.10:21116 connect=udp:10.10.10.50:21116 nat=true
Device rd-udp added to rustdesk
- Vérification :
utilisateur@serveur:~$ lxc config device show rustdesk
eth0:
ipv4.address: 10.10.10.50
name: eth0
network: lxdbr0
type: nic
rd-tcp:
connect: tcp:10.10.10.50:21115-21117
listen: tcp:203.0.113.10:21115-21117
nat: "true"
type: proxy
rd-udp:
connect: udp:10.10.10.50:21116
listen: udp:203.0.113.10:21116
nat: "true"
type: proxy
- Règles DNAT créées automatiquement par LXD :
utilisateur@serveur:~$ sudo nft list ruleset | grep 2111
ip daddr 203.0.113.10 tcp dport 21115-21117 dnat ip to 10.10.10.50
ip saddr 10.10.10.50 ip daddr 10.10.10.50 tcp dport 21115-21117 masquerade
ip daddr 203.0.113.10 udp dport 21116 dnat ip to 10.10.10.50:21116
ip saddr 10.10.10.50 ip daddr 10.10.10.50 udp dport 21116 masquerade
- Si un pare-feu ufw est actif sur l'hôte :
utilisateur@serveur:~$ sudo ufw allow 21115:21117/tcp
utilisateur@serveur:~$ sudo ufw allow 21116/udp
6. Installation de RustDesk dans le conteneur
- Entrer dans le conteneur :
utilisateur@serveur:~$ lxc exec rustdesk -- bash
root@rustdesk:~#
Une fois dans le conteneur (
root@rustdesk), les commandeslxcne sont plus disponibles.
- Installer les paquets de base :
root@rustdesk:~# apt update && apt install -y wget sudo curl
...
Setting up curl (7.88.1-10+deb12u15) ...
Processing triggers for libc-bin (2.36-9+deb12u14) ...
- Télécharger le script :
root@rustdesk:~# wget https://raw.githubusercontent.com/techahold/rustdeskinstall/master/install.sh
...
HTTP request sent, awaiting response... 200 OK
Saving to: 'install.sh'
'install.sh' saved [14210/14210]
- Rendre le script exécutable :
root@rustdesk:~# chmod +x install.sh
- Lancer l'installation :
root@rustdesk:~# ./install.sh
sudo detected and will be used.
Installing prerequisites
...
1) IP
2) DNS/Domain
Choose your preferred connection method: auto-resolve current WAN IP or enter your DNS/Domain:1
Creating /opt/rustdesk
Installing Rustdesk Server
...
Tidying up install
Grabbing installers
<CHAINE_DE_CONFIGURATION>
1) Yes
2) No
Please choose if you want to download configs and install HTTP server:2
Your IP/DNS Address is 203.0.113.10
Your public key is <CLE_PUBLIQUE>
Install Rustdesk on your machines and change your public key and IP/DNS name to the above
...
Press any key to finish install
Réponses aux questions du script :
| Question | Réponse conseillée |
|---|---|
| - Choose your preferred connection method: | |
| auto-resolve current WAN IP or enter your DNS/Domain | |
| - Méthode de connexion (IP / DNS) | 1 – IP (détection automatique de l'IP WAN), ou 2 si tu as un nom de domaine |
| - Please choose if you want to download configs and | |
| install HTTP server: | |
| - Télécharger les configs et installer le serveur HTTP | 2 – Non (évite d'exposer un service web en plus) |
Note la clé publique. Elle reste disponible dans le fichier .pub de /opt/rustdesk/.
La <CHAINE_DE_CONFIGURATION> encode l'IP et la clé. Elle peut être importée dans les clients, mais son champ api doit ensuite être effacé (voir Dépannage).
7. Vérification des services
Dans le conteneur :
root@rustdesk:~# systemctl list-units | grep -i rust
rustdeskrelay.service loaded active running Rustdesk Relay Server
rustdesksignal.service loaded active running Rustdesk Signal Server
root@rustdesk:~# ss -tulpn | grep 2111
udp UNCONN 0 0 *:21116 *:* users:(("hbbs",pid=1203,fd=7))
tcp LISTEN 0 128 *:21115 *:* users:(("hbbs",pid=1203,fd=13))
tcp LISTEN 0 128 *:21119 *:* users:(("hbbr",pid=1432,fd=10))
tcp LISTEN 0 128 *:21118 *:* users:(("hbbs",pid=1203,fd=15))
tcp LISTEN 0 128 *:21117 *:* users:(("hbbr",pid=1432,fd=9))
tcp LISTEN 0 128 *:21116 *:* users:(("hbbs",pid=1203,fd=11))
21118 et 21119 écoutent dans le conteneur mais ne sont pas redirigés depuis l'hôte : ils restent inaccessibles depuis Internet.
8. Test depuis un poste extérieur
utilisateur@poste:~$ nc -zv 203.0.113.10 21116
Connection to 203.0.113.10 21116 port [tcp/*] succeeded!
utilisateur@poste:~$ nc -zv 203.0.113.10 21117
Connection to 203.0.113.10 21117 port [tcp/*] succeeded!
9. Installation du client RustDesk
Page de téléchargement : github.com/rustdesk/rustdesk/releases
- Télécharger le client au format AppImage :
utilisateur@poste:~$ wget https://github.com/rustdesk/rustdesk/releases/download/1.5.0/rustdesk-1.5.0-x86_64.AppImage
- Rendre le fichier exécutable :
utilisateur@poste:~$ chmod +x rustdesk-1.5.0-x86_64.AppImage
- Lancer l'application :
utilisateur@poste:~$ ./rustdesk-1.5.0-x86_64.AppImage
10. Configuration des clients RustDesk
Sur chaque poste (celui qui contrôle et celui qui est contrôlé) :
-
Cliquer sur le menu « burger » en haut à droite de l'application.

-
Le menu « Paramètres » s'affiche à gauche.

- Sélectionner « Réseau ».


- Cliquer sur « Serveur ID/Relais ».

- Remplir les champs suivants :

| Champ | Valeur |
|---|---|
| Serveur ID | 203.0.113.10 |
| Clé | <CLE_PUBLIQUE> |
| Autres champs (Relais, API) | vides |
Cliquer sur Valider.
En bas de la fenêtre principale doit ensuite afficher : Succés

Pour se connecter, saisir l'ID du poste distant (celui affiché après le changement de serveur), puis son mot de passe.
11. Dépannage
Erreur Connexion refusée sur le port 21114
reqwest::Error { kind: Request, url: "http://203.0.113.10:21114/api/login-options", ...
ConnectError("tcp connect error", 203.0.113.10:21114, ... "Connexion refusée" }
Cause : le client cherche le serveur API (/api/login), qui n'existe que dans RustDesk Server Pro (comptes, carnet d'adresses, OIDC).
Solution :
- Ne pas utiliser le bouton « Se connecter » / « Login » du client. Avec le serveur OSS, on se connecte par ID + mot de passe du poste distant.
- Laisser le champ Serveur API vide, y compris après import de la chaîne de configuration.
- Ne pas ouvrir le port 21114.
Erreur Failed to connect to rs-ny.rustdesk.com:21116
WebRTC failed: Failed to connect: the target device is offline or does not exist.;
fallback failed: Failed to connect to rs-ny.rustdesk.com:21116
Cause : le client utilise encore les serveurs publics de RustDesk. La configuration n'est pas appliquée sur au moins un des deux postes.
Solution :
- Vérifier sur les deux postes que le serveur ID et la clé sont bien enregistrés, en cliquant sur Valider.
- Fermer complètement le client, puis le relancer.
- Les deux postes doivent afficher « Prêt ».
- Utiliser l'ID affiché après le changement de serveur.
12. Remarques
Garder la priorité sur sa souris pendant une session
RustDesk ne donne pas la priorité à la souris locale : la fonction existe dans le code mais elle est désactivée. Sur le poste contrôlé, on peut :
- couper ou rendre le contrôle clavier/souris en un clic, depuis l'icône dédiée de la fenêtre de connexion ;
- passer en lecture seule par défaut : Paramètres > Sécurité > Permissions, décocher « Activer le clavier/la souris ».
13. Maintenance
- Mise à jour : script
update.shdu dépôt techahold/rustdeskinstall. - Clé publique : fichier
.pubdans/opt/rustdesk/. - Redémarrer les services :
systemctl restart rustdesksignal rustdeskrelay - Consulter les journaux :
journalctl -u rustdesksignal -u rustdeskrelay -f