Diseño e implementación de una arquitectura de acceso remoto desde una red corporativa con restricciones estrictas. Tres intentos fallidos, una solución que combina Cloudflare Tunnel, Let's Encrypt vía ACME y Cloudflare Access con doble factor.
El objetivo era poder gestionar un servidor Proxmox VE doméstico de forma remota desde una red externa con restricciones. El entorno tenía tres restricciones combinadas que cerraron las soluciones habituales y obligaron a buscar una arquitectura alternativa.
tun del kernel. Sin ese módulo, cualquier solución VPN basada en interfaces virtuales es inviable — el kernel no puede crear la interfaz de red virtual necesaria.
Con VPN descartada, la siguiente opción fue un túnel SSH inverso: Proxmox establece una conexión SSH saliente hacia el VPS, el VPS expone un puerto en localhost, y desde el equipo cliente se abre un segundo túnel SSH hacia ese puerto. Esta arquitectura no requiere instalar nada en el equipo cliente (OpenSSH está disponible por defecto en Windows 10/11) y no depende de módulos de kernel especiales.
Se implementó completamente:
tunnel sin shell en ambas máquinas, solo para túnelesauthorized_keysautossh como servicio systemd en Proxmox para recuperación automáticaiptables en el VPS restringiendo el puerto del túnel a una IP autorizadaGatewayPorts no para que el puerto no sea accesible desde internet192.168.x.x:8006, el paquete no llegaba al destino — 100% packet loss desde el VPS hacia cualquier IP privada.
Cloudflare Tunnel permite exponer servicios internos a través de una conexión saliente desde un LXC hacia la infraestructura de Cloudflare, sin abrir puertos en el router. No requiere IP pública estática, no depende del ISP, y no necesita instalar nada en la red de destino.
Full (Strict) lo rechazaba. Con Full daba error 502 porque cloudflared no podía verificar el certificado. La opción noTLSVerify sí existe en el dashboard de Cloudflare Zero Trust (en los ajustes adicionales de la aplicación publicada, sección TLS → No TLS Verify), pero en su momento no la localicé y probé antes la vía del fichero de configuración YAML. Aun así, desactivar la verificación deja sin validar el tramo túnel → Proxmox: la solución que acabé adoptando (un certificado válido) mantiene la verificación estricta.
noTLSVerify: true → conflicto con credenciales (el túnel por token no usa fichero de credenciales local)Full en vez de Full (Strict) → seguía dando 502 por el certificado autofirmadoLa arquitectura definitiva combina tres componentes que resuelven conjuntamente lo que ninguno resolvía por separado.
Antes de nada, un LXC mínimo dedicado solo a correr cloudflared — separado de Proxmox y de cualquier otro servicio, para que el túnel no dependa de ninguna otra pieza del homelab. Ahí se configura todo lo relativo al túnel: instalación de cloudflared, autenticación con Cloudflare, creación del túnel y el public hostname que lo enlaza con Proxmox.
Al ser el punto único por el que se accede a Proxmox en remoto, este LXC tiene que estar operativo 24/7 — incluido justo después de un reinicio del propio Proxmox, sin intervención manual. Eso significa activar Start at boot (onboot: 1) en las opciones del contenedor.
Se emite un certificado válido directamente en Proxmox usando el challenge DNS-01 de Let's Encrypt con el plugin de Cloudflare. Esto elimina el certificado autofirmado sin necesidad de exponer el puerto 80 a internet.
El plugin de Cloudflare crea automáticamente un registro TXT _acme-challenge en el DNS, Let's Encrypt lo verifica, y emite el certificado. Proxmox lo instala y renueva automáticamente a partir de los 60 días de vida (el certificado dura 90).
Con el certificado válido, Cloudflare Tunnel puede conectar con verificación Full (Strict). Sin embargo, surgía un problema adicional: cuando cloudflared intentaba conectar a homelab.hjs.es:8006, el DNS resolvía a la IP pública de Cloudflare (no a la IP local de Proxmox), creando un bucle.
Solución: entrada en /etc/hosts del LXC de cloudflared apuntando el dominio a la IP local de Proxmox. El certificado coincide con el hostname y la conexión TLS valida correctamente.
Delante del túnel, Cloudflare Access actúa como capa de autenticación con dos reglas obligatorias (AND): restricción por IP de origen autorizada + OTP por email de un solo uso.
https://homelab.hjs.esRed restringida (cliente) │ │ HTTPS puerto 443 ▼ Cloudflare Edge │ │ Cloudflare Access │ → verifica IP autorizada │ → verifica OTP email ▼ Cloudflare Tunnel │ │ conexión saliente iniciada desde el LXC │ sin puertos abiertos en el router doméstico ▼ LXC cloudflared /etc/hosts → IP local de Proxmox │ │ HTTPS con certificado Let's Encrypt válido ▼ Proxmox VE :8006 certificado: homelab.hjs.es emisor: Let's Encrypt renovación: automática via ACME + Cloudflare DNS plugin
| Hipervisor | Proxmox VE 9.2 (Debian 13) |
| Contenedor tunnel | LXC Debian 13, cloudflared 2026.6.1 |
| Certificado TLS | Let's Encrypt via ACME (DNS-01) |
| DNS y CDN | Cloudflare (plan Free) |
| Autenticación | Cloudflare Access (Zero Trust) |
| Hardware | Intel i5 6ª gen · 16 GB RAM · 240 GB SSD |
| Sin puertos abiertos | Cloudflare Tunnel (conexión saliente) |
| Restricción de red | Cloudflare Access: solo IP autorizada |
| Autenticación | OTP por email, segundo factor obligatorio |
| Cifrado TLS | Let's Encrypt, Full Strict, TLS 1.3 |
| Sesión limitada | Expiración automática en 24h |
/etc/hosts para que la validación TLS funcione correctamente.
Referencia de uso diario para mantener este acceso, sin tener que reconstruir el razonamiento cada vez.
Para levantar el LXC dedicado a cloudflared sin instalarlo todo a mano, uso el script de Proxmox VE Helper-Scripts (comunidad, antes tteck). Se ejecuta desde la shell del propio Proxmox:
bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/ct/cloudflared.sh)"
Documentación del script: community-scripts.org/scripts/cloudflared. Tras crear el LXC, dentro del contenedor: cloudflared tunnel login y cloudflared tunnel create <nombre> (o crear el túnel directamente desde el dashboard de Cloudflare Zero Trust → Networks → Tunnels).
Como este LXC tiene que estar arriba siempre — incluido justo después de reiniciar Proxmox —, hay que activar Start at boot:
# Desde la shell de Proxmox (sustituye <ID_LXC> por el ID real, ej. 101): pct set <ID_LXC> --onboot 1 # Comprobar que ha quedado activado: pct config <ID_LXC> | grep onboot
O desde la GUI: selecciona el LXC → pestaña Options → Start at boot → Edit → Yes.
La renovación es automática, pero si hace falta comprobarla o forzarla:
# Ver estado y fecha de expiración del certificado activo: pvenode cert info # Forzar renovación manual vía ACME: pvenode acme cert renew
# Estado del servicio cloudflared: systemctl status cloudflared # Confirmar que /etc/hosts resuelve al Proxmox local, no a Cloudflare: cat /etc/hosts | grep homelab.hjs.es
Revisar en el dashboard de Cloudflare Zero Trust → Access → Applications, que la regla de IP autorizada siga apuntando a la IP pública actual de la red de origen (puede cambiar si su ISP no ofrece IP fija).