El problema: cada navegador nuevo requiere SSH
OpenClaw tiene un sistema de seguridad llamado device pairing. Cada vez que un navegador nuevo intenta conectarse al dashboard (Control UI), el gateway genera una solicitud de emparejamiento que alguien tiene que aprobar desde el servidor por SSH.
Para uso personal, es una pequeña molestia. Pero para un curso donde 20 alumnos necesitan acceder a sus propias instancias de OpenClaw, es un bloqueo total: cada alumno necesitaría acceso SSH al servidor para aprobar su propio dispositivo.
Necesitábamos una solución que cumpliera tres requisitos:
- Acceder al dashboard desde el navegador sin SSH
- Conexión cifrada (HTTPS) con certificado real
- Autenticación por email para controlar quién puede entrar
La solución: tres capas de seguridad
Después de varios intentos (incluyendo caminos que no funcionaron, que contamos al final), llegamos a una arquitectura con tres capas:
- Apache reverse proxy + Let's Encrypt — HTTPS con certificado real, proxy de WebSocket al gateway
- dangerouslyDisableDeviceAuth — elimina la necesidad de aprobar dispositivos por SSH
- Cloudflare Access — autenticación por email con código de un solo uso
El resultado: el alumno abre la URL, Cloudflare le pide su email, recibe un código, y entra al dashboard. Sin SSH, sin device pairing, con HTTPS.
Paso 1: Apache reverse proxy con WebSocket
El gateway de OpenClaw escucha en localhost:18789 con bind: loopback — no es accesible desde fuera. Apache actúa como intermediario: recibe el tráfico HTTPS en el puerto 443 y lo reenvía al gateway, incluyendo las conexiones WebSocket que el dashboard necesita para funcionar.
Los módulos de Apache necesarios (todos vienen preinstalados en las instancias Bitnami de Lightsail):
# Verificar que los módulos están habilitados
apache2ctl -M | grep -E 'proxy|rewrite|ssl|wstunnel'
# Necesarios: proxy, proxy_http, proxy_wstunnel, rewrite, sslPrimero, creamos el vhost HTTP (para el redirect y para el ACME challenge de Let's Encrypt):
sudo tee /etc/apache2/sites-available/openclaw.conf > /dev/null <<'EOF'
<VirtualHost *:80>
ServerName openclaw.<TU_DOMINIO>
RewriteEngine On
RewriteCond %{HTTP:X-Forwarded-Proto} !https
RewriteCond %{HTTPS} off
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
ProxyPreserveHost On
ProxyPass / http://localhost:18789/
ProxyPassReverse / http://localhost:18789/
RewriteCond %{HTTP:Upgrade} websocket [NC]
RewriteCond %{HTTP:Connection} upgrade [NC]
RewriteRule ^/?(.*) ws://localhost:18789/$1 [P,L]
</VirtualHost>
EOF
sudo a2ensite openclaw.conf
sudo systemctl reload apache2RewriteCond %{HTTP:X-Forwarded-Proto} !https es clave: cuando Cloudflare reenvía tráfico al origin, envía la cabecera X-Forwarded-Proto: https. Sin esta condición, Apache redirige a HTTPS en bucle infinito porque ve HTTP desde Cloudflare.Paso 2: Certificado HTTPS con Let's Encrypt
Con el vhost HTTP activo, certbot puede completar el challenge ACME y generar el certificado:
# Instalar certbot si no está disponible
sudo apt-get install -y certbot python3-certbot-apache
# Generar certificado (reemplaza con tu dominio)
sudo certbot --apache \
-d openclaw.<TU_DOMINIO> \
--non-interactive \
--agree-tos \
-m <TU_EMAIL>Certbot crea automáticamente el vhost SSL (openclaw-le-ssl.conf). Lo editamos para añadir el proxy con WebSocket:
sudo tee /etc/apache2/sites-available/openclaw-le-ssl.conf > /dev/null <<'EOF'
<IfModule mod_ssl.c>
<VirtualHost *:443>
ServerName openclaw.<TU_DOMINIO>
ProxyPreserveHost On
ProxyPass / http://localhost:18789/
ProxyPassReverse / http://localhost:18789/
RewriteEngine On
RewriteCond %{HTTP:Upgrade} websocket [NC]
RewriteCond %{HTTP:Connection} upgrade [NC]
RewriteRule ^/?(.*) ws://localhost:18789/$1 [P,L]
SSLCertificateFile /etc/letsencrypt/live/openclaw.<TU_DOMINIO>/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/openclaw.<TU_DOMINIO>/privkey.pem
Include /etc/letsencrypt/options-ssl-apache.conf
</VirtualHost>
</IfModule>
EOF
sudo systemctl reload apache2El certificado se renueva automáticamente cada 90 días via un timer de systemd que certbot configura.
Paso 3: Desactivar device pairing
Ahora que tenemos HTTPS, desactivamos el requisito de aprobar dispositivos por SSH:
# Desactivar device pairing
openclaw config set gateway.controlUi.dangerouslyDisableDeviceAuth true
# Añadir tu dominio a los orígenes permitidos
openclaw config set gateway.controlUi.allowedOrigins \
'["https://openclaw.<TU_DOMINIO>"]'
# Reiniciar gateway
openclaw gateway restartCon esto, cualquier navegador que tenga el token del gateway puede conectarse. El token se pasa en el fragmento de la URL:
https://openclaw.<TU_DOMINIO>/#token=<TU_GATEWAY_TOKEN>dangerouslyDisableDeviceAuth se llama "dangerous" por una razón — cualquiera con el token puede entrar. Por eso es OBLIGATORIO combinarlo con Cloudflare Access (paso 4). Sin esa capa, estarías exponiendo tu gateway a quien conozca la URL.Paso 4: Cloudflare Access (autenticación por email)
Cloudflare Access añade la capa de autenticación que falta: antes de que nadie llegue a tu gateway, Cloudflare le pide que se identifique con su email. Si el email no está en tu lista, no pasa.
Configurar el registro DNS
El registro DNS de tu subdominio debe tener el proxy activado (nube naranja) para que Cloudflare intercepte el tráfico:
Tipo: A
Nombre: openclaw
Contenido: <IP_DE_TU_SERVIDOR>
Proxy: Activado (nube naranja)Crear la aplicación de Access
En el dashboard de Cloudflare Zero Trust (one.dash.cloudflare.com):
- Access → Applications → Add an application
- Tipo: Self-hosted
- Application domain:
openclaw.<TU_DOMINIO> - Session duration: 24 hours
Crear la política de acceso
- Add a policy
- Policy name:
Equipo autorizado - Action: Allow
- Include → Emails: los emails que quieras autorizar
Cuando alguien intenta acceder, Cloudflare le pide su email, le envía un código de un solo uso, y solo si el email está en la lista le deja pasar. La sesión dura 24 horas — no le vuelve a pedir código hasta el día siguiente.
Gotchas que descubrimos (para que no te pase)
Llegamos a esta solución después de probar varios caminos que NO funcionaron. Aquí van los aprendizajes para que no pierdas el tiempo:
- Cloudflare Access bloquea WebSocket a través de Tunnels — las peticiones de upgrade nunca llegan al origin. Funciona con Apache directo.
- trusted-proxy y token son mutuamente excluyentes — OpenClaw no permite tener
gateway.auth.mode: "trusted-proxy"ygateway.auth.tokenal mismo tiempo. Elegimos token + Access. - SSL "Flexible" = redirect loop — Cloudflare envía HTTP al origin → Apache redirige a HTTPS → Cloudflare reenvía HTTP → bucle infinito. Solución: SSL Full (Strict).
- DNS proxy OFF para certbot — el ACME challenge de Let's Encrypt necesita que el tráfico llegue directo al servidor. Genera el certificado con proxy OFF, luego actívalo.
- ProxyPreserveHost On es esencial — sin él, el gateway recibe
localhostcomo Host y rechaza la conexión por origin mismatch.
Arquitectura: diagrama completo

