Skip to content

xulek/PyVNCServer

Repository files navigation

PyVNCServer

A feature-rich RFB/VNC server written in pure Python

Python 3.13+  MIT License  CI  Version 3.2.0


PyVNCServer is an RFC 6143-compliant VNC server that captures your desktop and streams it to any VNC viewer. It supports multiple encodings, adaptive compression, WebSocket transport for browser access via noVNC, and network-aware performance tuning -- all from a single Python package.

Highlights

Protocol & Security

  • RFB 3.3 / 3.7 / 3.8 negotiation
  • No-auth, VNC Authentication, TightVNC Security (type 16)
  • Read-only password support
  • Multi-client with configurable input arbitration

Encodings

  • Core: Raw, RRE, Hextile, Zlib, CopyRect
  • Advanced: ZRLE, Tight, JPEG
  • Experimental: H.264 (requires PyAV)
  • Adaptive per-rectangle encoder selection

Performance

  • LAN-tuned adaptive encoding with auto thresholds
  • Parallel region encoding with thread pool
  • Tile-grid incremental change detection
  • Request coalescing to reduce lag
  • Runtime capture backend failover

Platform & Transport

  • Screen capture: DXGI (dxcam), MSS, PIL fallback
  • Native cursor capture & RichCursor pseudo-encoding
  • Desktop resize (ExtendedDesktopSize)
  • WebSocket on the same port -- no websockify needed
  • Bundled noVNC web client

Quick Start

1. Install

git clone https://github.com/xulek/PyVNCServer.git
cd PyVNCServer
pip install -e .[dev]
Alternative: run without installing
# PowerShell
$env:PYTHONPATH = "src"
python -m pyvncserver --help
# Bash
PYTHONPATH=src python -m pyvncserver --help
Optional: Windows DXGI capture backend
pip install -e .[windows-capture]

Provides hardware-accelerated screen capture via Desktop Duplication API. Falls back to MSS automatically if unavailable.

2. Configure

Edit config/pyvncserver.toml -- set at least password for authentication:

[server]
host = "0.0.0.0"
port = 5900
password = "secret"

3. Run

pyvncserver serve --config config/pyvncserver.toml

4. Connect

vncviewer localhost:5900

Browser Access (WebSocket + noVNC)

PyVNCServer serves WebSocket and standard VNC on the same port -- no external proxy required.

1. Enable WebSocket in config/pyvncserver.toml:

[features]
enable_websocket = true

[websocket]
allowed_origins = ["http://localhost:8000"]

2. Start the VNC server, then serve the web client:

pyvncserver serve --config config/pyvncserver.toml
python -m http.server 8000                              # separate terminal

3. Open http://localhost:8000/web/vnc_client.html in your browser.

For production wss:// transport, terminate TLS at a reverse proxy (e.g. Nginx). See WEBSOCKET.md for details and an Nginx config example.

Configuration Reference

All settings live in config/pyvncserver.toml, organized into sections:

[server] -- Core server settings
Key Type Default Description
host str "0.0.0.0" Bind address
port int 5900 VNC port
password str "" VNC password (empty = no auth)
read_only_password str "" Optional view-only password
frame_rate int 30 Target FPS (WAN profile)
lan_frame_rate int 90 Target FPS (LAN profile)
network_profile_override str|null "lan" Force localhost, lan, wan, or auto-detect ("")
scale_factor float 1.0 Capture scaling factor
capture_backend str "auto" auto, dxcam, mss, or pil
capture_probe_frames int 0 Startup capture latency probe samples
capture_probe_warn_ms float 40.0 Probe warning threshold (ms)
max_connections int 10 Maximum simultaneous clients
client_socket_timeout float 60.0 Per-client read timeout (seconds)
input_control_policy str "single-controller" single-controller or shared
[features] -- Feature toggles
Key Default Description
enable_region_detection true Incremental update optimization
enable_metrics true Internal metrics collection
enable_request_coalescing true Drop stale framebuffer requests
enable_lan_adaptive_encoding true LAN-tuned encoder parameter adaptation
enable_websocket false WebSocket transport support
enable_tight_security true TightVNC security type 16
enable_cursor_encoding false RichCursor & PointerPos pseudo-encodings
enable_copyrect_encoding true CopyRect encoding
enable_zrle_encoding true ZRLE encoding
enable_tight_encoding true Tight encoding
enable_jpeg_encoding true JPEG encoding
enable_h264_encoding false H.264 encoding (requires PyAV)
enable_parallel_encoding true Multi-threaded region encoding
[lan] -- LAN adaptive encoding thresholds
Key Default Description
raw_area_threshold 0.10 Area ratio below which Raw is preferred
raw_max_pixels 65536 Max rectangle size eligible for Raw
zlib_area_threshold 0.08 Area ratio above which Zlib is preferred
zlib_min_pixels 8192 Min rectangle size for Zlib
zlib_compression_level 2 Zlib compression level
zlib_disable_if_request_gap_ms 1500 Disable Zlib if client request gap exceeds this
jpeg_area_threshold 0.20 Area ratio above which JPEG is preferred
jpeg_min_pixels 16384 Min rectangle size for JPEG
jpeg_quality_initial 84 Starting JPEG quality
jpeg_quality_min / max 70 / 95 Adaptive JPEG quality bounds
zrle_compression_level 3 ZRLE compression level
[websocket] -- WebSocket transport settings
Key Default Description
allowed_origins [] Allowed browser Origin values
detect_timeout 0.5 WebSocket handshake detection timeout
max_handshake_bytes 65536 Max HTTP upgrade header size
max_payload_bytes 8388608 Max inbound frame payload (8 MB)
max_buffer_bytes 16777216 Max receive buffer (16 MB)
[limits] and [logging]
Key Default Description
max_set_encodings 1024 Max SetEncodings items from client
max_client_cut_text 16777216 Max ClientCutText payload (16 MB)
encoding_threads 0 Worker threads for parallel encoding (0 = auto)
log_level "INFO" Python logging level
log_file "" Optional log file path

