TrollVNC is a VNC server for iOS devices, allowing remote access and control of the device’s screen.
- Low-latency capture with scaling, frame rate control, and back-pressure.
- Optional dirty-region updates for bandwidth savings.
- Tunable scroll wheel gestures and natural direction toggle.
- UTF‑8 Clipboard sync (UltraVNC).
- Orientation sync and rotation-aware input mapping.
- Optional server-side cursor overlay.
- Classic VNC authentication with full-access and view-only passwords.
- Built-in HTTP/WebSockets for browser access (HTTPS/WSS supported).
- Enable secure WebSocket connections without pain.
- Bonjour/mDNS auto-discovery on the local network.
- Reverse VNC
- Pre-seeded configuration
- Fork this repo and run GitHub workflow “Build TrollVNC”.
- Download “TrollVNC” from Releases and install it on your iOS device.
- Configure the VNC server settings from “Settings” → “TrollVNC” or the standalone “TrollVNC” app as needed.
- Or, run the following command on iOS device or simulator:
trollvncserver -p 5901 -n "My iPhone" [options]Basic:
-p portTCP port for VNC (default:5901)-c portTCP port for client management (listening on localhost only;0disables, default:0)-n nameDesktop name shown to clients (default:TrollVNC)-vView-only (ignore input)-A secKeep-alive interval to prevent device sleep by sending harmless dummy key events; only active while at least one client is connected (15..86400,0disables, default:0)
Display/Performance:
-s scaleOutput scale factor (0 < s <= 1, default:1.0;1means no scaling)-F specFrame rate: singlefps, rangemin-max, or fullmin:pref:max; on iOS 15+ a range is applied, on iOS 14 the max (or preferred) is used-d secDefer update window in seconds to coalesce changes (0..0.5, default:0.015)-Q nMax in-flight updates before dropping new frames (0..8, default:2;0disables dropping)
Dirty detection:
-t sizeTile size for dirty-detection in pixels (8..128, default:32)-P pctFullscreen fallback threshold percent (0..100, default:0;0disables dirty detection entirely)-R maxMax dirty rects before collapsing to a bounding box (default:256)-aEnable non-blocking swap (may cause tearing).
Scroll/Input:
-W pxWheel step in pixels per tick (0disables, default:48)-w k=v,..Wheel tuning keys:step,coalesce,max,clamp,amp,cap,minratio,durbase,durk,durmin,durmax-NNatural scroll direction (invert wheel delta)-M schemeModifier mapping:std|altcmd(default:std)-KLog keyboard events (keysym -> mapping) to stderr
HTTP/WebSockets:
-H portEnable built-in HTTP server on port (0disables; default0)-D pathAbsolute path for HTTP document root-e filePath to SSL certificate file-k filePath to SSL private key file
Discovery:
-B on|offEnable Bonjour/mDNS advertisement for auto-discovery by viewers on the local network (default:on)
Accessibility:
-O on|offSync UI orientation and rotate output (default:on)-E on|offEnable AssistiveTouch auto-activation (default:off)-U on|offEnable server-side cursor overlay (default:off)
Notifications:
-i on|offEnable a single user notification when the first client connects (default:on)-I on|offEnable user notifications for client connect/disconnect (default:on)
Extensions:
-C on|offEnable UltraVNC UTF-8 clipboard extension (default:on)-T on|offEnable TightVNC 1.x file transfer extension (default:off)
Logging:
-VEnable verbose logging (debug only)
Help:
-hShow built-in help message
Reverse Connection:
-reverse host:portConnect out to a listening VNC viewer (TightVNC/UltraVNC). IPv6 as[addr]:port.-repeater id host:portConnect out to an UltraVNC Repeater (Mode II) with numericid;host:portis the repeater’s server (invers) port (often5500).
When reverse is enabled, TrollVNC disables the local VNC port (
-p), HTTP/WebSockets (-H), and Bonjour (-B). See “Reverse VNC” below for full setup with examples.
Mouse:
- Left button: single-finger touch. Hold to drag; move updates while held.
- Right button: Home/Menu button. Press = short press; hold ≈ long press. Release ends the press.
- Middle button: Power button. Press = short press; hold ≈ long press. Release ends the press.
- Wheel: translated into short drags with coalescing/velocity; see “Wheel/Scroll Tuning”.
Keyboard:
- Standard ASCII keys, Return/Tab/Backspace/Delete, arrows, Home/End/PageUp/PageDown, and function keys F1..F24 are sent as HID keyboard usages.
- Modifier mapping (
-M):std(default): Alt -> Option; Meta/Super -> Command.altcmd(macOS): Alt -> Command; Meta -> Option; Super -> Command.
- Media/consumer keys (when the client sends XF86 keysyms):
- Brightness Up/Down -> display brightness increment/decrement
- Volume Up/Down/Mute -> volume increment/decrement/mute
- Previous / Play-Pause / Next -> previous track / toggle play-pause / next track
Touch, scroll, and button mappings respect the current rotation when
-O onis used.
AssistiveTouch Auto-Activation (-E on):
- When the first client connects, TrollVNC enables AssistiveTouch if it’s currently off; when the last client disconnects, it restores the previous state (disables it only if TrollVNC enabled it).
- Applies on device builds; no-op on the simulator.
Quick guidance on key trade-offs (latency vs. bandwidth vs. CPU/battery):
-s scale: Biggest lever for bandwidth and encoder CPU. Start at0.66–0.75for text-heavy UIs; use0.5for tight links or slow networks;1.0for pixel-perfect.-F spec: Cap preferred frame rate to balance smoothness and battery.30–60is a sensible range; on 120 Hz devices,60often suffices. On iOS 14 the max (or preferred if provided) value is used.-d sec: Coalesce updates. Larger values lower CPU/bitrate but add latency. Typical range0.005–0.030; interactive UIs prefer≤ 0.015.-Q n: Throughput vs. latency backpressure.1–2recommended.0disables dropping and can grow latency when encoders are slow.-t size: Dirty-detection tile size.32default;64cuts hashing/rect overhead on slower devices;16(or8) captures finer UI details at higher CPU cost.-P pct: Fullscreen fallback threshold. Practical25–40; higher values stick to rect updates longer.0disables dirty detection (always fullscreen).-R max: Rect cap before collapsing to a bounding box.128–512common; too high increases RFB overhead.-a: Non-blocking swap. Can reduce stalls/contension; may introduce tearing. Try if you see occasional stalls; leave off for maximal visual stability. If a non-blocking swap cannot lock clients, TrollVNC falls back to copying only dirty rectangles to the front buffer to minimize tearing and bandwidth.
Notes:
- Scaling happens before dirty detection; tile size applies to the scaled frame. Effective tile size in source pixels ≈ t / scale.
- With
-Q 0, frames are never dropped. If the client or network is slow, input-to-display latency can grow. - On older devices, prefer lowering
-sand increasing-tto reduce CPU and memory bandwidth.
By default, dirty detection is disabled because it usually has a high CPU cost. You can enable it with -P to set a fullscreen fallback threshold.
Low-latency interactive (LAN):
trollvncserver -p 5901 -n "My iPhone" -s 0.75 -d 0.008 -Q 1 -t 32 -P 35 -R 512Battery/bandwidth saver (cellular/WAN):
trollvncserver -p 5901 -n "My iPhone" -s 0.5 -d 0.025 -Q 2 -t 64 -P 50 -R 128High quality on fast LAN:
trollvncserver -p 5901 -n "My iPhone" -s 1.0 -d 0.012 -Q 2 -t 32 -P 30 -R 512Choppy network (high RTT/loss):
trollvncserver -p 5901 -n "My iPhone" -s 0.66 -d 0.035 -Q 1 -t 64 -P 60 -R 128Older devices (CPU-limited):
trollvncserver -p 5901 -n "My iPhone" -s 0.5 -d 0.02 -Q 1 -t 64 -P 40 -R 256Optional: add -a to any profile if you observe occasional stalls due to encoder contention; remove it if tearing is noticeable:
trollvncserver ... -aUse -F to set the CADisplayLink frame rate:
- Single value:
-F 60 - Range:
-F 30-60 - Full range with preferred:
-F 30:60:120
Notes:
- On iOS 15+, the full range is applied via
preferredFrameRateRange. - On iOS 14, only
preferredFramesPerSecondis available, so the max (or preferred if provided) is used.
Use -A to periodically send a harmless dummy key event to keep the device awake while clients are connected.
The scroll wheel is emulated with short drags. Fast wheel motion becomes one longer flick; slow motion becomes short drags. You can tune its feel at runtime:
-W px: Base pixels per wheel tick (0disables, default48). Larger = faster scrolls.-w k=v,...keys:step: same as-W(pixels)coalesce: coalescing window in seconds (default0.03,0..0.5)max: base max distance per gesture before clamp (default192)clamp: absolute clamp factor, final max distance = clamp × max (default2.5)amp: velocity amplification coefficient for fast scrolls (default0.18)cap: max extra amplification (default0.75)minratio: minimum effective distance vs step for tiny scrolls (default0.35)durbase: gesture duration base in seconds (default0.05)durk: gesture duration factor applied to sqrt(distance) (default0.00016)durmin: min gesture duration (default0.05)durmax: max gesture duration (default0.14)natural:1to enable natural direction,0to disable
Examples:
Smooth and slow:
trollvncserver ... -W 32 -w minratio=0.3,durbase=0.06,durmax=0.16Fast long scrolls:
trollvncserver ... -W 64 -w amp=0.25,cap=1.0,max=256,clamp=3.0More sensitive small scrolls:
trollvncserver ... -w minratio=0.5,durbase=0.055Disable wheel entirely:
trollvncserver ... -W 0Many VNC clients support clipboard sync, but behavior may vary. This feature is primarily supported by UltraVNC.
- UTF-8 clipboard sync is enabled by default; fallbacks to Latin-1 for legacy clients where needed.
- Starts when the first client connects and stops when the last disconnects.
- Disable it with
-C offif not desired.
When -O on is set, TrollVNC tracks iOS interface orientation and rotates the outgoing framebuffer to match (0°, 90°, 180°, 270°). Touch and scroll input are mapped into the device coordinate space with the correct axis and direction in all orientations.
TrollVNC does not draw a cursor by default; most VNC viewers render their own pointer. If your viewer expects the server to render a cursor, enable it with -U on.
Classic VNC authentication can be enabled via environment variables:
TROLLVNC_PASSWORD: full-access password. Enables VNC auth when set.TROLLVNC_VIEWONLY_PASSWORD: optional view-only password. When present, clients authenticating with this password can view but cannot send input.
Examples:
export TROLLVNC_PASSWORD=editpass
export TROLLVNC_VIEWONLY_PASSWORD=viewpass # optional
trollvncserver -p 5901 -n "My iPhone"Notes:
- Classic VNC only uses the first 8 characters of each password.
- You must set a password if you’re using the built-in VNC client of macOS.
-vforces global view-only regardless of password. View-only password applies per client.
TrollVNC can start LibVNCServer’s built-in HTTP server to serve a browser-based VNC client, noVNC.
- When
-His non-zero, the HTTP server listens on that port. - If
-Dis provided, its absolute path is used ashttpDir. If omitted, TrollVNC derives a defaulthttpDirrelative to the executable../share/trollvnc/webclients. - HTTP proxy CONNECT is enabled to support certain viewer flows.
Examples:
# Enable web client on port 5801 using the default web root
trollvncserver -p 5901 -H 5801
# Enable web client on port 8081 with a custom web root
trollvncserver -p 5901 -H 8081 -D /var/www/trollvnc/webclientsWSS encrypts the WebSocket transport (TLS for ws).
Prerequisites:
- A certificate (
cert.pem) and private key (key.pem) accepted by your browser. - The built‑in HTTP server enabled on some port with
-H(it also exposes the WebSocket endpoint).
Steps:
Generate or obtain a cert/key (example using a local CA on macOS).
brew install minica
minica -ip-addresses "192.168.2.100"Trust the CA: import minica.pem into your OS/browser trust store (otherwise the browser will warn).
Copy the host cert and key to the device (choose any readable path).
scp -r 192.168.2.100 [email protected]:/usr/share/trollvnc/ssl/Start TrollVNC with WSS enabled.
trollvncserver -p 5901 -H 5801 \
-e /usr/share/trollvnc/ssl/192.168.2.100/cert.pem \
-k /usr/share/trollvnc/ssl/192.168.2.100/key.pemConnect from your browser. Open the bundled web page at http://<host>:5801/. The secure endpoint will be available when -e/-k are provided.
Notes:
- The certificate must match what the browser connects to (IP or hostname/SAN).
- Self‑signed setups require trusting the CA or the specific certificate.
- Publishes a VNC service on the local network via Bonjour/mDNS (type
_rfb._tcp), using the name from-nand the port from-p. - Enabled by default. Toggle with
-B on|offor in Settings → TrollVNC → “Enable Auto-Discovery”. - Viewers on the same LAN that support Bonjour can find it automatically; otherwise connect by
ip:portshown in the app/logs.
TrollVNC can initiate an outbound connection to a listening VNC viewer or an UltraVNC repeater. This avoids opening inbound ports on the device and is helpful behind NAT/firewalls.
When reverse connection is enabled:
- The normal server listening port is disabled (equivalent to not using
-p). - The built-in HTTP server is disabled (any
-His ignored). - Bonjour/mDNS advertisement is disabled.
- Classic VNC authentication via environment variables still applies if set (see “Authentication”).
TrollVNC can connect to a viewer running in Listening mode. The viewer listens for inbound reverse connections; TrollVNC dials out.
Roles and steps:
- Start TightVNC or UltraVNC Viewer in “Listen” mode (UltraVNC: Connections → Listen mode, or Toolbar → Listen).
- Default listening port is
5500; you can change it in the viewer options. - Ensure your desktop firewall allows inbound on the chosen listening port.
-
CLI examples (use your viewer’s listening
host:port):# IPv4 trollvncserver -reverse 203.0.113.10:5500 -n "My iPhone" # IPv6 trollvncserver -reverse [2001:db8::1]:5500 -n "My iPhone"
-
Preferences (Settings → TrollVNC):
- Reverse Connection → Mode: Viewer
- Server:
host:port(e.g.,viewer.example.com:5500or[2001:db8::1]:5500)
Notes:
- Only an outbound TCP connection from the device to the viewer is required.
- If your viewer uses a custom port, specify that port in
-reverse host:portand in the Server field. - The desktop viewer shows the incoming reverse connection with the name from
-n.
TrollVNC can connect to an UltraVNC Repeater in Mode II. Both the Server (TrollVNC) and the Viewer make outbound connections to the Repeater and pair via a numeric ID.
Roles and steps:
- Deploy or start an UltraVNC Repeater that both device and viewer can reach (public, DMZ, or with NAT port forwards).
- Common defaults (may vary by setup):
- Server (invers) port:
5500 - Viewer port:
5901(sometimes5900)
- Server (invers) port:
- Make a note of the repeater’s
host:portfor the Server side (oftenhost:5500) and for the Viewer side (oftenhost:5901).
-
Choose a numeric Repeater ID (commonly up to 9 digits). Do not include
ID:— enter only the number. -
CLI example (use the repeater’s server port):
trollvncserver -repeater 12345679 repeater.example.com:5500 -n "My iPhone"12345679is the numeric Repeater ID.repeater.example.com:5500should point to the repeater’s server (invers) port. IPv6 example:-repeater 12345679 [2001:db8::1]:5500
-
Preferences (Settings → TrollVNC):
- Reverse Connection → Mode: UltraVNC Repeater
- Server:
host:server_port(e.g.,repeater.example.com:5500or[2001:db8::1]:5500) - Repeater ID: numeric (e.g.,
12345679)
Behavior when reverse is enabled: local VNC port is disabled, HTTP/WebSockets are disabled, and Bonjour/mDNS is disabled.
Optional: set TROLLVNC_REPEATER_RETRY_INTERVAL (seconds) to wait before exit if the connection fails (useful when a supervisor always restarts the process).
- UltraVNC Viewer is recommended for Mode II:
- Select “Repeater”; in “ID:12345679”, enter
ID:<your_id>(e.g.,ID:12345679). - Enter the repeater’s viewer address, e.g.,
repeater.example.com:5901. - Connect; the repeater pairs the viewer with the server using the matching ID.
- Select “Repeater”; in “ID:12345679”, enter
Notes:
- Connections are outbound from both sides; no inbound port on the iOS device is needed.
- Use the repeater’s server port for TrollVNC (
-repeater <id> host:server_port) and the viewer port for UltraVNC Viewer. - UltraVNC “Mode SSL” repeaters require special viewer/server builds; TrollVNC connects to standard (non-SSL) Mode II repeaters.
TrollVNC can be preconfigured via a bundled Managed.plist for supervised or fleet deployments where end users shouldn’t change settings.
- Create
prefs/TrollVNCPrefs/Resources/Managed.plistin the repo. - Populate it with the keys you need (see “Supported keys” below).
- Build/package the project as usual; the file is embedded into
TrollVNCPrefs.bundleautomatically. - Install the build on device. TrollVNC detects
Managed.plistat startup and applies the configured values. - Verify & expected behavior:
- “Settings” → “TrollVNC” shows a banner: “This TrollVNC instance is managed by your organization”.
- The preferences UI is effectively locked down.
- In‑app update prompts are suppressed while managed.
- Configured values take effect at startup; you don’t need equivalent CLI flags for these options.
-
Strings:
DesktopName: Desktop name shown to clientsModifierMap:std|altcmdFrameRateSpec: e.g.,"60","30-60", or"30:60:120"WheelTuning: advanced wheel tuning string, e.g.,"amp=0.25,cap=1.0,max=256,clamp=3.0"HttpDir: absolute path to HTTP doc rootSslCertFile: absolute path to TLS cert (PEM)SslKeyFile: absolute path to TLS key (PEM)- Reverse connection:
ReverseMode:viewer|repeaterReverseSocket:host:portor[ipv6]:port(preferred)- Backward-compat:
ReverseHost+ReversePort
- Authentication:
FullPassword: full-access password (first 8 chars used)ViewOnlyPassword: view-only password (first 8 chars used)
-
Numbers:
Port(1024..65535;0/<1024 is treated as invalid and falls back to 5901)KeepAliveSec(0 or 15..300; values 0..15 are treated as 0)Scale(0.1..1.0)DeferWindowSec(0..0.5)MaxInflight(0..8)TileSize(8..128)FullscreenThresholdPercent(0..100)MaxRects(1..4096)WheelStepPx(0 disables wheel; else 5..1000)HttpPort(0 disables; else 1024..65535)ReverseRepeaterID(numeric ID for UltraVNC Repeater Mode II)
-
Booleans:
Enabled,ClipboardEnabled,ViewOnly,OrientationSync,NaturalScroll,ServerCursor,AsyncSwap,KeyLogging,AutoAssistEnabled,BonjourEnabled,FileTransferEnabled,SingleNotifEnabled,ClientNotifsEnabled
Notes:
- When reverse connection is enabled via Managed.plist, behavior matches CLI reverse: local VNC port disabled, HTTP/WebSockets disabled, Bonjour disabled.
HttpDir,SslCertFile, andSslKeyFilemust be absolute paths.
Minimal preset: reverse to a listening viewer with a custom desktop name:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Enabled</key>
<true/>
<key>DesktopName</key>
<string>My iPhone</string>
<key>ReverseMode</key>
<string>viewer</string>
<key>ReverseSocket</key>
<string>203.0.113.10:5500</string>
<key>ClipboardEnabled</key>
<true/>
<key>KeepAliveSec</key>
<integer>60</integer>
</dict>
</plist>LAN example: enable built‑in HTTP client and TLS:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Enabled</key>
<true/>
<key>DesktopName</key>
<string>TrollVNC</string>
<key>Port</key>
<integer>5901</integer>
<key>Scale</key>
<real>0.75</real>
<key>FrameRateSpec</key>
<string>30:60:120</string>
<key>DeferWindowSec</key>
<real>0.012</real>
<key>MaxInflight</key>
<integer>2</integer>
<key>TileSize</key>
<integer>32</integer>
<key>FullscreenThresholdPercent</key>
<integer>35</integer>
<key>MaxRects</key>
<integer>512</integer>
<key>HttpPort</key>
<integer>5801</integer>
<key>HttpDir</key>
<string>/usr/share/trollvnc/webclients</string>
<key>SslCertFile</key>
<string>/usr/share/trollvnc/ssl/host/cert.pem</string>
<key>SslKeyFile</key>
<string>/usr/share/trollvnc/ssl/host/key.pem</string>
<key>ClipboardEnabled</key>
<true/>
<key>ViewOnly</key>
<false/>
<key>FullPassword</key>
<string>editpass</string>
<key>ViewOnlyPassword</key>
<string>viewpass</string>
</dict>
</plist>You can build TrollVNC entirely in GitHub Actions using the built-in workflow.
- Fork this repository (or enable “Actions” in your own clone).
- Go to the “Actions” tab → “Build TrollVNC” → “Run workflow”.
- Choose the branch to run on (usually main) and fill the form inputs below.
Due to a GitHub limit, the manual form exposes 10 commonly used options:
is_managed: whether to bundle aManaged.plist(managed deployment)desktop_name: display name shown to VNC clientsport: VNC TCP port (default5901)view_only: force view-only (ignore input)scale: output scale (0.1–1.0)frame_rate_spec: frame rate, e.g.60|30-60|30:60:120modifier_map: std | altcmdreverse_mode: none | viewer | repeaterreverse_socket:host:portor[ipv6]:port(for viewer or repeater server port)reverse_repeater_id: numeric ID (UltraVNC Repeater Mode II)
When is_managed is true, the workflow generates a Managed.plist from these inputs and bundles it.
You may set these repository secrets so the managed build embeds VNC passwords. If you don’t set them, the keys are omitted.
TVNC_FULL_PASSWORDTVNC_VIEWONLY_PASSWORD
Add them under: “Settings” → “Secrets and variables” → “Actions” → “New repository secret”.
In the workflow-managed build, the following keys are fixed to safe defaults:
Enabled=trueClipboardEnabled=trueSingleNotifEnabled=trueClientNotifsEnabled=trueKeepAliveSec=15OrientationSync=trueNaturalScroll=falseAutoAssistEnabled=falseServerCursor=falseBonjourEnabled=falseKeyLogging=false
For advanced tuning (HTTP/TLS, wheel tuning, dirty detection, etc.), commit your own prefs/TrollVNCPrefs/Resources/Managed.plist to the repo and leave is_managed unchecked, or extend the workflow locally.
- Each run uploads artifacts per scheme:
packages-default,packages-rootless,packages-roothide,packages-bootstrapdsym-default,dsym-rootless,dsym-roothide,dsym-bootstrap
- Download them from the run page →
Artifacts. - If you push to the
releasebranch (and the workflow runs there), a GitHub Release is created automatically with packaged files attached.
See: https://github.com/Lessica/BuildVNCServer
- libvncserver
- libjpeg-turbo
- libpng
- OpenSSL
- Cyrus SASL
- The majority of the main program
src/trollvncserver.mmwas written/generated by GitHub Copilot (GPT-5).
TrollVNC is an open-source VNC solution, licensed under GPLv2. You are free to access, use, and modify the source code. See the COPYING file for more information.
- Ready-to-use, pre-compiled builds
- Automatic updates and continuous improvements
- Priority support and troubleshooting assistance
- Sustainable development through your contribution
If you prefer, you can always build TrollVNC yourself directly from the source.
- Compile for free.
- Pay for convenience, updates, and support.
Support TrollVNC and help us keep remote access fast, secure, and evolving.