Apache Guacamole: Gateway de Acceso Remoto sin Cliente
Apache Guacamole es una puerta de enlace de escritorio remoto sin cliente que permite acceder a escritorios y servidores mediante RDP, VNC y SSH directamente desde el navegador web, sin necesidad de instalar ninguna aplicación en el dispositivo cliente. Al centralizar el acceso remoto en un único punto con autenticación y auditoría, es la solución ideal para entornos corporativos que necesitan control de acceso a infraestructuras sin exponer los puertos RDP/VNC directamente a Internet. Esta guía cubre el despliegue de Guacamole con Docker.
Requisitos Previos
- Servidor Linux con Docker 24+ y Docker Compose v2
- Mínimo 2 GB de RAM (4 GB recomendado para múltiples conexiones simultáneas)
- Dominio con certificado TLS (para producción)
- Puerto 443 accesible para los usuarios del gateway
- Acceso de red desde el servidor Guacamole a los hosts de destino (RDP/VNC/SSH)
Instalación con Docker Compose
# Crear directorio de trabajo
mkdir -p /opt/guacamole/{init,config}
cd /opt/guacamole
# Descargar el script de inicialización de la base de datos
docker run --rm guacamole/guacamole /opt/guacamole/bin/initdb.sh --postgresql \
> init/initdb.sql
# Crear el archivo docker-compose.yml
cat > docker-compose.yml << 'EOF'
version: "3.9"
services:
# Base de datos PostgreSQL para Guacamole
postgres:
image: postgres:15-alpine
restart: unless-stopped
container_name: guacamole-db
environment:
POSTGRES_DB: guacamole_db
POSTGRES_USER: guacamole_user
POSTGRES_PASSWORD: password_seguro_db_aqui
volumes:
- postgres_data:/var/lib/postgresql/data
- ./init/initdb.sql:/docker-entrypoint-initdb.d/initdb.sql:ro
networks:
- guacamole-net
healthcheck:
test: ["CMD-SHELL", "pg_isready -U guacamole_user -d guacamole_db"]
interval: 10s
timeout: 5s
retries: 5
# Daemon de Guacamole (procesamiento de protocolos RDP/VNC/SSH)
guacd:
image: guacamole/guacd:1.5.4
restart: unless-stopped
container_name: guacamole-guacd
networks:
- guacamole-net
# Aplicación web de Guacamole
guacamole:
image: guacamole/guacamole:1.5.4
restart: unless-stopped
container_name: guacamole-app
depends_on:
postgres:
condition: service_healthy
guacd:
condition: service_started
environment:
# Conexión al daemon guacd
GUACD_HOSTNAME: guacd
GUACD_PORT: 4822
# Conexión a la base de datos PostgreSQL
POSTGRESQL_HOSTNAME: postgres
POSTGRESQL_PORT: 5432
POSTGRESQL_DATABASE: guacamole_db
POSTGRESQL_USER: guacamole_user
POSTGRESQL_PASSWORD: password_seguro_db_aqui
# Seguridad de la sesión
GUACAMOLE_HOME: /etc/guacamole
volumes:
- ./config:/etc/guacamole
ports:
- "8080:8080"
networks:
- guacamole-net
volumes:
postgres_data:
networks:
guacamole-net:
driver: bridge
EOF
# Iniciar los servicios
docker compose up -d
# Verificar que todos los contenedores están en ejecución
docker compose ps
docker compose logs guacamole
Configuración de la Base de Datos
Guacamole guarda usuarios, conexiones y grupos en la base de datos:
# Verificar que la base de datos se inicializó correctamente
docker compose exec postgres psql -U guacamole_user -d guacamole_db \
-c "\dt" 2>/dev/null
# Debe mostrar las tablas: guacamole_connection, guacamole_user, etc.
# Las credenciales por defecto del administrador son:
# Usuario: guacadmin
# Contraseña: guacadmin
# IMPORTANTE: Cambiar la contraseña inmediatamente después del primer login
# Cambiar la contraseña del administrador directamente en la base de datos
# (alternativamente, cambiarla desde la interfaz web)
docker compose exec postgres psql -U guacamole_user -d guacamole_db << 'SQL'
UPDATE guacamole_user
SET password_hash = encode(digest(CONCAT('tu_nueva_contraseña', encode(password_salt, 'hex')), 'sha256'), 'hex'),
password_date = NOW()
WHERE entity_id = (SELECT entity_id FROM guacamole_entity WHERE name = 'guacadmin');
SQL
# La interfaz web está disponible en:
# http://IP-del-servidor:8080/guacamole
Configuración de Conexiones
Guacamole gestiona conexiones desde la interfaz web en Settings > Connections:
# Las conexiones también se pueden insertar directamente en la base de datos
# Útil para automatización o importación masiva
docker compose exec postgres psql -U guacamole_user -d guacamole_db << 'SQL'
-- Crear una nueva conexión SSH al servidor de producción
INSERT INTO guacamole_connection (connection_name, protocol, max_connections)
VALUES ('Servidor-Produccion-SSH', 'ssh', 5);
-- Obtener el ID de la conexión creada
SELECT connection_id FROM guacamole_connection
WHERE connection_name = 'Servidor-Produccion-SSH';
-- Añadir parámetros de la conexión SSH
INSERT INTO guacamole_connection_parameter (connection_id, parameter_name, parameter_value)
VALUES
(1, 'hostname', '10.0.1.10'),
(1, 'port', '22'),
(1, 'username', 'operador'),
-- NO almacenar contraseñas en texto claro; usar clave privada
-- (1, 'password', 'contraseña'),
-- Alternativa: autenticación por clave privada
(1, 'private-key', '-----BEGIN OPENSSH PRIVATE KEY-----\n...'),
(1, 'color-scheme', 'green-black'),
(1, 'font-size', '14');
-- Crear una conexión RDP a un servidor Windows
INSERT INTO guacamole_connection (connection_name, protocol)
VALUES ('Servidor-Windows-RDP', 'rdp');
INSERT INTO guacamole_connection_parameter (connection_id, parameter_name, parameter_value)
VALUES
(2, 'hostname', '10.0.2.20'),
(2, 'port', '3389'),
(2, 'username', 'Administrador'),
(2, 'domain', 'EMPRESA'),
(2, 'security', 'nla'), -- NLA es más seguro que RDP básico
(2, 'ignore-cert', 'true'), -- Solo en pruebas; usar certificado válido en prod
(2, 'resize-method', 'reconnect'),
(2, 'enable-font-smoothing', 'true');
SQL
Autenticación LDAP
Configura Guacamole para autenticar usuarios contra LDAP/Active Directory:
# Crear el archivo de configuración de Guacamole con LDAP
mkdir -p /opt/guacamole/config
cat > /opt/guacamole/config/guacamole.properties << 'EOF'
# Configuración LDAP para autenticación corporativa
ldap-hostname: ldap.empresa.local
ldap-port: 389
ldap-username-attribute: sAMAccountName # Para Active Directory
# ldap-username-attribute: uid # Para LDAP genérico
ldap-user-base-dn: ou=usuarios,dc=empresa,dc=local
ldap-search-bind-dn: cn=guacamole-reader,ou=service-accounts,dc=empresa,dc=local
ldap-search-bind-password: password_cuenta_servicio
# Mapeo de grupos LDAP a permisos de Guacamole
ldap-group-base-dn: ou=grupos,dc=empresa,dc=local
ldap-group-search-filter: (objectClass=groupOfNames)
# Los usuarios en el grupo "guacamole-admins" de LDAP serán administradores
ldap-user-attributes: cn,mail,givenName,sn
EOF
# Actualizar docker-compose.yml para montar la configuración
# Añadir en el servicio guacamole:
# volumes:
# - ./config:/etc/guacamole:ro
docker compose restart guacamole
docker compose logs guacamole | tail -20
Proxy Inverso con Nginx
# Instalar Nginx y Certbot
apt-get install -y nginx certbot python3-certbot-nginx
# Obtener certificado TLS
certbot certonly --nginx -d remoto.tudominio.com \
--email [email protected] --agree-tos --non-interactive
# Configuración de Nginx para Guacamole
cat > /etc/nginx/sites-available/guacamole << 'EOF'
server {
listen 80;
server_name remoto.tudominio.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
server_name remoto.tudominio.com;
ssl_certificate /etc/letsencrypt/live/remoto.tudominio.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/remoto.tudominio.com/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;
# Cabeceras de seguridad
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains" always;
add_header X-Frame-Options SAMEORIGIN;
add_header X-Content-Type-Options nosniff;
# WebSocket para Guacamole (requiere soporte de WebSocket)
location /guacamole/websocket-tunnel {
proxy_pass http://127.0.0.1:8080;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_buffering off;
proxy_read_timeout 3600s;
proxy_send_timeout 3600s;
}
# Resto de la aplicación Guacamole
location /guacamole {
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_buffering off;
client_max_body_size 1024m;
}
# Redirigir / a /guacamole para comodidad
location = / {
return 301 https://$host/guacamole/;
}
}
EOF
ln -s /etc/nginx/sites-available/guacamole /etc/nginx/sites-enabled/
nginx -t && systemctl reload nginx
Autenticación de Dos Factores
# Habilitar TOTP (Time-based One-Time Password) en Guacamole
# Añadir la extensión TOTP a la imagen de Guacamole o descargarla
# La extensión TOTP ya viene incluida en la imagen oficial de Guacamole
# Activarla en docker-compose.yml añadiendo al servicio guacamole:
# environment:
# TOTP_ENABLED: "true" # No disponible como var de entorno directa
#
# En su lugar, configurar en guacamole.properties:
cat >> /opt/guacamole/config/guacamole.properties << 'EOF'
# Habilitar TOTP para doble factor de autenticación
# (requiere la extensión totp-*.jar en el directorio de extensiones)
totp-issuer: Empresa
totp-period: 30
totp-digits: 6
EOF
# Los usuarios deberán configurar su app de autenticación (Google Authenticator,
# Authy, etc.) en su primer login tras activar TOTP
docker compose restart guacamole
Solución de Problemas
# Ver logs de todos los contenedores
docker compose logs -f
# Ver logs del daemon guacd (errores de conexión RDP/VNC/SSH)
docker compose logs guacd
# Probar la conectividad desde el servidor Guacamole al host de destino
docker compose exec guacd nc -zv 10.0.1.10 22 # Prueba SSH
docker compose exec guacd nc -zv 10.0.2.20 3389 # Prueba RDP
# La interfaz web no carga
# Verificar que el contenedor guacamole está en ejecución
docker compose ps
# Error "Cannot connect to Guacamole server"
# El servidor web no puede conectar con guacd
docker compose logs guacamole | grep "guacd"
# Error de autenticación en conexiones RDP
# - Verificar usuario/contraseña/dominio en los parámetros de conexión
# - Comprobar que NLA está configurado correctamente
# - Verificar que el firewall permite el tráfico al puerto 3389
# Sesión desconectada prematuramente (timeout)
# Aumentar los timeouts en la configuración de Nginx:
# proxy_read_timeout 3600s; (ya configurado arriba)
# Ver las conexiones activas en la base de datos
docker compose exec postgres psql -U guacamole_user -d guacamole_db \
-c "SELECT * FROM guacamole_connection_history ORDER BY start_date DESC LIMIT 10;"
Conclusión
Apache Guacamole transforma el acceso remoto corporativo en un servicio web centralizado y auditable que elimina la necesidad de clientes VPN o software RDP en los dispositivos de los usuarios, simplificando la gestión y mejorando la seguridad al no exponer directamente los puertos de escritorio remoto. La integración con LDAP/AD y la autenticación de dos factores, combinadas con el registro completo de sesiones, convierten a Guacamole en la solución más completa para el acceso remoto controlado a infraestructuras críticas.


