Dave Kempe e79883224f RDP: default to NTLM + persist Connections tree state
### RDP NTLM default

New [rdp] config section with default_auth_pkg. The resolver in
session.rs walks entry value -> config default -> hardcoded "ntlm".
Kerberos/Negotiate are still selectable per-entry or via the config
override, but the default is NTLM because Kerberos needs a KDC
reachable via DNS (often over TCP) and its failure mode is a silent
RDP hang that looks exactly like an unrelated network issue.

Existing entries and Guacamole-imported entries that stored
auth_pkg = None now resolve to NTLM automatically. Admins who do
run Kerberos-integrated hosts can set default_auth_pkg =
"kerberos" or "negotiate" in config.toml to restore the old
behaviour.

UI: the entry modal's NLA dropdown now says "Server default (NTLM)"
instead of "Default (negotiate)" so the behaviour matches the
label. Added an explicit "Negotiate (Kerberos first, NTLM fallback)"
option for completeness.

5 unit tests cover the resolver matrix (entry wins, empty entry
falls through, no entry falls through, empty config default falls
through, server default wins when entry is None).

### Connections tree persistence

Folder expansion state and the selected folder are now persisted
to localStorage, so reopening the page / logging back in no longer
collapses the whole tree or snaps you back to the alphabetical
first folder.

- `rustguac_connections_expanded`: {scope|path: true} map, saved
  on every toggleFolder() and on the auto-expand-on-subfolder-
  create path.
- `rustguac_connections_selected`: {scope, path}, saved on every
  selectedFolder assignment (click, new folder, new subfolder,
  delete-to-null, move entry).

On page load, loadFolders() now chains: fetch top-level folders ->
restoreExpandedTree() walks saved keys shallowest-first so deeper
paths can resolve via findFolder() after their ancestors populate
subfolderCache -> try restoring saved selection -> fall back to
the current auto-select-first behaviour only if nothing restored.

Stale keys (deleted folders, ACL-revoked folders) are dropped
opportunistically during the restore walk. Per-browser, not
per-user; try/catch wraps every storage call so private-mode / quota
errors degrade silently to the pre-persistence behaviour.
2026-04-22 16:32:37 +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-06 14:38:53 +11:00
2026-02-06 14:38:53 +11:00
2026-04-05 08:11:00 +10:00
2026-04-21 17:45:48 +10:00
2026-04-21 17:45:48 +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-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, 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
    +---> 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).
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 / OpenBao KV v2, never reach the browser
  • 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)
  • Session sharing — share tokens for read-only or collaborative access
  • 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
  • 8 built-in themes with CSS gradient backgrounds, or configure your own
  • Reports page with session analytics, history, and CSV export

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

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 13 MiB
Languages
Rust 40.7%
JavaScript 26.1%
HTML 23.8%
Shell 6%
Dockerfile 1.2%
Other 2.2%