Access your computers from any browser — no app needed.
rclient is an open-source web client for RustDesk that works with your self-hosted RustDesk relay server. Type a machine ID and password in your browser and you're in — keyboard, mouse, and live video, all without installing anything.
🌐 Live demo: rclient.linkzy.dev
(Demo connects to a real relay server in São Paulo, Brazil. You can test with your own RustDesk machine ID and password.)
RustDesk is a great open-source remote desktop tool, and running your own relay server gives you full control and low latency. But the native apps must be installed on every device you want to control from.
rclient fills that gap: once it's running on your VPS, you can connect to any of your machines from any browser — a friend's computer, a phone, a work machine where you can't install software.
Your Browser
│
│ HTTPS/WSS (Cloudflare Tunnel or your reverse proxy)
▼
rclient Web UI ──► rclient Gateway
(React + WebCodecs) (Node.js)
│
RustDesk protocol
(WebSocket, encrypted)
│
┌──────▼──────┐
│ Your VPS │
│ hbbs :21118│ ← rendezvous
│ hbbr :21119│ ← relay
└──────┬──────┘
│
Remote Machine
(RustDesk host app)
- Gateway (Node.js) — speaks the RustDesk binary protocol, handles encryption, and bridges the browser to your relay server
- Web UI (React) — renders the remote screen using the browser's built-in WebCodecs API, captures keyboard and mouse input
- A Linux VPS (1 GB RAM minimum — Oracle Cloud free tier works great)
- Docker and Docker Compose installed
- A domain name (or a free Cloudflare Tunnel for HTTPS without a static IP)
| Browser | Support |
|---|---|
| Chrome / Edge 94+ | ✅ Full |
| Firefox 130+ | ✅ Full |
| Safari 16.4+ | |
| Mobile browsers |
This guide takes you from zero to a working browser-based remote desktop. There are three parts:
The host is the computer you want to control remotely (e.g. your home PC).
- Download and install RustDesk on it
- Open RustDesk. Note your Machine ID and set a Password (the one you'll type in rclient later)
- Go to Settings → Network and configure your relay server:
- ID/Relay Server: your VPS IP or domain (e.g.
relay.yourdomain.com) - Key: the server public key (you'll get this in Step 2)
- ID/Relay Server: your VPS IP or domain (e.g.
- Make sure RustDesk is running (it can run as a background service)
💡 The host machine just needs to be on the internet and reachable via your relay server — no port forwarding required.
Skip this step if you already have a relay server running. If you're using public RustDesk servers, rclient will still work — but running your own gives you lower latency and full privacy.
On your VPS, create a working directory and compose file:
mkdir -p ~/rustdesk/data
cd ~/rustdeskCreate docker-compose.infra.yml:
version: "3"
networks:
rustdesk-net:
name: rustdesk-net
services:
hbbs:
image: rustdesk/rustdesk-server:latest
container_name: hbbs
command: hbbs
ports:
- "21115:21115"
- "21116:21116"
- "21116:21116/udp"
- "21118:21118"
volumes:
- ./data:/root
networks:
- rustdesk-net
restart: unless-stopped
depends_on:
- hbbr
hbbr:
image: rustdesk/rustdesk-server:latest
container_name: hbbr
command: hbbr
ports:
- "21117:21117"
- "21119:21119"
volumes:
- ./data:/root
networks:
- rustdesk-net
restart: unless-stoppedStart it and grab the server key:
docker compose -f docker-compose.infra.yml up -d
docker logs hbbs 2>&1 | grep "Key:"The key looks like: zJDp2iyK8zXDFZYUQxyftU+C9254fdIb3Xmngpj9DfI=
Go back to Step 1 and paste this key into RustDesk's Network → Key field on your host machine.
On your VPS (same machine as the relay, or a different one), create docker-compose.app.yml:
version: "3"
networks:
rustdesk-net:
external: true
name: rustdesk-net
services:
gateway:
image: ghcr.io/linkzy/rclient-gateway:latest
container_name: rclient-gateway
environment:
- HBBS_HOST=${HBBS_HOST:-hbbs}
- HBBS_WS_PORT=${HBBS_WS_PORT:-21118}
- HBBR_HOST=${HBBR_HOST:-hbbr}
- HBBR_WS_PORT=${HBBR_WS_PORT:-21119}
- SERVER_KEY=${SERVER_KEY}
networks:
- rustdesk-net
restart: unless-stopped
web:
image: ghcr.io/linkzy/rclient-web:latest
container_name: rclient-web
ports:
- "127.0.0.1:8080:80"
networks:
- rustdesk-net
restart: unless-stopped
depends_on:
- gatewayCreate a .env file next to it:
SERVER_KEY=your-server-key-hereStart it:
docker compose -f docker-compose.app.yml up -dThe web UI is now running on http://localhost:8080.
Browsers require HTTPS for WebCodecs to work. Two options:
Install cloudflared:
curl -L --output cloudflared.deb https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64.deb
sudo dpkg -i cloudflared.debLog in and create a tunnel:
cloudflared tunnel login
cloudflared tunnel create rclientCreate /etc/cloudflared/config.yml:
tunnel: <your-tunnel-id>
credentials-file: /root/.cloudflared/<your-tunnel-id>.json
ingress:
- hostname: rclient.yourdomain.com
service: http://localhost:8080
- service: http_status:404Add the DNS record and start:
cloudflared tunnel route dns rclient rclient.yourdomain.com
sudo cloudflared service install
sudo systemctl enable --now cloudflaredExample with Caddy:
rclient.yourdomain.com {
reverse_proxy localhost:8080
}
- Open
https://rclient.yourdomain.comin your browser - Enter the Machine ID from RustDesk on the host machine
- Enter the Password you set in RustDesk
- Click Connect
You should see the remote screen within a few seconds.
| Variable | Description | Default |
|---|---|---|
SERVER_KEY |
Server public key (base64, from hbbs logs) | required |
HBBS_HOST |
Rendezvous server hostname | hbbs |
HBBS_WS_PORT |
hbbs WebSocket port | 21118 |
HBBR_HOST |
Relay server hostname | hbbr |
HBBR_WS_PORT |
hbbr WebSocket port | 21119 |
rclient is functional and usable. On a well-located relay server (e.g. same region as your host machine):
- Keyboard/mouse input: near-instant (< 10ms perceived latency)
- Video: FPS depends on host machine performance and relay proximity. Typing and browsing are smooth.
- Latency: determined mainly by your relay server location — co-locating relay and host in the same region helps most
| Issue | Status | |---|---|---| | No audio | Planned (see Roadmap) | | No file transfer | Planned | | Single monitor only | Planned | | Clipboard sync | Planned |
See docs/TASKS.md for full status. Key items:
- Past hosts cards — after a successful connection, save the host as a card (ID, password, custom relay). Click to auto-connect.
- Demo defaults to public RustDesk servers — so random visitors can try it with their own machines
- Mobile keyboard input — on-screen keyboard overlay or device keyboard forwarding for mobile browsers
- Audio streaming — receive and play remote audio in the browser
- File transfer — upload/download files to/from the remote machine
- Multi-monitor support — switch between displays
- Clipboard sync — paste text into the remote machine
- Session auto-reconnect — reconnect automatically after network drop
- Never expose the gateway port (4000) publicly — only the
webcontainer should be public-facing. The gateway is automatically internal-only in the provided compose setup. - Use HTTPS — required for WebCodecs and important for protecting your connection password in transit.
- Passwords are never stored — rclient only uses the password during the RustDesk handshake and never logs or persists it.
rclient/
├── gateway/ ← Node.js/TypeScript backend (RustDesk protocol bridge)
│ └── src/
│ ├── proto/ ← .proto files
│ ├── rendezvous.ts ← hbbs WebSocket client
│ ├── relay.ts ← hbbr WebSocket client
│ ├── session.ts ← per-connection session (encryption, video, input)
│ └── server.ts ← WebSocket server facing the browser
├── web/ ← React/TypeScript frontend
│ └── src/
│ ├── components/ ← ConnectForm, RemoteScreen
│ ├── hooks/ ← useGateway (WebSocket connection)
│ └── video/ ← WebCodecs decoder
├── docker-compose.yml
├── docker-compose.prod.yml
└── docs/ ← Technical documentation
For contributors and AI agents, the full technical docs are in docs/:
| File | Contents |
|---|---|
docs/AI_GUIDELINES.md |
Architecture overview, coding conventions, common pitfalls |
docs/ARCHITECTURE.md |
System design, component diagram, gateway WebSocket API |
docs/PROTOCOL.md |
RustDesk protocol reference (protobuf, encryption, codecs) |
docs/KNOWN_ISSUES.md |
Confirmed bugs with root cause analysis |
- Read
docs/AI_GUIDELINES.mdfirst - Check
docs/KNOWN_ISSUES.mdbefore touchingsession.ts - Pick something from the Roadmap or Known Issues
- Open a PR
MIT