Documents the map-group subcommand in the group-to-role mappings section: creating a mapping, the one-mapping-per-group rule and the --force re-map, and that mappings are applied at the user's next OIDC login rather than immediately, which matters in both directions when revoking access. Documents the new cli_audit_log table: what is and is not recorded, that the actor prefers SUDO_USER so sudo names the person rather than root, that only successful actions are logged, how to read it with sqlite3, and the 90 day retention. Also corrects two pre-existing errors found while writing the above: - deployment-guide.md showed an [oidc.group_role_mappings] config table. No such config field exists, so anyone following the guide would add it and silently get no mappings at all. Replaced with the CLI commands that actually create them. The same block had session_ttl_secs under [oidc]; the real key is auth_session_ttl_secs and it is top level. - roles-and-access-control.md documented an enable-user subcommand that does not exist. Re-enabling is done from the Admin page or the API, so the doc now says that, with a warning about disabling your own account.
13 KiB
Deployment Guide
A step-by-step guide for planning and deploying rustguac in production. Covers network architecture, server preparation, RDP target setup, security hardening, and ongoing operations.
Architecture Overview
A typical deployment has three layers:
Internet
|
[HAProxy] ── TLS termination, rate limiting, Knocknoc ACL
|
[rustguac] ── session management, WebSocket proxy, connections
|
[guacd] ── protocol translation (SSH, RDP, VNC)
|
[targets] ── SSH servers, RDP desktops, VNC hosts
All components can run on a single server for small deployments (up to ~50 concurrent sessions). For larger deployments, guacd is the bottleneck (~158 MB per RDP session) and can be scaled separately.
Port allocation
| Port | Service | Exposure |
|---|---|---|
| 443 | HAProxy (HTTPS) | Public / Knocknoc-gated |
| 8089 | rustguac (HTTPS) | Loopback only (behind HAProxy) |
| 4822 | guacd (TLS) | Loopback only |
| 6000-6099 | Xvnc displays | Loopback only (web sessions) |
Step 1: Install rustguac
Debian 13 (recommended)
# Download the latest .deb from GitHub releases
wget https://github.com/sol1/rustguac/releases/latest/download/rustguac_amd64.deb
sudo apt install ./rustguac_amd64.deb
This installs rustguac + guacd to /opt/rustguac with systemd services.
Docker (recommended for non-Debian-13 hosts)
docker pull ghcr.io/sol1/rustguac:latest
docker run -d \
-p 443:8089 \
-v rustguac-data:/opt/rustguac/data \
-v rustguac-recordings:/opt/rustguac/recordings \
-v ./config.toml:/opt/rustguac/config.toml \
ghcr.io/sol1/rustguac:latest
The Docker image bundles guacd + FreeRDP + dependencies, so it runs cleanly on Ubuntu, RHEL, Rocky, Arch, and other distros where the bare-metal .deb would hit a FreeRDP ABI mismatch. See installation.md for the full story on non-Debian-13 targets.
See installation.md for all install options.
Step 2: Initial Configuration
Create an admin API key
/opt/rustguac/bin/rustguac --config /opt/rustguac/config.toml add-admin --name admin
Save the printed key (rgu_...) — it is shown only once. Use it for initial setup, then delete it once OIDC is configured (see Step 5).
Edit config.toml
sudo nano /opt/rustguac/config.toml
Key settings for a production deployment:
listen_addr = "127.0.0.1:8089" # Loopback only — HAProxy handles public TLS
guacd_addr = "localhost:4822"
[tls]
cert_path = "/opt/rustguac/tls/cert.pem"
key_path = "/opt/rustguac/tls/key.pem"
guacd_cert_path = "/opt/rustguac/tls/cert.pem"
# Trust HAProxy's X-Forwarded-For header
trusted_proxies = ["127.0.0.1/32"]
# Network allowlists — restrict what targets guacd can connect to.
# Prevents SSRF via crafted session requests.
[network]
allowed_ssh_cidrs = ["10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16"]
allowed_rdp_cidrs = ["10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16"]
allowed_vnc_cidrs = ["10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16"]
See configuration.md for the full reference.
Start services
sudo systemctl enable --now rustguac
Verify: curl -k https://localhost:8089/api/health
Step 3: Set Up HAProxy
HAProxy provides TLS termination, HTTP/2, WebSocket support, and Knocknoc integration.
Using nginx, Caddy, Apache, or Traefik instead? See reverse-proxies.md for per-proxy configs and an important %2F gotcha that affects nested folder paths on several of them.
Install
sudo apt install haproxy
Configure
Create /etc/haproxy/haproxy.cfg:
global
log /dev/log local0
maxconn 4096
stats socket /run/haproxy/admin.sock mode 0660 level admin
ssl-default-bind-options no-sslv3 no-tlsv10 no-tlsv11
defaults
log global
mode http
option httplog
timeout connect 5s
timeout client 30s
timeout server 30s
timeout tunnel 8h # Long-lived WebSocket sessions
timeout http-request 10s # Slowloris protection
frontend https
bind *:443 ssl crt /etc/ssl/private/rustguac.pem alpn h2,http/1.1
bind *:80
http-request redirect scheme https unless { ssl_fc }
http-request del-header X-Forwarded-For
option forwardfor
http-response set-header Strict-Transport-Security "max-age=31536000; includeSubDomains"
default_backend rustguac
backend rustguac
option httpchk GET /api/health
server rustguac 127.0.0.1:8089 ssl verify none check inter 30s
TLS certificate
Use Let's Encrypt or your organisation's CA:
# Let's Encrypt example (certbot + HAProxy)
sudo certbot certonly --standalone -d console.example.com
sudo cat /etc/letsencrypt/live/console.example.com/{fullchain,privkey}.pem \
> /etc/ssl/private/rustguac.pem
sudo systemctl restart haproxy
Step 4: Prepare RDP Targets
Linux (xrdp with H.264)
For the best video experience with Linux desktops, use xrdp with x264 H.264 encoding. A single setup script handles everything — desktop environment, audio, xrdp rebuild with x264, and GFX configuration:
# On the RDP target machine (not the rustguac server):
wget -O setup-xrdp-gfx.sh https://raw.githubusercontent.com/sol1/rustguac/main/contrib/setup-xrdp-gfx.sh
sudo bash setup-xrdp-gfx.sh --desktop mate
The --desktop flag installs a desktop environment (default: mate). Options: mate, xfce, kde, gnome, none. MATE is recommended — it's lightweight, Windows-like, and works reliably over xrdp without GPU.
The script runs in three phases:
- Phase 1 (pure trixie): Installs desktop, Firefox, Chromium, build tools, PulseAudio xrdp audio module, switches from PipeWire to real PulseAudio
- Phase 2 (temporary sid): Adds Debian sid repo, installs matching xorgxrdp, rebuilds xrdp with
--enable-x264, removes sid - Phase 3 (configure): Xorg backend, startwm.sh, gfx.toml with H.264 + x264 encoder
Run bash setup-xrdp-gfx.sh --help for all options, or bash setup-xrdp-gfx.sh --diagnose to troubleshoot after setup.
In the rustguac connections, enable these settings on the RDP entry:
- Enable Graphics Pipeline (GFX) -- checked
- H.264 Passthrough -- checked
- Enable Desktop Composition -- not needed for Linux (Windows-only DWM setting)
See rdp-video-performance.md for manual setup and tuning.
Windows
Windows RDP works out of the box. For video-heavy workloads:
# On the Windows RDP server (as Administrator):
.\contrib\setup-rdp-performance.ps1
# With GPU hardware encoding:
.\contrib\setup-rdp-performance.ps1 -EnableGPU
This enables AVC 4:4:4, 60 FPS, desktop composition, and GPU encoding.
Note: Windows only sends H.264 when a GPU (physical or virtual) is available. Without GPU, it uses Planar/RemoteFX which guacd re-encodes as JPEG/WebP. This is still good quality — just not as low-latency as H.264 passthrough.
Step 5: Configure Authentication
OIDC Single Sign-On (recommended)
Add to config.toml:
# Top-level key, so it must appear before the first [section] header
auth_session_ttl_secs = 28800 # OIDC auth session cookie TTL (default 86400, 24h)
[oidc]
issuer_url = "https://your-idp.example.com"
client_id = "rustguac"
redirect_uri = "https://console.example.com/auth/callback"
groups_claim = "groups"
Set the client secret in /opt/rustguac/env:
echo 'OIDC_CLIENT_SECRET=your-secret-here' | sudo tee -a /opt/rustguac/env
sudo chmod 600 /opt/rustguac/env
sudo systemctl restart rustguac
Group-to-role mappings are stored in the database rather than in config.toml. Create them with the CLI once the service is running:
/opt/rustguac/bin/rustguac --config /opt/rustguac/config.toml \
map-group --group RemoteConsoleAdmins --role admin
/opt/rustguac/bin/rustguac --config /opt/rustguac/config.toml \
map-group --group RemoteConsoleUsers --role operator
They can also be managed in the Admin page or through the API. See Group-to-role mappings.
See integrations.md for provider-specific guides (Authentik, JumpCloud, Entra ID, etc.).
Delete the bootstrap API key
Once OIDC is working and you have an admin user, remove the initial API key:
# List admin keys
/opt/rustguac/bin/rustguac --config /opt/rustguac/config.toml list-admins
# Delete by name
/opt/rustguac/bin/rustguac --config /opt/rustguac/config.toml delete-admin --name admin
API keys are powerful (full admin, no MFA). For day-to-day use, OIDC with group-based roles is more secure. If you need programmatic API access, create scoped user API tokens instead.
Step 6: Set Up the Connections (Vault)
The connections stores connection entries in HashiCorp Vault or OpenBao. Credentials stay server-side — they never reach the browser.
[vault]
addr = "https://vault.example.com:8200"
mount = "secret"
base_path = "rustguac"
role_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
echo 'VAULT_SECRET_ID=your-secret-id' | sudo tee -a /opt/rustguac/env
sudo systemctl restart rustguac
See integrations.md for Vault setup, AppRole configuration, and mTLS.
Step 7: Lock It Down with Knocknoc
Knocknoc removes the attack surface entirely. Instead of exposing rustguac's login page to the internet, Knocknoc gates access at the network layer:
- Before Knocknoc: the login page is visible to scanners, bots, and attackers
- After Knocknoc: the login page returns 403 unless the user has authenticated through Knocknoc first (SSO + MFA)
Only the front page (/) is gated. API endpoints, OIDC callbacks, and share links pass through to rustguac's own auth.
HAProxy + Knocknoc configuration
Add to your HAProxy config:
# Dynamic ACL managed by knocknoc-agent
acl knoc_rustguac src -u 600
acl is_root path /
# Gate only the login page
use_backend rustguac if is_root knoc_rustguac
use_backend denied if is_root
use_backend rustguac
Install and configure knocknoc-agent to manage ACL #600 via the HAProxy admin socket.
Why this matters
rustguac gives users administrative access to servers. Even with OIDC and strong passwords, exposing the login page means:
- Brute-force and credential-stuffing attacks
- Zero-day exploits against the web layer
- Reconnaissance by scanners
Knocknoc ensures the login page is only reachable after identity-verified network authentication. The attack surface goes from "the entire internet" to "zero".
Step 8: Enable Drive Mapping (optional)
Drive mapping lets users transfer files to/from remote sessions.
Basic (unencrypted)
[drive]
enabled = true
drive_path = "/opt/rustguac/drives"
drive_name = "Shared Drive"
Encrypted (LUKS + Vault)
For environments requiring at-rest encryption:
sudo /opt/rustguac/bin/drive-setup.sh
This creates a LUKS-encrypted volume with the encryption key stored in Vault. See integrations.md for details.
Step 9: Session Recording (optional)
Session recordings are enabled by default and stored in /opt/rustguac/recordings.
recording_path = "/opt/rustguac/recordings"
[recording_rotation]
enabled = true
max_disk_percent = 80 # Auto-delete oldest when disk usage exceeds 80%
interval_secs = 300 # Check every 5 minutes
Recordings can be played back in the browser via the Sessions page, or exported for compliance.
Ongoing Operations
Monitoring
- Health check:
GET /api/healthreturns 200 when rustguac and guacd are running - System status:
GET /api/system/status(admin only) shows version, uptime, active sessions - Reports: Session history, top connections, top users available at
/reports.html(poweruser+ role)
Upgrading
# Debian package
sudo apt install ./rustguac_new-version.deb
sudo systemctl restart rustguac
Config files are preserved across upgrades (--force-confold). Database migrations run automatically on startup.
Backup
Back up these paths:
/opt/rustguac/config.toml— configuration/opt/rustguac/data/rustguac.db— users, tokens, session history/opt/rustguac/env— secrets (Vault secret ID, OIDC client secret)/opt/rustguac/recordings/— session recordings (if needed for compliance)
The connections is in Vault — back up Vault separately.
Security checklist
- HAProxy terminates TLS with a valid certificate (not self-signed)
- rustguac listens on loopback only (
listen_addr = "127.0.0.1:8089") - Network allowlists configured (prevent SSRF to unintended targets)
- OIDC configured with group-based role mappings
- Bootstrap API key deleted after OIDC setup
- Knocknoc gates the login page (optional but strongly recommended)
- Drive encryption enabled if file transfer is used in regulated environments
- Session recording enabled for audit compliance
/opt/rustguac/envhaschmod 600permissions- Trusted proxies configured to match HAProxy IP