# 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://<server-ip>: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.
