TL;DR — Resumen Rápido

Guía completa de Caddy como proxy inverso con HTTPS automático. Configura SSL sin esfuerzo, balanceo de carga, verificaciones de salud y hosting multi-sitio.

Caddy es un servidor web en Go que convierte el HTTPS automático en el comportamiento predeterminado, no en una tarea adicional. A diferencia de Nginx o Apache donde TLS implica instalar certbot, escribir scripts de renovación y depurar cron jobs, Caddy negocia certificados con Let’s Encrypt o ZeroSSL en el momento en que agregas un dominio a tu configuración.

Requisitos Previos

  • Un servidor Linux (Ubuntu 22.04/24.04, Debian, RHEL o Docker).
  • Un dominio con registros DNS A apuntando a la IP pública de tu servidor.
  • Puertos 80 y 443 abiertos en el firewall — Caddy los necesita para el desafío ACME HTTP-01.
  • Servicios backend ejecutándose en puertos localhost (Node.js, Python, PHP, etc.).

Arquitectura de Caddy

Caddy es un binario estático único escrito en Go sin dependencias de tiempo de ejecución.

HTTPS automático via ACME. Cuando configuras un dominio, Caddy:

  1. Detecta que el dominio requiere un certificado.
  2. Ejecuta un desafío ACME HTTP-01 o TLS-ALPN-01.
  3. Almacena el certificado en ~/.local/share/caddy/ (o /var/lib/caddy/ para instalaciones del sistema).
  4. Programa la renovación 30 días antes del vencimiento — automáticamente.
  5. Adjunta respuestas OCSP a los handshakes TLS para verificaciones más rápidas de revocación.

API de administración. Caddy expone una API REST en localhost:2019 para cambios de configuración en vivo — sin necesidad de reiniciar.


Instalación

apt (Ubuntu/Debian — recomendado)

sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https curl
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' \
  | sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' \
  | sudo tee /etc/apt/sources.list.d/caddy-stable.list
sudo apt update && sudo apt install caddy

Docker

docker run -d \
  --name caddy \
  -p 80:80 -p 443:443 -p 443:443/udp \
  -v $PWD/Caddyfile:/etc/caddy/Caddyfile \
  -v caddy_data:/data \
  caddy:latest

xcaddy — Compilaciones Personalizadas con Plugins

xcaddy build \
  --with github.com/caddy-dns/cloudflare \
  --with github.com/mholt/caddy-ratelimit

Sintaxis del Caddyfile

Bloques de sitio:

example.com {
    reverse_proxy localhost:3000
}

Opciones globales:

{
    email admin@example.com
}

Fragmentos reutilizables:

(cabeceras_comunes) {
    header {
        X-Content-Type-Options nosniff
        X-Frame-Options DENY
        -Server
    }
}

example.com {
    import cabeceras_comunes
    reverse_proxy localhost:3000
}

Configuración del Proxy Inverso

Proxy Inverso Básico

example.com {
    reverse_proxy localhost:3000
}

Caddy gestiona automáticamente la redirección HTTP→HTTPS, la emisión del certificado, la renovación y el grapado OCSP.

Balanceo de Carga

example.com {
    reverse_proxy app1:3000 app2:3000 app3:3000 {
        lb_policy round_robin
    }
}
PolíticaDescripción
round_robinDistribuye solicitudes uniformemente entre backends
least_connDirige al backend con menos conexiones activas
ip_hashHash de IP del cliente para sesiones fijas
cookieUsa una cookie para persistencia de sesión
uri_hashHash de la URI de la solicitud

Verificaciones de Salud Activas y Pasivas

example.com {
    reverse_proxy app1:3000 app2:3000 {
        lb_policy least_conn
        health_uri /health
        health_interval 10s
        health_timeout 5s
        fail_duration 30s
        max_fails 3
    }
}

Manipulación de Cabeceras

example.com {
    reverse_proxy localhost:3000 {
        header_up X-Real-IP {remote_host}
        header_up X-Forwarded-Proto {scheme}
        header_down -Server
        header_down -X-Powered-By
    }
}

HTTPS Automático en Profundidad

