Remote Desktop over Tailscale¶
Tailscale provides secure, zero-config access to your VMs from anywhere. This is the recommended approach for remote desktop access.
Why Tailscale¶
| Traditional Approach | Tailscale Approach |
|---|---|
| Port forward 3389/5900 | No port forwarding |
| Expose to internet | Never exposed |
| Complex firewall rules | Zero config |
| Dynamic DNS needed | MagicDNS built-in |
| VPN setup complexity | One command |
Architecture¶
┌──────────────────────────────────────────────────────────────┐
│ Tailscale Network │
│ │
│ ┌─────────────┐ ┌─────────────────┐ │
│ │ macOS │ │ Home Server │ │
│ │ Laptop │◄──────────────────────►│ (Host) │ │
│ │ │ WireGuard Tunnel │ │ │
│ │ 100.64.0.1 │ (direct or relay) │ 100.64.0.2 │ │
│ └─────────────┘ └────────┬────────┘ │
│ │ │
│ ┌────────▼────────┐ │
│ │ VMs │ │
│ │ VNC: 5900 │ │
│ │ RDP: 3389 │ │
│ │ SPICE: 5901 │ │
│ └─────────────────┘ │
└──────────────────────────────────────────────────────────────┘
Setup¶
Prerequisites¶
- Tailscale account (tailscale.com)
- Tailscale installed on all devices
Server Setup¶
# Install Tailscale
curl -fsSL https://tailscale.com/install.sh | sh
# Start and authenticate
sudo tailscale up
# Verify
tailscale status
macOS Client Setup¶
Or download from tailscale.com/download.
Sign in through the menu bar icon.
Find Your Tailscale Addresses¶
# On server
tailscale status
# 100.64.0.2 server user@email.com linux -
# MagicDNS hostname
tailscale status --json | jq -r '.Self.DNSName'
# server.tail-network.ts.net
Connecting to VMs¶
VNC (Linux VMs)¶
# Using MagicDNS
open vnc://server.tail-network.ts.net:5900
# Using Tailscale IP
open vnc://100.64.0.2:5900
RDP (Windows VMs)¶
In Microsoft Remote Desktop: 1. Add PC 2. PC name: server.tail-network.ts.net 3. Port: 3389 (or specify: server.tail-network.ts.net:3389) 4. Connect
SPICE¶
Firewall Configuration¶
On Host Server¶
Allow VNC/RDP only from Tailscale network:
# Allow VNC from Tailscale only
sudo ufw allow in on tailscale0 to any port 5900:5910 proto tcp
# Allow RDP from Tailscale only
sudo ufw allow in on tailscale0 to any port 3389 proto tcp
# Deny from other interfaces
sudo ufw deny 5900:5910/tcp
sudo ufw deny 3389/tcp
Verify Rules¶
VM Network Options¶
Option 1: NAT with Port Forward (Simple)¶
VMs on NAT network, forward ports from host:
# Forward host:5901 to VM:5900
sudo iptables -t nat -A PREROUTING -i tailscale0 -p tcp --dport 5901 -j DNAT --to-destination 192.168.122.10:5900
sudo iptables -A FORWARD -p tcp -d 192.168.122.10 --dport 5900 -j ACCEPT
Connect: vnc://server.tail-network.ts.net:5901
Option 2: Bridge Network (Direct Access)¶
VMs on bridged network get their own IPs:
Requires Tailscale subnet router.
Option 3: Tailscale on VMs (Best)¶
Install Tailscale in each VM:
# Inside Linux VM
curl -fsSL https://tailscale.com/install.sh | sh
sudo tailscale up
# Inside Windows VM
# Download and install from tailscale.com
Connect directly:
Subnet Router¶
Expose VM network via Tailscale subnet router.
Enable on Host¶
# Advertise VM network
sudo tailscale up --advertise-routes=192.168.122.0/24
# Enable IP forwarding
echo 'net.ipv4.ip_forward = 1' | sudo tee /etc/sysctl.d/99-tailscale.conf
sudo sysctl -p /etc/sysctl.d/99-tailscale.conf
Approve in Admin Console¶
- Open Tailscale Admin Console
- Find server, click "..."
- Edit route settings
- Approve 192.168.122.0/24
Connect to VMs¶
Works from any Tailscale client.
Performance Optimization¶
Check Connection Type¶
Direct Connection¶
Direct connections are faster: - Same network: Always direct - Different networks: Usually direct via UDP hole punching - Restrictive NAT: May relay through Tailscale DERP servers
Optimize for Relayed Connections¶
If relayed, reduce bandwidth: - Lower color depth - Reduce resolution - Increase compression
Access Control¶
Tailscale ACLs¶
Restrict who can access which VMs:
{
"acls": [
{
"action": "accept",
"src": ["group:admins"],
"dst": ["server:*"]
},
{
"action": "accept",
"src": ["user@email.com"],
"dst": ["server:5900", "server:3389"]
}
]
}
Per-VM Access¶
With Tailscale on each VM:
{
"acls": [
{
"action": "accept",
"src": ["group:developers"],
"dst": ["dev-vm:5900"]
},
{
"action": "accept",
"src": ["group:qa"],
"dst": ["qa-vm:3389"]
}
]
}
Troubleshooting¶
Cannot Connect¶
# Check Tailscale is connected
tailscale status
# Verify route to server
tailscale ping server
# Check if direct or relayed
tailscale netcheck
Connection Times Out¶
- Verify VNC/RDP service running on host
- Check firewall allows tailscale0
- Verify VM is running and accessible from host
Slow Performance¶
- Check if relayed:
tailscale status - If relayed, check UDP ports open (41641)
- Reduce quality settings in client
- Check for network congestion
MagicDNS Not Resolving¶
# Check DNS status
tailscale status
# Verify MagicDNS enabled
# In Tailscale Admin Console > DNS
# Test resolution
nslookup server.tail-network.ts.net
Example Configurations¶
Single VM Server¶
Server (100.64.0.2) - Tailscale installed
└── Windows VM (NAT, port forward 3389)
From macOS:
MS Remote Desktop → server.tail-network.ts.net:3389
Multi-VM Lab¶
Server (100.64.0.2) - Tailscale + Subnet Router
├── Linux Dev (192.168.122.10:5900)
├── Windows Work (192.168.122.11:3389)
└── Linux Test (192.168.122.12:5900)
From macOS:
VNC → 192.168.122.10:5900 (via subnet route)
RDP → 192.168.122.11:3389 (via subnet route)
Enterprise Style¶
Each VM has Tailscale installed:
├── dev-vm.tail-network.ts.net:5900
├── windows-vm.tail-network.ts.net:3389
└── test-vm.tail-network.ts.net:5900
ACLs control access per user/group