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.
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 | 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) |
# Download the latest .deb from GitHub releases
wget https://github.com/sol1/rustguac/releases/latest/download/rustguac_amd64.deb
sudo apt install ./rustguac_amd64.debThis installs rustguac + guacd to /opt/rustguac with systemd services.
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:latestThe 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.
/opt/rustguac/bin/rustguac --config /opt/rustguac/config.toml add-admin --name adminSave the printed key (rgu_...) — it is shown only once. Use it for initial setup, then delete it once OIDC is configured (see Step 5).
sudo nano /opt/rustguac/config.tomlKey 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.
sudo systemctl enable --now rustguacVerify: curl -k https://localhost:8089/api/health
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.
sudo apt install haproxyCreate /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
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 haproxyFor 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 mateThe --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 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 -EnableGPUThis 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.
Add to config.toml:
[oidc]
issuer_url = "https://your-idp.example.com"
client_id = "rustguac"
redirect_uri = "https://console.example.com/auth/callback"
groups_claim = "groups"
session_ttl_secs = 28800 # 8 hours
[oidc.group_role_mappings]
"RemoteConsoleAdmins" = "admin"
"RemoteConsoleUsers" = "operator"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 rustguacSee integrations.md for provider-specific guides (Authentik, JumpCloud, Entra ID, etc.).
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 adminAPI 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.
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 rustguacSee integrations.md for Vault setup, AppRole configuration, and mTLS.
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.
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.
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".
Drive mapping lets users transfer files to/from remote sessions.
[drive]
enabled = true
drive_path = "/opt/rustguac/drives"
drive_name = "Shared Drive"For environments requiring at-rest encryption:
sudo /opt/rustguac/bin/drive-setup.shThis creates a LUKS-encrypted volume with the encryption key stored in Vault. See integrations.md for details.
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 minutesRecordings can be played back in the browser via the Sessions page, or exported for compliance.
- 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)
# Debian package
sudo apt install ./rustguac_new-version.deb
sudo systemctl restart rustguacConfig files are preserved across upgrades (--force-confold). Database migrations run automatically on startup.
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.
- 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