Saltar al contenido principal
intermedioPart 2

Asegurar OpenClaw con un proxy inverso Caddy + HTTPS

· 9 min de lectura
Rafael Fernandes
Ingeniero de PLN y Redactor Técnico en WiLine
Share:
OpenClaw+
0/6
🎯 Skill path0/6 earned
Self-hosting OpenClaw

En Artículo 1 hicimos funcionar OpenClaw — pero solo a través de HTTP sin cifrar, con un workaround allowInsecureAuth. Aquí colocamos Caddy frente a él como un proxy inverso: verdadero HTTPS, autenticación emparejada por dispositivo, y los puertos del gateway cerrados para que el proxy sea la única forma de acceso. Cada comando y error a continuación proviene de la implementación real.

Reproducibilidad

Continúa desde el Artículo 1 en la misma instancia WEC — Ubuntu 22.04.5 LTS, OpenClaw 2026.6.8. Usamos Caddy 2 (caddy:2). Debido a que esta máquina no tiene un dominio público, usamos la CA interna de Caddy (tls internal) para HTTPS autofirmado; la sección Pasando a producción muestra el cambio de una línea a certificados reales de Let's Encrypt una vez que tengas un dominio.


Lo que construirás

Caddy termina HTTPS y hace un proxy inverso al gateway de OpenClaw a través de la red interna de Docker. El gateway deja de publicar sus propios puertos — el único punto de entrada se convierte en Caddy en :443.