Cómo Caddy Obtiene Certificados

  1. Llega una solicitud para example.com.
  2. Caddy verifica su almacén de certificados — no se encuentra ninguno.
  3. Caddy ejecuta un desafío ACME HTTP-01.
  4. El servidor ACME (Let’s Encrypt) verifica el token.
  5. Caddy recibe el certificado firmado y lo almacena.
  6. HTTP redirige automáticamente a HTTPS.
  7. Caddy renueva el certificado 30 días antes del vencimiento.

TLS Bajo Demanda

Para plataformas SaaS donde los usuarios agregan dominios personalizados:

{
    on_demand_tls {
        ask http://localhost:8080/verificar-dominio
        interval 2m
        burst 5
    }
}

CA Interna para Desarrollo Local

localhost {
    tls internal
    reverse_proxy localhost:3000
}

Ejecuta caddy trust para instalar la CA local de Caddy en el almacén de confianza del sistema.


Patrones Comunes del Caddyfile

SPA con Enrutamiento del Lado del Cliente

app.example.com {
    root * /var/www/app
    try_files {path} /index.html
    file_server
}

PHP con PHP-FPM

php.example.com {
    root * /var/www/php-app
    php_fastcgi unix//run/php/php8.3-fpm.sock
    file_server
}

Servidor de Archivos Estáticos con Compresión

files.example.com {
    root * /var/www/archivos
    encode gzip zstd
    file_server browse
}

Caddy vs Nginx vs Traefik vs HAProxy

CaracterísticaCaddyNginxTraefikHAProxy
HTTPS automáticoIntegrado, predeterminadoManual (certbot)IntegradoManual
Sintaxis de configuraciónSimple CaddyfileComplejo nginx.confYAML/TOMLComplejo
Recarga en tiempo realSí (API + señal)Sí (señal)
Balanceo de carga8 políticasRound-robin, IP hashMúltiplesExtenso
API de administraciónREST JSONNoREST JSONSocket
HTTP/3 (QUIC)Sí (v1.25+)No
Mejor paraHTTPS automático, simplicidadArchivos estáticos de alto rendimientoDocker/K8sBalanceo TCP

Caddyfile de Producción: Hosting Multi-Sitio

{
    email ops@example.com
    admin localhost:2019
}

(cabeceras_seguridad) {
    header {
        X-Content-Type-Options nosniff
        X-Frame-Options SAMEORIGIN
        Referrer-Policy strict-origin-when-cross-origin
        -Server
    }
}

app.example.com {
    import cabeceras_seguridad
    encode gzip zstd

    reverse_proxy app1:3000 app2:3000 {
        lb_policy least_conn
        health_uri /health
        health_interval 15s
        fail_duration 30s
    }
}

api.example.com {
    import cabeceras_seguridad
    reverse_proxy localhost:8080 {
        header_up X-Real-IP {remote_host}
        header_up X-Forwarded-Proto {scheme}
    }
}

www.example.com {
    import cabeceras_seguridad
    encode gzip zstd
    root * /var/www/marketing
    try_files {path} /index.html
    file_server
}

example.com {
    redir https://www.example.com{uri} 301
}

Errores Comunes y Casos Especiales

  • El puerto 80 debe ser accesible. Caddy usa el desafío ACME HTTP-01. Si el puerto 80 está bloqueado, usa el desafío DNS-01 con un plugin DNS via xcaddy.
  • Límites de tasa en Let’s Encrypt. Máximo 50 certificados por dominio por semana. Usa la CA de staging durante las pruebas.
  • header_up Host puede romper algunos backends. Prueba primero sin esta directiva.
  • La API de administración es solo localhost por defecto. Nunca expongas el puerto 2019 públicamente.
  • Recarga vs reinicio. Usa siempre systemctl reload caddy en producción para evitar tiempo de inactividad.

Resumen

  • HTTPS automático — Caddy obtiene y renueva certificados de Let’s Encrypt/ZeroSSL sin configuración.
  • Sintaxis simple — Cinco líneas en el Caddyfile reemplazan cientos de líneas de configuración de Nginx.
  • 8 políticas de balanceo de carga — incluyendo sesiones fijas via cookie e IP hash.
  • Verificaciones de salud activas y pasivas — elimina y re-agrega backends fallidos automáticamente.
  • TLS bajo demanda — emite certificados dinámicamente para dominios de usuarios.
  • API REST de administración — cambios de configuración en vivo en localhost:2019 sin reinicios.

Artículos Relacionados