VPS Remote Desktop — Setup & Maintenance
Deploy a headless Ubuntu VPS with a browser-accessible XFCE desktop over noVNC, secured with Tailscale. Designed for non-technical users who interact via Telegram but occasionally need desktop access.
Architecture
User's browser → Tailscale (encrypted) → noVNC (port 6080) → websockify → x11vnc → Xvfb + XFCE
User's phone → Telegram → OpenClaw gateway (port 443/polling)
Admin → Tailscale → SSH (port 2222)
Prerequisites
- Ubuntu VPS (22.04 or later, 2+ cores, 4GB+ RAM, tested on OVH)
- SSH access
- Tailscale account (free tier: 100 devices, 3 users)
- Domain or static IP (optional)
Initial Setup
Run all commands via SSH as the default user (e.g. ubuntu).
1. System Update + Core Packages
sudo apt update && sudo apt upgrade -y
sudo apt install -y python3 python3-pip python3-venv git curl
2. Node.js
curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash -
sudo apt install -y nodejs
3. Security Hardening
# Firewall
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow 2222/tcp # SSH (non-standard port)
sudo ufw allow 3389/tcp # RDP (optional, can remove later)
sudo ufw enable
# Change SSH port
sudo sed -i 's/#Port 22/Port 2222/' /etc/ssh/sshd_config
# Ubuntu 24.04+ uses socket activation — override it:
sudo systemctl edit ssh.socket
# Add between comment blocks:
# [Socket]
# ListenStream=
# ListenStream=0.0.0.0:2222
# ListenStream=[::]:2222
sudo systemctl daemon-reload
sudo systemctl restart ssh.socket
sudo systemctl restart sshd
# Disable root login
sudo sed -i 's/#PermitRootLogin yes/PermitRootLogin no/' /etc/ssh/sshd_config
sudo sed -i 's/PermitRootLogin yes/PermitRootLogin no/' /etc/ssh/sshd_config
sudo systemctl restart sshd
# Auto security updates
sudo apt install -y unattended-upgrades
sudo dpkg-reconfigure -plow unattended-upgrades
# Fail2ban (SSH + RDP)
sudo apt install -y fail2ban
Create /etc/fail2ban/jail.local:
[sshd]
enabled = true
port = 2222
maxretry = 3
bantime = 3600
findtime = 600
[xrdp]
enabled = true
port = 3389
filter = xrdp
logpath = /var/log/xrdp.log
maxretry = 3
bantime = 3600
findtime = 600
Create /etc/fail2ban/filter.d/xrdp.conf:
[Definition]
failregex = .*FAILED LOGIN.*client_ip=<HOST>
ignoreregex =
sudo systemctl enable fail2ban
sudo systemctl start fail2ban
4. Desktop Environment (XFCE + noVNC)
sudo apt install -y xfce4 dbus-x11 xvfb x11vnc novnc websockify
Set VNC password:
mkdir -p ~/.vnc
x11vnc -storepasswd
Install Chrome (works best in virtual display):
wget -q -O /tmp/chrome.deb https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb
sudo apt install -y /tmp/chrome.deb
Launch Chrome inside noVNC terminal with: google-chrome --no-sandbox &
5. Systemd Service (auto-start on boot)
Create /etc/systemd/system/vnc-desktop.service:
[Unit]
Description=VNC Desktop (Xvfb + XFCE + x11vnc + noVNC)
After=network.target
[Service]
Type=simple
User=ubuntu
Environment=HOME=/home/ubuntu
Environment=DISPLAY=:1
ExecStart=/bin/bash -c 'Xvfb :1 -screen 0 1920x1080x24 & sleep 2 && DISPLAY=:1 dbus-launch --exit-with-session startxfce4 & sleep 3 && x11vnc -display :1 -forever -rfbauth /home/ubuntu/.vnc/passwd -rfbport 5901 & websockify --web /usr/share/novnc 6080 localhost:5901'
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
Note: Replace User=ubuntu and HOME=/home/ubuntu with the actual username if different.
sudo systemctl daemon-reload
sudo systemctl enable vnc-desktop
sudo systemctl start vnc-desktop
6. Fix DNS (Ubuntu 25.04+)
sudo mkdir -p /etc/systemd/resolved.conf.d
sudo tee /etc/systemd/resolved.conf.d/dns.conf > /dev/null << 'EOF'
[Resolve]
DNS=8.8.8.8 8.8.4.4
EOF
sudo systemctl restart systemd-resolved
7. Tailscale (encrypted remote access)
curl -fsSL https://tailscale.com/install.sh | sh
sudo tailscale up
# Open the auth URL in browser, sign in
tailscale ip -4 # Note the 100.x.x.x IP
Lock down noVNC to Tailscale only:
sudo ufw delete allow 6080/tcp
Access desktop: http://100.x.x.x:6080/vnc.html
8. OpenClaw
Install OpenClaw:
sudo npm install -g openclaw
openclaw --version
Full VPS setup (user systemd fix, gateway token, gateway service install/start, SSH tunnel for dashboard, Telegram pairing):
references/openclaw-setup.md
Systemd service reference (legacy/low-level):
references/openclaw-service.md
9. (Optional) Install gog (Google Workspace CLI) on the VPS
If the user will need Gmail/Calendar/Drive automation from the VPS, install and authenticate gog.
- Steps:
references/gogcli.md
Maintenance Commands
Service Management
# Desktop service
sudo systemctl status vnc-desktop
sudo systemctl restart vnc-desktop
sudo systemctl stop vnc-desktop
sudo journalctl -u vnc-desktop --since "10 minutes ago"
# OpenClaw gateway
openclaw gateway status
openclaw gateway restart
# Tailscale
tailscale status
sudo tailscale up # re-authenticate if needed
Fail2ban
sudo fail2ban-client status sshd
sudo fail2ban-client status xrdp
sudo fail2ban-client set sshd unbanip 1.2.3.4 # unban IP
sudo fail2ban-client set xrdp unbanip 1.2.3.4
System Updates
sudo apt update && sudo apt upgrade -y
sudo reboot # if kernel updated
Disk Space
df -h
sudo apt autoremove -y
sudo journalctl --vacuum-size=100M
User Management
sudo adduser newuser
sudo usermod -aG sudo newuser
sudo passwd newuser
Troubleshooting
| Symptom | Fix |
|---|---|
| noVNC black screen | sudo systemctl restart vnc-desktop |
| Browser not loading pages | Check DNS: sudo systemctl restart systemd-resolved |
| Chrome won't launch | Run with DISPLAY=:1 google-chrome --no-sandbox & |
| VNC wrong password | x11vnc -storepasswd then restart vnc-desktop |
| SSH connection refused | Check port: ss -tlnp | grep 2222 |
| Locked out (fail2ban) | Use OVH KVM console to unban |
| Desktop not starting on reboot | sudo systemctl enable vnc-desktop |
| Tailscale disconnected | sudo tailscale up and re-auth |
SSH locked out by fail2ban (can't reach port 2222)
Symptoms: SSH connection refused or timed out, but VPS pings fine. noVNC still works.
Diagnosis:
- Connect via noVNC (Tailscale IP, port 6080) — fail2ban doesn't affect this
- Open terminal in noVNC and run:
sudo fail2ban-client status sshd - Check if your IP is in the banned list
Fix:
sudo fail2ban-client set sshd unbanip <YOUR_IP>
If fail2ban hangs (unban command stuck >15s):
sudo systemctl restart fail2ban
This clears all bans and restarts clean.
Prevention: If you're getting banned repeatedly (e.g. from automated SSH attempts by Vito/agents), consider whitelisting your IP:
# Add to /etc/fail2ban/jail.local under [DEFAULT]:
ignoreip = 127.0.0.1/8 ::1 <YOUR_STATIC_IP>
sudo systemctl restart fail2ban
Security Summary
| Layer | Protection |
|---|---|
| Firewall (ufw) | Only SSH (2222) open publicly |
| SSH | Non-standard port, no root, fail2ban |
| Desktop (noVNC) | Tailscale-only, VNC password |
| RDP (optional) | Fail2ban, can be disabled |
| Updates | Automatic via unattended-upgrades |
| Network | OVH DDoS protection (built-in) |
| VPN | Tailscale WireGuard tunnel |
Mac Client Access (for end user)
- Install Tailscale from App Store, log in with same account
- Open browser:
http://100.x.x.x:6080/vnc.html - Enter VNC password
- No other software needed
Prevent Sleep (if running on iMac instead of VPS)
sudo pmset -a sleep 0
sudo pmset -a disablesleep 1
sudo pmset -a autorestart 0
