Mi homelab Proxmox + Cloudflare Tunnel: stack y por qué

Cómo expongo proyectos públicos en internet desde mi servidor casero sin abrir un solo puerto en el router, sin pagar VPS, y con HTTPS automático.


Todo lo que ves en lalu.dev, oficina.lalu.dev, agents.lalu.dev, blog.lalu.dev, security.lalu.dev, ai.lalu.dev corre en una computadora bajo mi escritorio. Cero AWS, cero Vercel, cero Railway. Cuesta lo que cuesta la luz (~$5 USD/mes).

Esta es la receta exacta.

El hardware

Un mini-PC con:

Total: ~$300 USD comprado hace un año. Funciona.

La arquitectura

Internet


Cloudflare (HTTPS, DDoS, WAF, cache)

   ▼ Cloudflare Tunnel (outbound-only, sin abrir puertos)


[ VM Ubuntu en Proxmox ]

   ├── nginx           ← entry point HTTP
   ├── Docker Compose  ← 11+ containers
   │   ├── portafolio (estático)
   │   ├── blog (Astro estático)
   │   ├── oficina-virtual (React)
   │   ├── agents-discord (bot Python)
   │   ├── ops-db (Postgres)
   │   └── ...
   └── otros servicios

Por qué Proxmox

Podría tener todo en una VM Ubuntu pelada. Pero Proxmox me da:

Para self-hosting serio, vale la pena la capa extra. Para hobby — Docker directo en Ubuntu basta.

Por qué Cloudflare Tunnel (vs port forwarding)

Antes lo hacía con port forwarding clásico:

  1. Reenviar puerto 80/443 del router a la VM
  2. Caddy/nginx con Let’s Encrypt
  3. DNS apuntando a mi IP residencial

Funcionaba. Pero:

Cloudflare Tunnel cambia el modelo. La VM inicia una conexión saliente a Cloudflare. Cloudflare hace de proxy reverso. Nadie del internet conoce mi IP residencial. Nadie puede escanearme.

Es gratis, incluso para tráfico ilimitado. Cloudflare lo subsidia porque les da datos de tráfico web global.

El setup, paso a paso

1. Instalar cloudflared en la VM

curl -L --output cloudflared.deb \
  https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64.deb
sudo dpkg -i cloudflared.deb

2. Crear el tunnel en Cloudflare

En el dashboard de Zero Trust:

3. Correrlo como container

Mi docker-compose.yml:

tunnel:
  image: cloudflare/cloudflared:latest
  restart: always
  command: tunnel --no-autoupdate run --token ${CLOUDFLARE_TOKEN}

El token está en .env (chmod 600). El container inicia la conexión a Cloudflare y se queda escuchando.

4. Mapear hostnames → servicios

En Tunnels → tu tunnel → Public Hostnames → Add a public hostname:

HostnameService
lalu.devhttp://nginx:80
blog.lalu.devhttp://blog:80
oficina.lalu.devhttp://oficina-virtual:80
agents.lalu.devhttp://agents-discord:8080

Cloudflare resuelve blog.lalu.dev → tu tunnel → tu container blog:80. Magia, pero entendible.

5. DNS automático

Cuando agregas un public hostname, Cloudflare crea automáticamente el CNAME en tu zona DNS. No tocas DNS a mano.

El SSL/HTTPS — gratis y automático

Cloudflare termina el HTTPS en su edge. Dentro del tunnel todo es HTTP plano (es túnel cifrado de extremo a extremo entre cloudflared y CF, así que no importa que sea HTTP en mi LAN). Yo no manejo certificados.

Si quieres HTTPS también dentro de tu LAN (defense-in-depth), puedes poner Caddy en medio. Para la mayoría de casos, sobra.

Lo que no me funcionó

Tailscale Funnel: similar concepto, pero más restringido (solo 3 hostnames free, sin custom domain en plan free). Para hobby, podría funcionar. Para vender servicios bajo tu dominio, no.

Ngrok: ideal para development, no para producción permanente. El plan free reasigna URLs.

Wireguard VPN + IP fija: te obliga a un VPS público, que es lo que querías evitar.

El truco del Zero Trust Access

Cloudflare Tunnel viene con un bonus: Access policies. Para mi /dashboard administrativo, agregué:

Application: agents.lalu.dev/dashboard Policy: Email is [email protected] Method: One-time PIN

Resultado: para acceder a mi dashboard interno, tengo que verificar mi email con un PIN. Sin VPN, sin password manager, sin que el endpoint sea públicamente accesible. Gratis hasta 50 usuarios.

El elefante en el cuarto: ¿qué pasa cuando se va la luz?

Tu homelab no tiene 99.9% uptime. Si se va la luz, todo cae.

Mis mitigaciones:

  1. UPS pequeño ($60 USD) — aguanta cortes cortos, da tiempo a shutdown ordenado
  2. BIOS “Restore on AC Power Loss: Power On” — cuando vuelve la luz, el host arranca solo
  3. Docker restart: always — los containers se levantan con el host
  4. VM autostart en Proxmox — la VM arranca con el host

Sin UPS, los cortes son inevitables. Si tu negocio depende de 24/7 garantizado, considera:

Para freelance de proyectos puntuales — el self-hosting es perfectamente válido.

Costos reales del mes

ConceptoMes
Mini-PC (amortizado a 5 años)~$5
Electricidad (~30W promedio)~$3
Cloudflare (todos los servicios usados)$0
Dominios (4 a $12/año c/u)$4
Anthropic API (11 agentes)~$5
Total~$17 USD

Para comparar: Vercel Pro + Railway + Supabase + Anthropic + dominios = $100-200 USD/mes fácil.

Cuándo NO uses esto

Para todo lo demás — portafolios, blogs, MVPs, side-projects, herramientas internas, proyectos freelance — self-hosting con Proxmox + Cloudflare Tunnel es óptimo.


Si quieres ver el sistema funcionando, todo lo que está en lalu.dev corre exactamente en este setup. Los stats live de oficina.lalu.dev vienen de esta misma máquina.


← todos los posts