Apache Guacamole
Deploy Apache Guacamole on Kubernetes — a clientless remote desktop gateway that allows RDP, VNC, SSH, and Telnet access directly from a web browser with no client installation required.
Default credentials are guacadmin / guacadmin — change immediately after first login
Fresh Guacamole installations use guacadmin / guacadmin as the default administrator credentials. These are
hardcoded in the schema SQL and well-known publicly. Change the password immediately after the first login via
the Guacamole admin UI.
Key Features
- guacd sidecar — protocol daemon runs alongside the web app, communicating on localhost:4822
- Dual-image architecture —
guacamole(Tomcat web app) +guacd(protocol daemon) - PostgreSQL bundled by default — no extra setup for quick start
- Schema init Job — automatic
guacamole_dbschema creation on install - OIDC, SAML, and TOTP — SSO and MFA integrations
- Tomcat reverse proxy — correct client IP via
X-Forwarded-Forsupport - Database-aware backup —
pg_dumpormysqldumpto S3
Installation
HTTPS repository:
helm repo add helmforge https://repo.helmforge.dev
helm repo update
helm install guacamole helmforge/guacamole -f values.yaml
OCI registry:
helm install guacamole oci://ghcr.io/helmforgedev/helm/guacamole -f values.yaml
Deployment Examples
# values.yaml — Guacamole with bundled PostgreSQL (default)
# Default credentials: guacadmin / guacadmin — CHANGE IMMEDIATELY after first login
guacd:
logLevel: info
postgresql:
enabled: true
auth:
database: guacamole_db
username: guacamole_user
password: 'strong-db-password'
ingress:
enabled: true
ingressClassName: traefik
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
hosts:
- host: remote.example.com
paths:
- path: /
pathType: Prefix
tls:
- secretName: guacamole-tls
hosts:
- remote.example.com# values.yaml — Guacamole with OIDC SSO (Keycloak example)
# OIDC replaces local database authentication for login
# redirectUri is auto-detected from ingress if left empty
oidc:
enabled: true
authorizationEndpoint: 'https://auth.example.com/realms/myrealm/protocol/openid-connect/auth'
jwksEndpoint: 'https://auth.example.com/realms/myrealm/protocol/openid-connect/certs'
issuer: 'https://auth.example.com/realms/myrealm'
clientId: guacamole
redirectUri: 'https://remote.example.com/' # auto-detected from ingress if empty
scope: 'openid email profile'
usernameClaim: preferred_username
groupsClaim: groups
totp:
enabled: true # combine OIDC with TOTP for 2FA on top of SSO
postgresql:
enabled: true
auth:
password: 'strong-db-password'
ingress:
enabled: true
ingressClassName: traefik
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
hosts:
- host: remote.example.com
paths:
- path: /
pathType: Prefix
tls:
- secretName: guacamole-tls
hosts:
- remote.example.com# values.yaml — Guacamole with SAML SSO
saml:
enabled: true
idpMetadataUrl: 'https://auth.example.com/realms/myrealm/protocol/saml/descriptor'
entityId: 'https://remote.example.com/'
callbackUrl: 'https://remote.example.com/' # auto-detected from ingress if empty
strict: true
groupAttribute: groups
postgresql:
enabled: true
auth:
password: 'strong-db-password'
ingress:
enabled: true
ingressClassName: traefik
hosts:
- host: remote.example.com
paths:
- path: /
pathType: Prefix# values.yaml — Guacamole with external PostgreSQL and S3 backup
postgresql:
enabled: false
mysql:
enabled: false
database:
type: postgresql
external:
host: postgres.database.svc.cluster.local
port: 5432
name: guacamole_db
username: guacamole_user
existingSecret: guacamole-db-credentials
existingSecretPasswordKey: password
backup:
enabled: true
schedule: '0 2 * * *'
s3:
endpoint: https://s3.amazonaws.com
bucket: guacamole-backups
existingSecret: guacamole-s3-credentials
ingress:
enabled: true
ingressClassName: traefik
hosts:
- host: remote.example.com
paths:
- path: /
pathType: PrefixConfiguration Reference
Images
| Parameter | Type | Default | Description |
|---|---|---|---|
image.repository | string | docker.io/guacamole/guacamole | Guacamole web app image. |
image.tag | string | "1.6.0" | Image tag. |
guacd.image.repository | string | docker.io/guacamole/guacd | guacd protocol daemon image. |
guacd.image.tag | string | "1.6.0" | guacd image tag. |
Guacamole
| Parameter | Type | Default | Description |
|---|---|---|---|
guacamole.contextPath | string | ROOT | Web context path. ROOT = serve at /. Change to guacamole for /guacamole/. |
guacamole.extraEnv | array | [] | Extra environment variables. |
guacd.port | integer | 4822 | Internal guacd daemon port. |
guacd.logLevel | string | info | guacd log level: info, debug, warning, error. |
Reverse Proxy
| Parameter | Type | Default | Description |
|---|---|---|---|
proxy.enabled | boolean | true | Enable Tomcat RemoteIpValve for correct client IPs. |
proxy.ipHeader | string | X-Forwarded-For | Header containing the real client IP. |
proxy.protocolHeader | string | X-Forwarded-Proto | Header containing the protocol (http/https). |
OIDC
| Parameter | Type | Default | Description |
|---|---|---|---|
oidc.enabled | boolean | false | Enable OIDC SSO. |
oidc.authorizationEndpoint | string | "" | OIDC authorization endpoint URL. |
oidc.jwksEndpoint | string | "" | JWKS token validation endpoint URL. |
oidc.issuer | string | "" | Expected token issuer. |
oidc.clientId | string | "" | OIDC client ID. |
oidc.redirectUri | string | "" | Redirect URI. Auto-detected from ingress if empty. |
oidc.usernameClaim | string | preferred_username | JWT claim for the username. |
oidc.groupsClaim | string | groups | JWT claim for groups. |
SAML
| Parameter | Type | Default | Description |
|---|---|---|---|
saml.enabled | boolean | false | Enable SAML SSO. |
saml.idpMetadataUrl | string | "" | IdP SAML metadata URL. |
saml.entityId | string | "" | Service provider entity ID. |
saml.callbackUrl | string | "" | Callback URL. Auto-detected from ingress if empty. |
saml.strict | boolean | true | Enforce certificate validation. |
saml.groupAttribute | string | groups | SAML group attribute name. |
totp.enabled | boolean | false | Enable TOTP two-factor authentication. |
Database and Init Job
| Parameter | Type | Default | Description |
|---|---|---|---|
database.type | string | postgresql | Database type: postgresql or mysql. |
database.external.host | string | "" | External database hostname. |
database.external.existingSecret | string | "" | Existing secret with database password. |
initDb.enabled | boolean | true | Run schema init Job on install (safe for upgrades). |
postgresql.enabled | boolean | true | Deploy the bundled PostgreSQL subchart. |
postgresql.auth.password | string | "" | Password. Required when using the subchart. |
mysql.enabled | boolean | false | Deploy the bundled MySQL subchart. |
Service and Ingress
| Parameter | Type | Default | Description |
|---|---|---|---|
service.type | string | ClusterIP | Service type. |
service.port | integer | 80 | Service port. |
ingress.enabled | boolean | false | Enable an Ingress resource. |
ingress.ingressClassName | string | traefik | Ingress class name. |
Backup
Database-aware: pg_dump for PostgreSQL, mysqldump for MySQL.
| Parameter | Type | Default | Description |
|---|---|---|---|
backup.enabled | boolean | false | Enable scheduled database S3 backup. |
backup.schedule | string | "0 2 * * *" | Cron schedule. |
backup.s3.endpoint | string | "" | S3-compatible endpoint URL. |
backup.s3.bucket | string | "" | Target bucket name. |
backup.s3.existingSecret | string | "" | Existing secret with S3 credentials. |
extraManifests | array | [] | Extra Kubernetes manifests. |