Apache Guacamole
No necesita la instalación de agentes o ningún tipo de software cliente. Gracias a HTML5, una vez Guacamole está instalado en un servidor, lo único necesario para acceder a tu desktop es un Navegador WEB.
un despliegue típico de Guacamole incluye tres servicios separados:
- guacamole/guacd: es el
servicioservicio guacd.guacamole-server tiene soporteparapara VNC, RDP, SSH, telnet, y Kubernetes. - guacamole/guacamole: proporciona las aplicaciones web de Guacamole ejecutadas en Tomcat con soporte para WebSocket.
- mysql o postgresql: proporciona la base de datos que usará Guacamole para validación y guarda los datos de configuración de las conexiones.
Requisitos
- Docker instalado siguiendo los pasos
dede instalar - Portainer configurado siguiendo los pasos
dede instalar portainer. (opcional) - NGINX Proxy manager siguiendo los pasos de
instalarinstalar NGINX Proxy Manager. (opcional) - Traefik configurado siguiendo los pasos de
instalar Traefik. (opcional)
Enlaces
Imagenes
- guacamole/guacamole – Docker Image | Docker Hub
- guacamole/guacd – Docker Image | Docker Hub
- mariadb – Official Image | Docker Hub
Directorios
mkdir -pv $HOME/docker_volumes/guacamole/{db,guacd/drive}
chmod 777 $HOME/docker_volumes/guacamole/guacd/drive
Portainer- Agregar nuevo «stack»
Add a new stack – Portainer Documentation
Web editor
En Portainer «Stack» agregamos nuevo usando el editor WEB pegando el contenido del fichero «docker-compose.yml» y el contenido del fichero de variables modificando los valores necesarios
Fichero de variables «.env»
DOMAIN=domain.comTZ=Europe/Madrid
CONTAINERDIR=DOCKER_DATA_DIR=/home/user"mi_usuario"/docker_volumes
DOMAIN="mi_dominio.com"
VERSION=1.5.5
GUACD_HOSTNAME=guacd
MYSQL_HOSTNAME=guacdb
MYSQL_ROOT_PASSWORD=#GeneraPassword
MYSQL_DATABASE=guacamole_db
MYSQL_USER=guacamole_user
MYSQL_PASSWORD=#GeneraPassword
Fichero «docker-compose.yml» inicial
services:
guacdb:
container_name: guacdb
image: docker.io/mariadb
restart: unless-stopped
env_file: stack.env
volumes:
- $CONTAINERDIR/DOCKER_DATA_DIR/guacamole/db:/var/lib/mysql
Iniciando la base de datos MySQL
Si la base de datos no ha sido iniciada aun con el esquema de Guacamole, será un paso previo usando Guacamole. Un script para generar lo necesario en SQL está incluido en la imagen de Guacamole .
Para generar el el script SQL para iniciar una nueva base de datos MySQL como como documenta el manual de Guacamole:
# Para Docker
sudo docker run --rm guacamole/guacamole /opt/guacamole/bin/initdb.sh --mysql > guac_db.sql
# Para Podman
sudo podman run --rm docker.io/guacamole/guacamole /opt/guacamole/bin/initdb.sh --mysql > guac_db.sql
Copiando el script de inicialización en el contenedor
#Para Docker
sudo docker cp guac_db.sql guacdb:/guac_db.sql
#Para Podman
sudo podman cp guac_db.sql guacdb:/guac_db.sql
Abriendo un shell para iniciar la BD
# Para Docker
sudo docker exec -it guacdb bash
# Para Docker
sudo podman exec -it guacdb bash
root@ef7a965feb22:/# cat /guac_db.sql | mysql -u root -p guacamole_db
root@ef7a965feb22:/# exit
Apaga el «Stack» y amplia el fichero docker-compose con el contenido del siguiente punto
Ampliando el fichero «docker-compose.yml»
...
guacd:
container_name: guacd
image: docker.io/guacamole/guacd:$VERSION
restart: unless-stopped
volumes:
- $CONTAINERDIR/DOCKER_DATA_DIR/guacamole/guacd/drive:/drive:rw
- $CONTAINERDIR/DOCKER_DATA_DIR/guacamole/guacd/record:/record:rw
guacamole:
container_name: guacamole
image: docker.io/guacamole/guacamole:$VERSION
restart: unless-stopped
env_file: stack.env
depends_on:
- guacdb
- guacd
ports:
- 8080:8080
En este punto ya puedes ir a http://my.docker.ip.address:8080/guacamole y entrar con guacadmin/guacadmin.
Publicando detrás de un proxy
Crear registro DNS
En el proveedor que aloja el servidor DNS público, crear un registro DNS que resuelva la IP pública que llega al Proxy hacia un nombre del estilo "guacamole.domain.com"
NGINX proxy
Para publicar el contenedor detrás de de NGINX proxy, el fichero "docker-compose.yml" contandrá contandrá lo siguiente:
services:
guacdb:
container_name: guacdb
image: mariadb
restart: unless-stopped
env_file: stack.env
volumes:
- $CONTAINERDIR/DOCKER_DATA_DIR/guacamole/guacdb-data:/var/lib/mysql
networks:
- backend
guacd:
container_name: guacd
image: guacamole/guacd:$TAG
restart: unless-stopped
env_file: stack.env
volumes:
- $CONTAINERDIR/DOCKER_DATA_DIR/guacamole/guacd/drive:/drive:rw
- $CONTAINERDIR/DOCKER_DATA_DIR/guacamole/guacd/record:/record:rw
networks:
- backend
guacamole:
container_name: guacamole
image: guacamole/guacamole:$TAG
restart: unless-stopped
env_file: stack.env
depends_on:
- guacdb
- guacd
networks:
- backend
- proxy
networks:
backend:
proxy:
external: true
Crear un nuevo "proxy host"
Añade un nuevo proxy host con el nombre de dominio creado en el paso anterior redirigido hacia el nombre del contenedor y el puerto que use:

