Skip to content

Architecture

Dave Kempe edited this page Apr 26, 2026 · 1 revision

Architecture

rustguac sits between web browsers and guacd, with optional integrations on the side.

                         Browser
                            |
                            | HTTPS + WebSocket
                            v
                   +-------------------+
                   |  Reverse proxy    |  TLS termination, optional Knocknoc gating
                   |  (HAProxy etc.)   |
                   +---------+---------+
                             |
                             v
                   +-------------------+        +------------+
                   |     rustguac      | <----> |   Vault    |  KV v2 connection entries,
                   |   (Rust, axum)    |        | (OpenBao)  |  user credential variables
                   +---------+---------+        +------------+
                             |                        ^
                             | TLS                    |
                             v                        |
                       +-----------+                  |  AppRole login,
                       |   guacd   |                  |  token renewal
                       | (C daemon)|                  |
                       +-----+-----+                  |
                             |                        |
       +---------------------+---------+--------------+--------------+
       |                |              |                             |
       v                v              v                             v
   SSH server      RDP server     VNC server            Xvnc + Chromium    Docker container
                                                       (web sessions)     + xrdp (VDI)

Components

rustguac (Rust binary)

  • HTTP/HTTPS API + WebSocket endpoints (axum)
  • OIDC authentication (openidconnect crate), API key authentication
  • Session lifecycle: pending -> active -> completed -> ended
  • Vault client for connection entries and per-user credential variables
  • SQLite admin database (rusqlite, bundled): users, API keys, OIDC role mappings, audit logs, session history
  • WebSocket-to-guacd proxy with on-disk recording tee
  • Process supervision for Xvnc + Chromium (web sessions) and Docker containers (VDI)

guacd (upstream C daemon)

  • Bundled from apache/guacamole-server
  • Speaks the Guacamole wire protocol on the network side, and SSH/VNC/RDP on the target side
  • Patched for FreeRDP 3.15+ compatibility on Debian 13 (see patches/)

Browser client

  • HTML/JS served from static/
  • Uses guac-common-js (Tunnel.js, Client.js, Display.js, etc.) verbatim from upstream
  • client.html is the session page; connections.html, sessions.html, recordings.html, admin.html are the management surfaces

Optional integrations

  • HashiCorp Vault / OpenBao for connection entries (KV v2) and per-user credential variables
  • OIDC provider (Authentik, Google, Okta, Keycloak, JumpCloud, anything that speaks OIDC discovery)
  • HAProxy + Knocknoc for zero-trust gating of the login page (see Knocknoc integration)
  • Docker daemon for VDI desktop containers
  • NetBox for connection sync via custom fields and webhooks (see docs/netbox.md)

Session types

Type Browser sees guacd connects to
SSH xterm-style terminal SSH server (target)
RDP RDP desktop RDP server (target)
VNC VNC desktop VNC server (target)
Web Chromium rendering whatever URL Local Xvnc display, which is rendering Chromium
VDI RDP desktop Local Docker container running xrdp (one per user)

For web sessions, rustguac spawns Xvnc + Chromium per session, then connects guacd to that Xvnc display via VNC. Chromium runs with --user-data-dir per session for profile isolation, native autofill from Vault, and --host-rules for per-entry domain allowlisting.

For VDI sessions, rustguac asks the configured VdiDriver to start (or reuse) a container named rustguac-vdi-{username}. Bollard talks to the local Docker socket. The container exposes xrdp on port 3389 and accepts VDI_USERNAME / VDI_PASSWORD env vars. Containers persist after disconnect and are reaped after an idle timeout.

Process model

  • rustguac is one Tokio runtime, one process. axum handles HTTP, async tasks handle session proxying.
  • guacd is a separate process that rustguac connects to over TCP (loopback or unix socket).
  • Each web session has its own Xvnc + Chromium subprocess pair, supervised by rustguac.
  • Each VDI session has its own Docker container, lifecycle managed by rustguac.
  • SQLite uses WAL mode; rusqlite calls happen on tokio::task::spawn_blocking boundaries so they don't stall the runtime.

Ports

Port Service Exposure
443 Reverse proxy (HTTPS) Public, optionally gated by Knocknoc
8089 rustguac (HTTPS) Loopback only (behind reverse proxy)
4822 guacd (TLS) Loopback only
6000-6099 Xvnc displays (:100-:199) Loopback only

VDI containers listen on port 3389 inside their own network namespace; rustguac talks to them over the Docker network.

Where to look in the source

Concern File
Entry point, CLI, server setup src/main.rs
REST API src/api.rs
Session state machine src/session.rs
WebSocket-to-guacd proxy src/websocket.rs
Guacamole protocol parser/encoder src/protocol.rs
Vault client src/vault.rs
OIDC src/oidc.rs
API key + role auth src/auth.rs
guacd connection src/guacd.rs
Web session lifecycle src/browser.rs
VDI driver trait src/vdi/mod.rs
VDI Docker driver src/vdi/docker.rs
SQLite admin DB src/db.rs

Clone this wiki locally