CLI Usage

# Start with default config
pyvncserver serve

# Start with custom config and debug logging
pyvncserver serve --config config/pyvncserver.toml --log-level DEBUG

# Run as Python module (no install required, set PYTHONPATH=src)
python -m pyvncserver serve --config config/pyvncserver.toml

Programmatic startup:

from pyvncserver import VNCServer

server = VNCServer(config_file="config/pyvncserver.toml")
server.start()

Project Structure

PyVNCServer/
├── src/
│   ├── pyvncserver/            # Packaged application (new code goes here)
│   │   ├── cli.py              # CLI entrypoint
│   │   ├── config.py           # TOML config loader
│   │   ├── app/server.py       # Main VNCServerV3 class
│   │   ├── rfb/                # Protocol layer (auth, encodings, messages)
│   │   ├── platform/           # OS integration (capture, cursor, input)
│   │   ├── runtime/            # Connection pool, network profiles, threading
│   │   ├── features/           # Clipboard, session recording, WebSocket
│   │   └── observability/      # Logging, metrics, Prometheus, profiling
│   └── vnc_lib/                # Internal implementation library
│       ├── protocol.py         # RFB protocol negotiation
│       ├── encodings.py        # Encoder implementations + EncoderManager
│       ├── screen_capture.py   # Screen capture with backend selection
│       ├── auth.py             # VNC/Tight authentication
│       └── ...                 # 20+ modules
├── config/pyvncserver.toml     # Default server configuration
├── tests/                      # 320+ pytest tests
├── benchmarks/                 # Performance measurement scripts
├── examples/                   # Demo scripts
├── web/                        # noVNC browser client
└── docs/                       # Architecture & protocol docs

Testing

# Full test suite
python -m pytest tests/ -v --tb=short

# Single test file
python -m pytest tests/test_encodings.py -v

# Single test
python -m pytest tests/test_vnc_server.py::TestClassName::test_method -v

# With coverage report
python -m pytest tests/ --cov=pyvncserver --cov=vnc_lib --cov-report=term-missing

Benchmarks

python benchmarks/benchmark_encoders.py              # Encoder throughput (Raw/Zlib/Tight/ZRLE)
python benchmarks/benchmark_screen_capture.py         # Capture backend performance
python benchmarks/benchmark_screen_capture_methods.py 20  # Comparative backend benchmark
python benchmarks/benchmark_lan_latency.py 127.0.0.1 5900 20  # Network latency

To measure real capture latency at startup, set in config:

[server]
capture_probe_frames = 12
capture_probe_warn_ms = 40.0

Security

Important: VNC authentication uses DES-based challenge-response and provides only basic protection. Traffic is not encrypted by default.

For production deployments:

  • Set a strong password in config/pyvncserver.toml
  • Run behind SSH tunneling, a VPN, or a TLS-terminating reverse proxy
  • Restrict allowed_origins for WebSocket access
  • Bind to 127.0.0.1 if only local access is needed
  • Do not expose directly to untrusted networks

Troubleshooting

No screen capture or input in Linux headless environments

pyautogui and capture backends require a graphical session. For X11:

export DISPLAY=:0

For headless servers, run Xvfb and ensure the process has display access.

Import or runtime issues with mss / Pillow

Reinstall dependencies:

pip install -r requirements.txt
Browser connects but shows nothing
  • Verify enable_websocket = true in [features]
  • Verify allowed_origins contains the origin serving the page (e.g., http://localhost:8000)
  • Serve the web client over HTTP, not file:// (ES modules require it)
  • Check that the VNC port is not blocked by a firewall

Dependencies

Package Purpose
mss Fast cross-platform screen capture
Pillow Image processing and PIL capture fallback
pyautogui Keyboard and mouse input simulation
pycryptodome DES encryption for VNC authentication
numpy Fast pixel data operations
dxcam (optional) Windows DXGI Desktop Duplication capture
PyAV (optional) H.264 encoding via FFmpeg

License

This project is licensed under the MIT License.


Built with Python 3.13+ • RFC 6143 compliant • github.com/xulek/PyVNCServer

About

VNC server implementation in pure Python

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Contributors