Requisitos previos

  • Artículo 1 completado — OpenClaw funcionando en ~/openclaw
  • Acceso a la terminal de la VM
  • Un nombre de host para el gateway. Con un dominio público, úsalo (y obtén certificados reales de Let's Encrypt). En una máquina privada, usamos openclaw.local + una entrada en hosts.

Paso 1 — Confirma el punto de partida

cd ~/openclaw
docker compose ps

Deberías ver openclaw-gateway Up (healthy), publicando 18789/18790/3978. Ese es nuestro estado inicial: funcionando, pero solo HTTP.

docker compose ps mostrando el gateway en funcionamiento


Paso 2 — Escribe el Caddyfile

La configuración de Caddy: servir HTTPS y hacer proxy a todo al gateway. tls internal usa la propia CA local de Caddy — no se necesita un dominio público.

cat > Caddyfile <<'EOF'
# Caddy selecciona su certificado por SNI (el nombre de host en el apretón de manos TLS).
# Una IP desnuda no envía SNI, así que usamos un nombre de host. Con un dominio público, coloca tu
# dominio aquí y elimina `tls internal` para Let's Encrypt automático.
openclaw.local {
tls internal
reverse_proxy openclaw-gateway:18789
}
EOF

El objetivo del proxy es openclaw-gateway:18789 — Caddy accede al gateway por su nombre de servicio de Compose a través de la red compartida de Docker.


Paso 3 — Agrega Caddy a Compose

docker compose fusiona automáticamente un docker-compose.override.yml, así que agregamos un servicio caddy sin tocar el archivo de compose oficial de OpenClaw:

cat > docker-compose.override.yml <<'EOF'
services:
caddy:
image: caddy:2
restart: unless-stopped
ports:
- "80:80"
- "443:443"
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile:ro
- caddy_data:/data
- caddy_config:/config

volumes:
caddy_data:
caddy_config:
EOF

caddy_data persiste la CA local + certificados a través de reinicios.


Paso 4 — Inicia Caddy

docker compose up -d
docker compose ps

Caddy se inicia junto al gateway con 443 publicado, y genera su CA interna + un certificado en la primera ejecución.

Contenedor de Caddy en funcionamiento con 443 publicado

nota

docker compose up -d también inicia el ayudante de un solo uso openclaw-cli; su inactividad aquí es inofensiva — lo invocamos con docker compose run --rm cuando es necesario.


Paso 5 — Verifica HTTPS

Accede al endpoint de salud del gateway a través de Caddy. --resolve hace que curl envíe el nombre de host (SNI) mientras apunta a la máquina:

curl -k --resolve openclaw.local:443:127.0.0.1 https://openclaw.local/healthz
# {"ok":true,"status":"live"}

healthz devolviendo a través de HTTPS vía Caddy

¿Recibes un tlsv1 alert internal error?

Eso sucede si usaste una IP desnuda como dirección del sitio — consulta Solución de problemas #1. Usa un nombre de host.


Paso 6 — Reasegura el gateway

Ahora el tráfico llega a través de https://openclaw.local. Dos cambios de configuración:

  1. Agrega el origen HTTPS a allowedOrigins (la UI de Control rechaza orígenes desconocidos).
  2. Desactiva allowInsecureAuth — HTTPS es un contexto seguro, por lo que el workaround del Artículo 1 ya no es necesario.
docker compose run --rm --no-deps --entrypoint node openclaw-gateway \
dist/index.js config set --batch-json '[{"path":"gateway.controlUi.allowedOrigins","value":["https://openclaw.local"]},{"path":"gateway.controlUi.allowInsecureAuth","value":false}]'

docker compose restart openclaw-gateway

Paso 7 — Empareja tu navegador

Abre https://openclaw.local/ en tu navegador (en una máquina privada, primero mapea 10.80.4.212 openclaw.local en el archivo hosts de tu máquina — /etc/hosts en macOS/Linux, o C:\Windows\System32\drivers\etc\hosts editado como Administrador en Windows).

Primero recibirás una advertencia de certificado"Tu conexión no es privada" (NET::ERR_CERT_AUTHORITY_INVALID). Esto es esperado con tls internal: el certificado está firmado por la CA local de Caddy, que tu sistema operativo no confía. Haz clic en Avanzado → Proceder a openclaw.local (inseguro) para continuar. (Con un dominio real + Let's Encrypt, el certificado es públicamente confiable y esta advertencia nunca aparece — consulta Pasando a producción.)

Advertencia de certificado del navegador — haz clic en Avanzado, luego Proceder

Ahora la página se carga — pero con allowInsecureAuth desactivado, el gateway requiere emparejamiento de dispositivo antes de que este navegador pueda usar la UI de Control. Ese es el flujo seguro haciendo su trabajo. La pantalla muestra un id de solicitud; apruébalo en el host:

docker compose run --rm openclaw-cli devices approve <request-id-from-the-screen>

Pantalla que requiere emparejamiento de dispositivo

De vuelta en el navegador, haz clic en Conectar nuevamente — se empareja y carga el panel.


Paso 8 — Cierra el acceso directo (el verdadero endurecimiento)

El gateway aún publica 18789 al host, por lo que http://<vm-ip>:18789 es todavía accesible en HTTP sin cifrar, eludiendo a Caddy. Ciérralo: deja de publicar los puertos del gateway para que Caddy en :443 sea la única puerta. Caddy aún puede acceder a él a través de la red interna.

cat > docker-compose.override.yml <<'EOF'
services:
openclaw-gateway:
# Deja de publicar los puertos del host del gateway — Caddy accede a él internamente, así que el
# único punto de entrada es HTTPS en :443.
ports: !reset []

caddy:
image: caddy:2
restart: unless-stopped
ports:
- "80:80"
- "443:443"
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile:ro
- caddy_data:/data
- caddy_config:/config

volumes:
caddy_data:
caddy_config:
EOF
docker compose up -d

ports: !reset [] limpia los puertos que el compose base publicó.


Paso 9 — Prueba que está bloqueado

curl -s -m 5 http://<vm-ip>:18789/healthz ; echo " <- HTTP directo (debería FALLAR)"
curl -sk --resolve openclaw.local:443:127.0.0.1 https://openclaw.local/healthz ; echo " <- a través de Caddy (debería funcionar)"

El primero no devuelve nada (conexión rechazada) — la puerta insegura ha desaparecido. El segundo aún devuelve {"ok":true,"status":"live"}.

Antes/después: puerto directo rechazado, HTTPS funciona

Tu OpenClaw ahora es accesible solo a través de HTTPS, emparejado por dispositivo.

UI de Control de OpenClaw sobre HTTPS

Habilidad desbloqueada 🏅

Ahora puedes poner verdadero HTTPS y autenticación frente a cualquier servicio autoalojado — y probar que la puerta trasera está cerrada.


Solución de problemas (errores reales)

1. tlsv1 alert internal error

Ocurre cuando la dirección del sitio en el Caddyfile era una IP desnuda (https://10.80.4.212):

curl: (35) error:0A000438:SSL routines::tlsv1 alert internal error

Los registros de Caddy mostraron que el certificado se obtuvo correctamente. Causa: TLS selecciona un certificado por SNI (el nombre de host en el apretón de manos), pero las conexiones a una IP desnuda no envían SNI — así que Caddy no puede coincidir un certificado y aborta. Solución: usa una dirección de sitio con nombre de host (Paso 2). Un lector con un dominio real nunca enfrenta esto — el dominio es el SNI.

2. Se requiere emparejamiento de dispositivo

En la primera conexión HTTPS después de desactivar allowInsecureAuth:

Se requiere emparejamiento de dispositivo — Este navegador necesita una aprobación única del host del Gateway
antes de que pueda usar la UI de Control.

Causa: este es el flujo seguro correcto — con la autenticación insegura desactivada, cada nuevo navegador debe ser aprobado. Solución: docker compose run --rm openclaw-cli devices approve <request-id>. (El CLI puede registrar scope upgrade pending approval … using local fallback pero aún completa la aprobación.)

3. NET::ERR_CERT_AUTHORITY_INVALID

Esperado con tls internal — el certificado está firmado por la CA local de Caddy, que tu sistema operativo no confía. Haz clic para continuar en una máquina privada. Con un dominio público + Let's Encrypt (a continuación), el certificado es confiable y no hay advertencia.


Pasando a producción

Con un dominio real, intercambia dos líneas en el Caddyfile — apúntalo a tu dominio y elimina tls internal:

- openclaw.local {
- tls internal
+ openclaw.example.com {
reverse_proxy openclaw-gateway:18789
}

Luego apunta el registro A del dominio a la IP pública de la VM y abre 80 + 443 a Internet. Caddy automáticamente provisiona y renueva un certificado de Let's Encrypt — confiable, sin advertencias, sin --resolve o /etc/hosts necesarios. Actualiza allowedOrigins a https://openclaw.example.com.


Notas de seguridad

  • Único punto de entrada — solo el :443 de Caddy está expuesto; el gateway no tiene puertos de host (Paso 8).
  • Emparejamiento de dispositivo — cada navegador necesita aprobación única (openclaw devices).
  • Lista de orígenes permitidos — la UI de Control solo acepta https://openclaw.local.
  • Rotar secretos — regenera OPENCLAW_GATEWAY_TOKEN si alguna vez ha sido mostrado (capturas de pantalla, comparticiones de pantalla).

Finished this tutorial?
Mark it complete to earn Real HTTPS + auth on your skill path.

¿Qué sigue?

Has terminado Parte 2 de la serie Autoalojamiento de OpenClaw. A continuación:

Los archivos complementarios (Caddyfile, docker-compose.override.yml) se encuentran en el repositorio de manifiestos de WiLine (enlace que vendrá con el repositorio).


Desmontaje

Para eliminar solo Caddy y reabrir los puertos directos, elimina docker-compose.override.yml y Caddyfile, luego docker compose up -d. Para detener todo:

docker compose down

Comments & questions

Hit an error, spotted a typo, or have a question? Leave a note below.