Skip to content

Deployment Docker

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

Deployment: Docker

The published image is sol1/rustguac on Docker Hub. It's a multi-arch manifest covering amd64 and arm64. Tags are :latest, :1.6.6 (semver), and the rolling :1.6 (minor) and :1 (major).

The image bundles guacd and rustguac in a single container, with an entrypoint that starts both. It's intentionally not split into two containers; guacd and rustguac talk to each other over loopback inside the container, which is simpler to operate than wiring up a service mesh.

Quick start

docker run --rm -it \
  -p 8089:8089 \
  -v rustguac-data:/opt/rustguac/data \
  -v rustguac-recordings:/opt/rustguac/recordings \
  sol1/rustguac:latest

That gets you a running instance on port 8089 with no auth configured. Do not expose this directly to the internet at minimum, terminate TLS in a reverse proxy and configure OIDC.

docker-compose

A more realistic deployment, with persistence, custom config, and a reverse proxy:

services:
  rustguac:
    image: sol1/rustguac:latest
    restart: unless-stopped
    volumes:
      - ./config.toml:/opt/rustguac/config.toml:ro
      - ./tls:/opt/rustguac/tls:ro
      - rustguac-data:/opt/rustguac/data
      - rustguac-recordings:/opt/rustguac/recordings
      - rustguac-drives:/opt/rustguac/drives
      - rustguac-vdi-homes:/opt/rustguac/vdi-homes
    environment:
      RUST_LOG: info
      VAULT_SECRET_ID: ${VAULT_SECRET_ID}
      OIDC_CLIENT_SECRET: ${OIDC_CLIENT_SECRET}
    expose:
      - "8089"
    networks:
      - rustguac-net

  haproxy:
    image: haproxy:latest
    restart: unless-stopped
    volumes:
      - ./haproxy.cfg:/usr/local/etc/haproxy/haproxy.cfg:ro
      - ./tls:/etc/haproxy/tls:ro
    ports:
      - "443:443"
    depends_on:
      - rustguac
    networks:
      - rustguac-net

volumes:
  rustguac-data:
  rustguac-recordings:
  rustguac-drives:
  rustguac-vdi-homes:

networks:
  rustguac-net:

Volumes

Path Purpose Persistence
/opt/rustguac/data SQLite admin DB, OIDC session store Required
/opt/rustguac/recordings Session recordings Required if you've enabled recording
/opt/rustguac/drives LUKS-encrypted per-session drive storage Required if you've enabled file transfer
/opt/rustguac/vdi-homes Per-user VDI container home directories Required if you've enabled VDI
/opt/rustguac/config.toml Configuration Read-only mount
/opt/rustguac/tls TLS cert/key for the rustguac listener Read-only mount

Environment variables

Variable Purpose
RUST_LOG Log level (e.g. info, rustguac=debug)
GUACD_LOG_LEVEL Verbosity for the bundled guacd
VAULT_SECRET_ID AppRole secret ID for the Vault client
OIDC_CLIENT_SECRET OIDC client secret (overrides config.toml)

The image runs as a non-root rustguac user (uid 103 by convention). If you bind-mount config or TLS files, make sure they're readable by that user, or set ownership/perms accordingly.

VDI inside Docker

If you want to run VDI containers (per-user Docker desktops) from a containerised rustguac, you have two real options:

  1. Mount the host Docker socket into the rustguac container (-v /var/run/docker.sock:/var/run/docker.sock). The simplest path. rustguac asks the host Docker daemon to spawn sibling containers. Note: this is essentially root-equivalent on the host, so weigh that against your threat model.
  2. Run a separate Docker daemon (e.g. via docker:dind) that rustguac talks to. More isolation, more moving parts.

Configure docker_socket in your config.toml's [vdi] section to point to wherever the socket actually is from inside the container.

TLS between rustguac and guacd

Inside the published image, rustguac and guacd talk over TLS on loopback. The image ships with a self-signed cert at /opt/rustguac/tls/cert.pem for that internal hop. You don't need to provide one for that path. The TLS cert you do care about is the one your reverse proxy uses for client connections.

Building locally

git clone https://github.com/sol1/rustguac
cd rustguac
docker build -t rustguac:dev .

The Dockerfile is multi-stage:

  1. guacd-builder: Debian trixie, autoconf-builds guacd with the FreeRDP 3.15+ patches applied.
  2. rust-builder: Rust 1-bookworm, cargo build --release.
  3. runtime: Debian trixie-slim with both binaries copied in.

Cross-platform builds (e.g. arm64 from an x86_64 host) work via docker buildx build --platform linux/arm64.

Operational notes

  • Logs go to stdout/stderr; collect them with whatever you usually use (docker logs, journald via the journald log driver, etc.).
  • Health can be checked with curl -fsk https://<host>:8089/api/auth/status. Returns 200 when rustguac is up.
  • Restart policy should be unless-stopped or always. rustguac will not auto-recover from a hard guacd crash; the container exits and Docker restarts it.
  • Memory budget around 200 MB for rustguac + ~150 MB per active RDP session. VDI desktops are sized by their [vdi].default_memory_limit config (default 2 GB per container).

See also: Architecture, Knocknoc integration, and the in-repo docs/deployment-guide.md for the bare-metal equivalent.

Clone this wiki locally