VPS Tutorials
Self-Host a RustDesk Remote Desktop Relay Server on a VPS (2026): hbbs/hbbr, Docker Compose, Ports and Security Configuration
This tutorial is for users who want to replace the RustDesk public servers with a self-hosted relay. You will learn how to deploy hbbs and hbbr on a VPS with Docker Compose, open the required ports such as 21115-21117, configure the client ID/Relay Server and Key, and handle firewalls, key backups, latency, connection failures and security exposure issues.

Self-Host a RustDesk Remote Desktop Relay Server on a VPS (2026): hbbs/hbbr, Docker Compose, Ports and Security Configuration
RustDesk is easy to use, but many people hit a wall once they actually start relying on it: the public servers are sometimes unstable, remote connection latency fluctuates, file transfers are slow, and occasionally you simply cannot connect.
The most typical scenario I have seen: a Windows desktop at home, a laptop at the office, and RustDesk installed on a phone too. Remotely checking files and helping family members with computer problems is quite convenient. But in the evening, once the public relay slows down, dragging the mouse feels like moving through glue.
This is where self-hosting RustDesk Server makes sense.
It does not move the entire remote desktop program onto the VPS. Instead, it runs two services on the VPS:
hbbs: the ID / rendezvous / signaling server, responsible for device discovery and hole-punching coordinationhbbr: the relay server, responsible for forwarding traffic when a direct connection fails
Simply put: the client is still installed on your computers and phones, and the VPS only acts as "middle coordination and fallback relay". If you have a VPS with decent networking, self-hosting is usually more controllable than public servers.
It suits these cases:
- You frequently use RustDesk to remotely access your own computers.
- You do not want to depend on the default public servers.
- You have multiple devices that need long-term remote maintenance.
- You want the relay node closer to you, for example Hong Kong, Japan, Singapore or the US West Coast.
- You can accept opening a few RustDesk-specific ports.
It does not suit these cases:
- You only occasionally help a friend remotely once.
- You have no public VPS and only want to run it on a home NAS.
- You cannot open UDP ports.
- You expect complete accounts, permissions, auditing and team management like a commercial remote control product.
If you only need temporary remote control, using the default RustDesk servers is simpler. The value of self-hosting is: stability, controllability and more predictable latency.
The easiest place to go wrong with RustDesk Server is the ports.
According to the official documentation, the OSS self-hosted service mainly involves these ports:
| Service | Port | Protocol | Purpose |
|---|---|---|---|
| hbbs | 21115 | TCP | NAT type test |
| hbbs | 21116 | TCP / UDP | ID registration, heartbeat, hole punching, connection coordination |
| hbbr | 21117 | TCP | Relay service |
| hbbs | 21118 | TCP | Web Client support, optional |
| hbbr | 21119 | TCP | Web Client support, optional |
If you do not use the Web Client, the core ports are:
TCP: 21115, 21116, 21117
UDP: 21116
21118 and 21119 are not required ports for the desktop client; they are mainly related to the Web Client. When you first start troubleshooting, you can open the full set of ports first, and tighten them according to actual needs once everything works.
RustDesk Server does not consume much CPU or memory, but it does consume network quality.
Minimum configuration:
| Scenario | Recommended configuration |
|---|---|
| Personal remote desktop | 1 vCPU / 512MB-1GB RAM / 10GB SSD |
| Home multi-device | 1 vCPU / 1GB RAM / 20GB SSD |
| Shared by multiple people, frequent relaying | 2 vCPU / 2GB RAM / 40GB SSD |
What really matters is:
- The latency from the VPS to your location.
- Whether it is stable during evening peak hours.
- Whether the upload and download bandwidth is sufficient.
- Whether UDP works properly.
- Whether the traffic quota is enough.
If you mainly remotely access a home computer from mainland China, Hong Kong, Japan, Singapore and the US West Coast are usually more suitable than Europe. European VPSs are very cheap, but once remote control latency is high, mouse movement becomes very uncomfortable.
This article assumes:
- Ubuntu 22.04 / 24.04 or Debian 12.
- Docker and Docker Compose are already installed.
- You have an externally accessible domain, for example
rustdesk.example.com, or you can use the VPS public IP directly. - The firewall and cloud provider security group are configurable.
Confirm Docker:
docker version
docker compose version
Create the directory:
sudo mkdir -p /opt/rustdesk-server
sudo chown -R "$USER":"$USER" /opt/rustdesk-server
cd /opt/rustdesk-server
mkdir -p data
The data directory is important; it stores the keys generated by RustDesk Server. If this directory is lost, the Key configured in the clients will no longer match, and you will have to reconfigure all devices later.
Create docker-compose.yml:
nano docker-compose.yml
Write the following content, replacing rustdesk.example.com with your public domain or VPS public IP. Do not use a container name, an internal hostname, or an address that only resolves on the server itself; the client must be able to reach it from the external network.
services:
hbbs:
image: rustdesk/rustdesk-server:1.1.15
container_name: hbbs
command: hbbs -r rustdesk.example.com:21117
volumes:
- ./data:/root
ports:
- "21115:21115"
- "21116:21116"
- "21116:21116/udp"
- "21118:21118"
depends_on:
- hbbr
restart: unless-stopped
hbbr:
image: rustdesk/rustdesk-server:1.1.15
container_name: hbbr
command: hbbr
volumes:
- ./data:/root
ports:
- "21117:21117"
- "21119:21119"
restart: unless-stopped
There are several key points here:
hbbs -r rustdesk.example.com:21117tells the client the relay server address../data:/rootis used to persist the keys.21116requires both TCP and UDP.hbbsandhbbrshare the samedatadirectory.- The example pins
rustdesk/rustdesk-server:1.1.15; when upgrading later, you can check Docker Hub / GitHub Release first and then manually change the version number.
If you use a bare IP, you can also write:
command: hbbs -r 1.2.3.4:21117
The advantage of a domain is that when you change VPS later, you only need to change DNS and do not have to re-enter the IP on every client.
Run:
docker compose up -d
Check the containers:
docker compose ps
View the logs:
docker compose logs -f --tail=100
Normally, hbbs will generate a set of keys. You can read the files directly:
ls -l data
cat data/id_ed25519.pub
You can also find the Key in the logs:
docker logs hbbs 2>&1 | grep -i key
The Key that clients need to fill in later is usually the content of id_ed25519.pub.
If UFW is enabled on the VPS:
sudo ufw allow 21115/tcp
sudo ufw allow 21116/tcp
sudo ufw allow 21116/udp
sudo ufw allow 21117/tcp
sudo ufw allow 21118/tcp
sudo ufw allow 21119/tcp
sudo ufw reload
If you are sure you do not use the Web Client, you can leave 21118 and 21119 closed. But during the beginner troubleshooting stage, opening the full set of ports is simpler; tighten them once you confirm connectivity.
Do not forget the security group in the cloud provider console. Some people configure ufw allow correctly inside the VPS, but the cloud console still blocks it, and they end up unable to connect.
Check the listening ports:
ss -lntup | grep 211
You should see ports such as 21115, 21116 and 21117.
Open the RustDesk client:
Settings -> Network -> ID/Relay Server
Common ways to fill it in:
ID Server: rustdesk.example.com
Relay Server: rustdesk.example.com
API Server: 留空
Key: 粘贴 data/id_ed25519.pub 的内容
If you do not have a domain, fill in the VPS public IP. Here you must fill in a public address that the client can reach; do not fill in hbbs, localhost, 127.0.0.1 or a Docker internal network address.
Both devices must be filled in with the same server and Key. After filling them in, restart the RustDesk client or disconnect and reconnect.
If the configuration succeeds, the client usually shows a normal server connection status at the bottom. Then use one device to connect to the other for testing.
RustDesk uses a direct connection when possible and only goes through the relay when a direct connection fails. The self-hosted server's hbbs first coordinates hole punching, and forwards through hbbr after that fails.
You can determine this in several ways:
- Look at the client connection information.
- Check whether the
hbbrlogs contain connection records. - Observe whether VPS traffic rises noticeably during remote control.
- Use
iftopornloadto watch traffic on port 21117.
Install nload:
sudo apt update
sudo apt install -y nload
nload
If VPS outbound traffic increases noticeably during remote control, it is very likely going through the relay.
This also reminds you: if you frequently relay large file transfers, VPS traffic will be consumed quickly. Remote desktop itself is fine; file transfers and high-resolution screens are what really consume traffic.
The core RustDesk ports are not ordinary HTTP services, so you cannot just reverse_proxy 127.0.0.1:21117 them like a website and be done.
If you are only deploying OSS RustDesk Server, it is recommended to open the core ports 21115-21117 directly and not force an ordinary HTTP reverse proxy on them.
The optional 21118, 21119 and Web Client scenarios are where WebSocket / HTTPS proxying comes in. Most individual users do not need to touch it at first; getting the desktop client working is more important.
If your network only allows outbound 443, RustDesk also has a more complex 443 solution, but that is no longer an entry-level deployment. This article first covers the most stable and easiest-to-troubleshoot standard port approach.
This is very important.
Back up the data directory:
cd /opt/rustdesk-server
mkdir -p /opt/backups/rustdesk-server
tar czf /opt/backups/rustdesk-server/rustdesk-server-$(date +%F-%H%M).tar.gz data docker-compose.yml
The safest approach is to back up the entire data directory. At minimum, keep the private key file:
data/id_ed25519
data/id_ed25519.pub is the public key that clients fill in, which is important, but what really determines the server identity is the id_ed25519 private key. If the private key is lost, the server regenerates a new set of keys, the Key originally filled in by clients becomes invalid, and you have to reconfigure every device. That is fine with a few devices, but very annoying with a dozen or more.
It is recommended to sync the backup to a second location, such as another VPS, a NAS, object storage or an encrypted cloud drive.
Back up before upgrading:
cd /opt/rustdesk-server
tar czf /opt/backups/rustdesk-server/before-upgrade-$(date +%F-%H%M).tar.gz data docker-compose.yml
Then check for a new version and modify the image tag in docker-compose.yml, for example from 1.1.15 to a new stable version.
Pull the new image:
docker compose pull
docker compose up -d
View the logs:
docker compose logs -f --tail=100
After upgrading, actually connect once with two devices; do not just assume everything is fine because the container is Up.
I do not recommend using latest long-term in a tutorial. It is fine for personal testing for convenience, but for production use, pinning a version is more stable and easier to roll back if something goes wrong.
First check the containers:
docker compose ps
docker compose logs --tail=100
Then check the ports:
ss -lntup | grep 211
Then check both layers of firewall:
- The VPS system firewall, such as UFW.
- The cloud provider security group.
Many times the problem is not RustDesk, but UDP 21116 not being opened.
This usually means signaling works but direct connection or relay has a problem.
Focus on checking:
- Whether
21117/tcpis open. - Whether the public domain/IP in
hbbs -ris written incorrectly. - Whether the client Relay Server is filled in correctly.
- Whether the Key matches the server.
Read the server public key again:
cat /opt/rustdesk-server/data/id_ed25519.pub
Confirm that there are no extra spaces, line breaks or missing characters when pasting into the client.
If you deleted the data directory before, the keys may have changed. In that case you must update the Key on all clients.
First determine whether it is going through the relay. If both ends can connect directly, the VPS only handles coordination and the speed mainly depends on the networks at both ends; if it goes through the relay, the speed is affected by the VPS bandwidth and route.
You can try:
- Switch to a VPS region closer to you.
- Test outside evening peak hours.
- Check whether the VPS is being rate-limited.
- Lower the RustDesk image quality and frame rate.
- Do not transfer large files while remote controlling.
Remote desktop is most sensitive to jitter. Low latency does not necessarily mean a good experience; stability matters more.
First check whether the data directory still exists:
ls -l /opt/rustdesk-server/data
If id_ed25519.pub has changed, it means the keys were regenerated. Most likely you did not mount the persistent directory correctly, or you missed data during migration.
When restoring, prioritize restoring the entire data directory, especially the id_ed25519 private key. Holding only the old .pub public key cannot restore the server identity.
RustDesk Server itself exists to let clients find each other; it is not a traditional backend system, but you should not ignore security entirely.
Recommendations:
- Do not expose VPS root password login.
- Only open the ports you need in the firewall.
- When not using the Web Client, do not open 21118/21119.
- Update Docker images and system patches promptly.
- Back up the
datakey directory, especially theid_ed25519private key. - Do not send the server private key to others.
- Enable strong passwords and connection confirmation on clients.
- Do not give strangers long-term unattended access.
If you use it for family or a team, it is best to agree in advance: which devices allow unattended access and which devices must be manually confirmed. Remote desktop tools are genuinely convenient, but granting the wrong permissions is genuinely dangerous.
Check once before formal use:
- The
hbbsandhbbrcontainers are both running. -
21115/tcp,21116/tcp,21116/udp,21117/tcpare open. - If using the Web Client,
21118/tcp,21119/tcpare handled; if not, keep them closed. -
hbbs -ris filled with a public domain or VPS public IP that clients can access. - The client ID Server, Relay Server and Key are all filled in.
- The entire
datadirectory is backed up, especially thedata/id_ed25519private key. - An actual connection test between two devices has passed.
- File transfer and unattended access are tested as needed.
- VPS traffic and bandwidth are sufficient.
If you only remote in occasionally, the default RustDesk public servers are enough.
If you frequently remotely access your own computers, NAS or family computers, or you do not want to leave connection quality to public servers, self-hosting RustDesk Server is well worth it. It does not have high VPS requirements; what really matters is the network route, port opening and key backup.
My advice: first run it on a cheap but stable-route VPS and test for 3-5 days. If remote control is smooth even during evening peak hours, then gradually switch your home and office devices over. Do not change all devices at once; verify first, then migrate.