El flujo completo
Navegador del alumno
│
▼
Cloudflare Edge (HTTPS)
│ ← Access: ¿email autorizado? → Código por email
▼
Apache :443 (Let's Encrypt TLS)
│ ← ProxyPass + mod_proxy_wstunnel
▼
OpenClaw Gateway :18789 (loopback)
│ ← Token auth (sin device pairing)
▼
Dashboard Control UI ✓Tres capas: Cloudflare Access controla quién (email), HTTPS cifra la comunicación, y el token autoriza la conexión WebSocket. El puerto 18789 nunca se expone al exterior.
Para un curso: setup por máquina en 5 comandos
Con un snapshot de Lightsail como base (que ya tiene Apache, certbot y OpenClaw configurados), cada nueva máquina de alumno se configura así:
# 1. Nuevo token de gateway (único por máquina)
openclaw config set gateway.auth.token $(openssl rand -base64 24)
# 2. DNS: crear A record → IP del alumno (proxy OFF inicialmente)
# openclaw-alumnoX.tudominio.com → IP_ALUMNO
# 3. Certificado SSL
sudo certbot --apache -d openclaw-alumnoX.<TU_DOMINIO> \
--non-interactive --agree-tos -m <TU_EMAIL>
# 4. Actualizar Apache vhost con el dominio del alumno
sudo sed -i 's/openclaw.<TU_DOMINIO>/openclaw-alumnoX.<TU_DOMINIO>/g' \
/etc/apache2/sites-available/openclaw-le-ssl.conf
sudo systemctl reload apache2
# 5. Activar proxy en DNS + añadir email del alumno a Access policyEn menos de dos minutos, cada alumno tiene su propia instancia con HTTPS, sin SSH, protegida por email.
Conclusión
El device pairing de OpenClaw es una buena medida de seguridad para uso individual. Pero para escenarios con múltiples usuarios — cursos, equipos, demos — necesitas una alternativa. La combinación de Apache + Let's Encrypt + Cloudflare Access te da seguridad real sin la fricción de SSH.
Lo más importante: nunca desactives el device pairing sin poner otra capa de autenticación encima. El dangerouslyDisableDeviceAuth sin Cloudflare Access es como quitar la cerradura de tu puerta y dejar la llave debajo del felpudo.
Si tienes preguntas o quieres montar algo similar, escríbenos a [email protected].