pletch b3b2cce36e fix(rdp): reinstall the RDPGFX wrappers after a channel reconnect
The previous commit stopped guac_rdp_rdpgfx_channel_connected() from wrapping
its own wrapper, which fixed the recursion crash, but it guarded on
orig_surface_command being NULL:

    if (rdp_client->settings->enable_h264
            && rdp_client->orig_surface_command == NULL) {

orig_surface_command lives on guac_rdp_client, so it is per-connection, while
the handler it protects is per-channel-instance. FreeRDP's
gdi_graphics_pipeline_uninit() sets SurfaceCommand to NULL and
gdi_graphics_pipeline_init() assigns gdi_SurfaceCommand back
(libfreerdp/gdi/gfx.c:1864, :1911), so a reconnect restores FreeRDP's own
handler -- and the once-only guard, seeing a non-NULL orig_surface_command
from the first install, declines to wrap it again. Passthrough is then dead
for the rest of the session.

xrdp reconnects the channel at login, for the display resize the previous
commit already identified, so this fired on essentially every xrdp session.
It was silent: the surface commands still reached FreeRDP's GDI decoder and
guacd re-encoded them as JPEG/WebP, so the desktop rendered correctly at
~100% of a core while no H.264 reached the browser. A trace on xrdp 0.10.6
showed one keyframe forwarded, the channel unloading 52ms later, and no
"H.264 passthrough enabled" line after the reconnect that followed.

Guard on what is actually installed, per callback. The two are restored on
different schedules -- gdi_graphics_pipeline_init() assigns SurfaceCommand
but never touches CapsConfirm -- so after a reconnect CapsConfirm is still
ours while SurfaceCommand is FreeRDP's again. A single guard keyed on
SurfaceCommand would pass and then point orig_caps_confirm at
guac_rdp_gfx_caps_confirm itself, reaching the same stack exhaustion by the
other callback.

With this, the same host forwards 807 AVC420 deltas and 3 keyframes over 60s
of desktop use, with guacd at 3.3% of a core.
2026-09-02 23:33:58 -04:00
2026-02-06 14:38:53 +11:00
2026-02-06 14:38:53 +11:00
2026-02-06 14:38:53 +11:00
2026-02-06 14:38:53 +11:00
2026-04-05 08:11:00 +10:00
2026-08-11 11:35:09 +10:00
2026-08-11 11:35:09 +10:00
2026-02-06 14:38:53 +11:00
2026-02-06 14:38:53 +11:00
2026-02-06 14:38:53 +11:00
2026-02-07 09:32:05 +11:00

rustguac

CI Release License Docker

A lightweight Rust replacement for the Apache Guacamole Java webapp. Browser-based SSH, RDP, VNC, SPICE, Proxmox VE consoles, web browsing, and VDI desktop containers through guacd.

No Java. No Tomcat. Single binary + guacd.

Architecture

Browser (HTML/JS)
    |
    | WebSocket over HTTPS
    v
rustguac (Rust, axum)
    |
    | TLS (Guacamole protocol)
    v
guacd (C, from guacamole-server)
    |
    +---> SSH server
    +---> RDP server
    +---> VNC server
    +---> SPICE server (libvirt/QEMU displays)
    +---> Proxmox VE VM console (SPICE via the PVE spiceproxy API)
    +---> Xvnc + Chromium (web browser sessions)
    +---> Docker container + xrdp (VDI desktop sessions)

Features

Session types

Type Description
SSH Browser-based terminal with password, private key, or ephemeral keypair auth. SFTP file transfer.
RDP Windows/Linux RDP with auto-fit resize, Kerberos NLA, RemoteApp/RAIL, H.264 passthrough, GFX pipeline.
VNC Connect to any VNC server (KVM/IPMI consoles, remote desktops, VM displays).
SPICE Direct SPICE displays (libvirt/QEMU consoles) with TLS, CA verification, certificate-subject pinning, and SPICE-proxy support.
Proxmox VE VM consoles brokered through the Proxmox API. One-time SPICE tickets fetched just-in-time at connect (only the API token is stored), node auto-detected from the VM ID, and SSH-tunnel aware.
Web Headless Chromium on Xvnc with native autofill, domain allowlisting, login script automation.
VDI Ephemeral Docker desktop containers per user. Persist after disconnect, auto-cleanup on idle.

Security & authentication

  • OIDC single sign-on: Authentik, Google, Okta, Keycloak, or any OpenID Connect provider
  • 4-tier role system: admin, poweruser, operator, viewer with OIDC group mapping
  • API key auth: SHA-256 hashed keys with IP allowlists and expiry
  • Vault-backed connections: credentials in HashiCorp Vault or OpenBao KV v2, never reach the browser (see Requirements)
  • TLS everywhere: HTTPS for clients, TLS between rustguac and guacd
  • CIDR allowlists: per-protocol network restrictions for session targets
  • Per-entry clipboard control: disable copy and/or paste for data loss prevention
  • Rate limiting: per-IP, per-endpoint via tower_governor
  • Session recording: Guacamole format with playback UI, disk rotation, per-entry limits

Connectivity

  • Multi-hop SSH tunnels: chain jump hosts/bastions to reach isolated networks (all session types, including the Proxmox API and console hops)
  • Session sharing: share tokens for read-only or collaborative access
  • Headless API integration: create a session over the REST API and hand a browser a ready-to-open URL via a single-use WebSocket ticket, with no OIDC login and no API key in the browser (see Connecting to a session)
  • Encrypted file transfer: LUKS-encrypted per-session drive storage (RDP), SFTP (SSH)
  • Credential variables: shared credentials across connections entries

VDI desktop containers

  • Docker-based: one container per user, deterministic naming, BYO image
  • Persist after disconnect: reconnect to the same desktop within idle timeout
  • Logout detection: desktop logout stops the container, tab close preserves it
  • Session thumbnails: live preview in the connections, click to reconnect
  • Persistent home directories: bind-mounted user data survives container restarts
  • Per-entry resource limits: CPU, memory, idle timeout per connections entry
  • VdiDriver trait: extensible for downstream forks (Nomad, Proxmox, cloud)

UI

  • Connections with folder-based organisation and OIDC group access control
  • Active Sessions section with live thumbnail previews
  • Session ended overlay with Reconnect/Close buttons
  • Clipboard panel controls (Home + Fullscreen)
  • 8 built-in themes with CSS gradient backgrounds, or configure your own
  • Reports page with session analytics, history, and CSV export

Requirements

Component Status Notes
guacd Bundled Built from apache/guacamole-server, ships in the .deb and Docker image. No separate install.
Vault or OpenBao Required for the Connections UI Stores connection entries and credentials server-side. Without it the Connections page is unavailable and users can only run ad-hoc sessions via the API. Use contrib/vault-quickstart.sh for one-command setup (auto-detects vault or bao, supports --dev and --local modes).
OIDC provider Optional For SSO. API-key auth works on its own. Authentik/Google/Okta/Keycloak/JumpCloud all tested.
Docker Optional Only needed for VDI desktop containers.

Quick start

Debian 13 (.deb)

Pre-built packages for amd64 and arm64 are available from Releases:

sudo apt install ./rustguac_*.deb
/opt/rustguac/bin/rustguac --config /opt/rustguac/config.toml add-admin --name admin
sudo systemctl enable --now rustguac

Docker

docker pull sol1/rustguac:latest
docker run -d -p 8089:8089 sol1/rustguac:latest

For VDI support, mount the Docker socket:

docker run -d -p 8089:8089 \
  -v /var/run/docker.sock:/var/run/docker.sock \
  --group-add $(getent group docker | cut -d: -f3) \
  sol1/rustguac:latest

Other distributions

Pre-built packages are provided for Debian 13. For other distributions, build from source:

sudo ./install.sh

See the Installation guide for full details including Docker Compose, TLS setup, and development builds.

VDI setup

VDI requires Docker on the host:

curl -fsSL https://get.docker.com | sh
sudo usermod -aG docker rustguac
sudo systemctl restart rustguac

Add [vdi] to your config and create a VDI entry in the connections. See VDI Desktop Containers for image requirements and configuration.

Documentation

Getting started

Features

Integration & reference

  • Integrations: Vault, LUKS drives, SSH tunnels, Kerberos, HAProxy, Knocknoc
  • NetBox: connections sync via custom fields and webhooks
  • Security: TLS, rate limiting, headers, audit logging, hardening
  • API Reference: REST API endpoints, the session connection flow, and headless ws-ticket integration
  • Migration from Apache Guacamole: MySQL/MariaDB to Vault

Commercial support

Commercial support for rustguac is available from Sol1.

License

Apache License 2.0. See LICENSE for details.

S
Description
Lightweight Rust replacement for Apache Guacamole — browser-based SSH, RDP, VNC, SPICE/PVE and web sessions via guacd with SSH jump hosts, Kerberos NLA, Vault address book, and OIDC SSO
Readme Apache-2.0 36 MiB
Languages
Rust 42.5%
JavaScript 28.1%
HTML 21.6%
Shell 4.8%
CSS 1.3%
Other 1.7%