# Quick Browser-Based Remote Desktop (x11vnc + noVNC) Lightweight alternative to Sunshine/Moonlight when you need to view the desktop in a laptop browser — no client install, no pairing, zero config beyond apt packages. Useful for quick admin tasks, one-off desktop viewing, or when Moonlight isn't available on the client. ## When to use - View the desktop from a laptop browser (Chrome, Firefox, Safari) - No client software allowed/available on the remote machine - Quick one-off access — don't need persistent pairing or low-latency game streaming - User says "I need to see my desktop in my browser" ## Setup (one-time) ```bash sudo apt-get install -y x11vnc websockify novnc ``` ## Launch (run each time) ```bash # 1. Kill any stale processes from previous runs pkill x11vnc 2>/dev/null pkill websockify 2>/dev/null sleep 1 # 2. Share the existing display via VNC (no password, shared) # -noxdamage fixes black screen with noVNC # -scale 1920x1080 downsamples 4K for browser performance x11vnc -display :0 -forever -shared -nopw -noxdamage -scale 1920x1080 & # 3. Use the official noVNC launcher (handles websockify bridge internally) /usr/share/novnc/utils/novnc_proxy --listen 6800 --vnc localhost:5900 --web /usr/share/novnc & ``` **IMPORTANT:** Using the official `novnc_proxy` launcher is preferred over raw `websockify`. It starts its own internal websockify, serves noVNC files, and handles the WebSocket handshake correctly. It serves `vnc.html` (the full noVNC client) at the root, not just `vnc_lite.html`. ## Verify ```bash # x11vnc listening (port 5900) ss -tlnp | grep 5900 # novnc_proxy listening (port 6800, 0.0.0.0 = accessible from LAN) ss -tlnp | grep 6800 # noVNC serving curl -s -o /dev/null -w "%{http_code}" http://localhost:6800/vnc.html # Expect: 200 ``` ## Client URL Open in laptop browser: ``` http://:6800/vnc.html ``` The `novnc_proxy` launcher auto-fills the WebSocket connection parameters — no query params needed. Example: `http://192.168.50.98:6800/vnc.html` ## Teardown ```bash pkill x11vnc pkill websockify pkill -f novnc_proxy ``` ## Pitfalls - **UFW blocks port 6800 by default.** If the client browser says "site can't be reached," open the port: `sudo ufw allow 6800/tcp`. - **Black screen in noVNC.** If noVNC connects but shows only black (no desktop), first check whether it's a VNC encoding issue or the GPU framebuffer itself is black. Take an X11 screenshot to distinguish: `DISPLAY=:0 xwd -root -out /tmp/screen.xwd && convert /tmp/screen.xwd /tmp/screen.png`. If the screenshot is all-black (tiny file, ~1.3KB for any resolution), the GPU isn't rendering anything — check DRM connector state: `for c in /sys/class/drm/card*-HDMI-*/; do echo "$(basename $c): $(cat $c/enabled) dpms=$(cat $c/dpms)"; done`. If `enabled=disabled` and `dpms=Off`, the display is in a kernel-level DPMS lockup and only a reboot will fix it (see `references/debug-black-screen.md` for full workflow). If the screenshot shows the desktop but noVNC shows black, it's a VNC encoding issue — add `-noxdamage` to x11vnc. XDamage can fail to track on 4K displays and with compositing enabled. - **4K display kills browser performance.** Streaming a native 4K (3840x2160) framebuffer over noVNC is extremely heavy for the browser. Always downsample with `-scale 1920x1080` (or `-scale 1280x720` for slower connections). The x11vnc `-scale` flag handles this server-side. - **Use novnc_proxy, not raw websockify.** The Debian `novnc` package includes `/usr/share/novnc/utils/novnc_proxy` — a wrapper script that manages websockify internally, serves the full `vnc.html` client, and handles auto-connect better than the raw `websockify --web=...` command. - **websockify binds 0.0.0.0 by default** — accessible from LAN. No auth on this setup; only use on trusted networks. - **x11vnc -nopw means NO password.** Anyone on the LAN can connect to port 5900 directly. Acceptable for quick local use; don't leave running. - **Contrasts with Sunshine/Moonlight:** This is pure software encode (no NVENC), higher latency, higher CPU usage. Fine for desktop viewing; terrible for gaming.