One-shot Bicep deployment of a self-hosted RustDesk server (hbbs + hbbr) on a small Ubuntu 24.04 VM in Azure, accessible only via Tailscale.
The VM has zero inbound exposure to the internet — no public IP, no open NSG rules. All traffic (SSH and RustDesk) flows over the Tailscale tunnel.
- Resource group (created by
deploy.sh) - VNet (10.30.0.0/16) + subnet with NAT gateway (egress only)
- NSG with no inbound allow rules (default deny)
- NAT gateway + public IP for outbound traffic only
- NIC (no public IP)
- Ubuntu 24.04 LTS VM (default
Standard_B1s, ~$8/mo) cloud-initthat:- Installs Tailscale, joins the VM to your tailnet as
rustdesk-azurewith Tailscale SSH enabled - Configures
ufwto deny all inbound except on thetailscale0interface - Installs Docker + Compose plugin
- Launches the two RustDesk containers (
hbbs,hbbr) withnetwork_mode: host, relay address auto-filled from the Tailscale IP
- Installs Tailscale, joins the VM to your tailnet as
- Azure CLI logged in (
az login) - A Tailscale account with MagicDNS enabled
- A Tailscale auth key (
tskey-auth-...) — generate one at https://login.tailscale.com/admin/settings/keys with short expiry jq(optional, used by deploy.sh to pretty-print outputs)
./deploy.shYou'll be prompted for a Tailscale auth key, or set it via env var:
TAILSCALE_AUTHKEY=tskey-auth-... ./deploy.shOverride other defaults via env vars:
LOCATION=centralus RG_NAME=rg-rustdesk-private \
VM_SIZE=Standard_B1s ./deploy.shWait ~3-5 minutes after the deployment completes for cloud-init to finish installing Tailscale + Docker and pulling the containers.
tailscale ssh azureuser@rustdesk-azure "sudo docker logs hbbs 2>&1 | grep -i 'Key:'"The exact command is printed in the deployment outputs as getKeyCommand.
Settings → Network → ID/Relay Server:
- ID Server:
rustdesk-azure(Tailscale MagicDNS) or the Tailscale IP - Relay Server: same
- Key: the value from the
hbbslogs above
The client machine must be on the same Tailscale tailnet.
- Tailscale ACLs: Restrict which devices on your tailnet can reach
rustdesk-azure. See Tailscale ACLs. - Auth key expiry: Use short-lived Tailscale auth keys. The key is only needed at first boot; the VM stays joined after the key expires.
az group delete --name rg-rustdesk-private --yes --no-wait- Data (including the generated key) lives in
/opt/rustdesk/dataon the VM. Snapshot the OS disk or back up that directory if you want it durable. - This uses the OSS server. For web console / user management, see RustDesk Server Pro.