Si queremos eliminar el "path" /guacamole de la URL, agregamos en las propiedades avanzadas del proxy host la siguiente configuración avanzada:
location / {
proxy_pass http://guacamole:8080/guacamole/;
proxy_buffering off;
proxy_http_version 1.1;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $http_connection;
proxy_cookie_path /guacamole/ /;
Traefik

Para publicar el contenedor detrás del proxy proxy Traefik, deberás añadir al final del fichero "docker-compose.yml" lo siguiente:
networks:
- backend
- traefik_public
labels:
- traefik.enable=true
- traefik.http.routers.guacamole.rule=Host(`guacamole.$DOMAIN`)
- traefik.http.routers.guacamole.tls=true
- traefik.http.routers.guacamole.tls.certresolver=letsencrypt
- traefik.http.routers.guacamole.middlewares=guacamole-prefix
- traefik.http.middlewares.guacamole-prefix.addprefix.prefix=/guacamole
networks:
backend:
traefik_public:
external: true
Validación de usuarios
OpenID (Azure AD)
Registra la aplicación siguiendo estos pasos:
- Validate en el portal de Azure (https://portal.azure.com/) en el servicio de "Microsoft Entra ID"
- En Administrar -> Registro de aplicaciones -> Nuevo Registro

Añade este contenido al fichero de variables .env
AZURE_TENANT_ID=#Id. de directorio (inquilino)
OPENID_CLIENT_ID=#Id. de aplicación (cliente)
OPENID_REDIRECT_URI=https://guacamole.$DOMAIN
OPENID_AUTHORIZATION_ENDPOINT=https://login.microsoftonline.com/${AZURE_TENANT_ID}/oauth2/v2.0/authorize
OPENID_JWKS_ENDPOINT=https://login.microsoftonline.com/${AZURE_TENANT_ID}/discovery/v2.0/keys
OPENID_ISSUER=https://login.microsoftonline.com/${AZURE_TENANT_ID}/v2.0
OPENID_USERNAME_CLAIM_TYPE=email
OPENID_SCOPE=openid email profile
EXTENSION_PRIORITY=openid
En la configuración de la "Autenticación" seleccionar "Tokens de id."

Microsoft Active Directory (LDAP)
Nota: Si configuramos la conexión con Active Directory, tenemos que crear en nuestro Directorio Activo (dentro de nuestra Base DN) un usuario llamado "guacadmin", y NO debe tener la misma contraseña que el usuario de MySQL. Podremos validarnos con usuarios LDAP y usuarios MySQL
Añade este contenido al fichero de variables .env
# Active Directory
LDAP_HOSTNAME=DIRECCIÓN_IP_CONTROLADOR_DE_DOMINIO
LDAP_PORT=389 # O seguro: 636
LDAP_USER_BASE_DN=OU=ruta,DC=dominio,DC=local
LDAP_USERNAME_ATTRIBUTE=samAccountName
LDAP_CONFIG_BASE_DN=OU=ruta,DC=dominio,DC=local
LDAP_ENCRYPTION_METHOD=none # O seguro: ssl, starttls
LDAP_SEARCH_BIND_DN=cn=usuario_LDAP,OU=ruta,DC=dominio,DC=local
LDAP_SEARCH_BIND_PASSWORD=password
LDAP_USER_SEARCH_FILTER=(memberOf=CN=guacamoleUsers,OU=ruta,DC=dominio,DC=local)
Para estar seguro que esto funciona, podemos acceder al al contenedor «guacamole» y ejecutar el siguiente comando para ver si se ha añadido la configuración de LDAP al fichero guacamole.properties:
docker exec -it guacamole bash
cat /home/guacamole/.guacamole/guacamole.properties
Y podremos ver el contenido del fichero guacamole.properties
Autologin a traves de URL
http://my.docker.ip.address:8080/guacamole/#/?serverid=ZZZZZZ&username=USER&password=PASS
Parameter tokens
The values of connection parameters can contain «tokens» which will be replaced by Guacamole when used. These tokens allow the values of connection parameters to vary dynamically by the user using the connection, and provide a simple means of forwarding authentication information without storing that information in the connection configuration itself, so long as the remote desktop connection uses the same credentials as Guacamole.
Each token is of the form ${TOKEN_NAME}, where TOKEN_NAME is some descriptive name for the value the token represents. Tokens with no corresponding value will never be replaced, but should you need such text within your connection parameters, and wish to guarantee that this text will not be replaced with a token value, you can escape the token by adding an additional leading «$», as in «$${TOKEN_NAME}».
${GUAC_USERNAME}
The username of the current Guacamole user. When a user accesses this connection, this token will be dynamically replaced with the username they provided when logging in to Guacamole.
${GUAC_PASSWORD}
The password of the current Guacamole user. When a user accesses this connection, this token will be dynamically replaced with the password they used when logging in to Guacamole.


