ARQUITECTURA HTTPS AUTOMATICO DE CADDY Clientes Navegador / API Movil / CLI HTTPS :443 Caddy Server HTTPS Auto (ACME) Proxy Inverso Balanceo de Carga Compresion HTTP/2 & HTTP/3 reverse_proxy HTTP Node.js :3000 app.ejemplo.com Python :8000 api.ejemplo.com Docker :9000 admin.ejemplo.com Let's Encrypt ACME CA Caddy obtiene certificados automaticamente y redirige a tus backends

Caddy es un servidor web moderno y de codigo abierto escrito en Go que destaca por una caracteristica principal: HTTPS automatico. Mientras que servidores web tradicionales como Nginx y Apache requieren configuracion manual de certificados con Certbot u herramientas similares, Caddy obtiene y renueva certificados TLS de Let’s Encrypt en el momento en que apuntas un dominio hacia el. Combinado con su sintaxis de configuracion minima, proxy inverso integrado y soporte para HTTP/3, Caddy se ha convertido en la opcion preferida para desarrolladores que desean servicio web seguro y listo para produccion con el minimo esfuerzo posible.

Que es Caddy?

Caddy es una plataforma de servidor web extensible que prioriza la facilidad de uso y las configuraciones seguras por defecto. Fue creado por Matt Holt en 2015 y se distribuye como un binario unico compilado estaticamente sin dependencias externas.

Caracteristicas clave de Caddy:

  • HTTPS automatico — Provisiona y renueva certificados TLS de Let’s Encrypt o ZeroSSL sin ninguna configuracion
  • HTTP/2 y HTTP/3 — Habilitados por defecto para todos los sitios HTTPS
  • Proxy inverso — Proxy inverso integrado con balanceo de carga, verificaciones de salud y manipulacion de cabeceras
  • Modo sin configuracion — Un Caddyfile simple de dos lineas puede servir un sitio completo con HTTPS
  • Multiplataforma — Se ejecuta en Linux, macOS, Windows y BSD
  • Ecosistema de plugins — Extiende funcionalidad con modulos para proveedores DNS, autenticacion, limitacion de velocidad y mas

Caddy se distribuye bajo la licencia Apache 2.0 y es gratuito tanto para uso personal como comercial.

Caddy vs Nginx

Si actualmente usas Nginx y te preguntas si Caddy es adecuado para tu proyecto, aqui tienes una comparacion directa:

CaracteristicaCaddyNginx
HTTPSAutomatico (cliente ACME integrado)Manual (requiere Certbot o similar)
Sintaxis de configuracionCaddyfile (minima, legible)nginx.conf (potente pero verbose)
HTTP/2Habilitado por defectoRequiere configuracion explicita
HTTP/3 (QUIC)Integrado, habilitado por defectoExperimental (requiere build separado)
Proxy inversoDirectiva integradaModulo integrado
Balanceo de cargaIntegrado con multiples politicasIntegrado (round-robin, least_conn, etc.)
Recarga de configuracionSin inactividad via API o SIGHUPSin inactividad via nginx -s reload
LenguajeGo (seguro en memoria)C (alto rendimiento)
Uso de memoriaBajo (~20-50 MB)Muy bajo (~5-15 MB)
Rendimiento brutoMuy buenoExcelente (maneja millones de RPS)
Comunidad y ecosistemaCreciendo rapidamenteMasivo, decadas de documentacion

Cuando elegir Caddy: Quieres HTTPS automatico, configuracion minima y un conjunto de caracteristicas modernas sin gestion manual de certificados. Ideal para aplicaciones autoalojadas, proyectos personales y despliegues pequenos a medianos.

Cuando elegir Nginx: Necesitas control extremadamente granular, maximo rendimiento bruto para millones de conexiones simultaneas, o amplia compatibilidad de modulos de decadas de desarrollo del ecosistema.

Prerrequisitos

Antes de instalar Caddy, asegurate de tener:

  • Un servidor Linux con Ubuntu 22.04+ o Debian 12+ (otras distribuciones tambien son compatibles)
  • Un nombre de dominio con registros DNS A/AAAA apuntando a la IP publica de tu servidor
  • Puertos 80 y 443 abiertos en tu firewall (requeridos para el desafio ACME HTTP y HTTPS)
  • Acceso root o sudo al servidor
  • Ningun otro servidor web (Nginx, Apache) escuchando en los puertos 80/443

Verifica que tu firewall permite los puertos requeridos:

# Si usas UFW
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw status

Instalando Caddy en Ubuntu

El metodo de instalacion recomendado usa el repositorio APT oficial de Caddy, que proporciona actualizaciones automaticas:

# Instalar dependencias requeridas
sudo apt update
sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https curl

# Agregar la clave GPG de Caddy
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg

# Agregar el repositorio de Caddy
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | sudo tee /etc/apt/sources.list.d/caddy-stable.list

# Instalar Caddy
sudo apt update
sudo apt install -y caddy

Verifica la instalacion:

caddy version

Deberias ver una salida como v2.8.4 h1:... confirmando que Caddy esta instalado. La instalacion del paquete tambien crea un servicio systemd, un Caddyfile predeterminado en /etc/caddy/Caddyfile, y un usuario caddy para ejecutar el proceso.

Alternativa: Instalar desde Binario

Si prefieres una instalacion manual o necesitas una version especifica:

# Descargar la ultima version
curl -Lo caddy.tar.gz "https://github.com/caddyserver/caddy/releases/latest/download/caddy_2.8.4_linux_amd64.tar.gz"

# Extraer y mover al PATH
tar xzf caddy.tar.gz
sudo mv caddy /usr/bin/caddy
sudo chmod +x /usr/bin/caddy

# Verificar
caddy version

Entendiendo el Caddyfile

El Caddyfile es el archivo de configuracion de Caddy. Su sintaxis es intencionalmente minima — describes que quieres, no como lograrlo. Caddy completa los valores predeterminados razonables.

El Caddyfile se encuentra en /etc/caddy/Caddyfile cuando se instala desde el gestor de paquetes. Aqui esta la estructura basica:

# Opciones globales (opcional)
{
    email admin@example.com
}

# Bloque del sitio
example.com {
    root * /var/www/html
    file_server
}

Conceptos clave:

  • Direccion del sitio — El dominio o IP antes de la llave de apertura. Usar un nombre de dominio activa el HTTPS automatico.
  • Directivas — Comandos dentro del bloque del sitio como root, file_server, reverse_proxy.
  • Opciones globales — Configuraciones dentro de un bloque {} de nivel superior sin direccion. Se usan para email (para registro ACME), configuraciones de logging, etc.
  • Matchers — Patrones como * o /api/* que controlan a que solicitudes se aplica una directiva.

Despues de editar el Caddyfile, valida y recarga:

# Validar sintaxis
caddy validate --config /etc/caddy/Caddyfile

# Recargar sin tiempo de inactividad
sudo systemctl reload caddy

Sirviendo Archivos Estaticos

Servir un sitio web estatico con Caddy requiere solo unas pocas lineas:

example.com {
    root * /var/www/mysite
    file_server
}

Eso es todo. Caddy:

  1. Obtendra un certificado TLS para example.com automaticamente
  2. Servira archivos desde /var/www/mysite
  3. Habilitara HTTP/2 y HTTP/3
  4. Redirigira HTTP a HTTPS

Para una configuracion de sitio estatico mas completa con compresion y cache:

example.com {
    root * /var/www/mysite

    # Habilitar compresion gzip y zstd
    encode gzip zstd

    # Servir archivos estaticos con navegacion de directorio deshabilitada
    file_server {
        hide .git .env
    }

    # Paginas de error personalizadas
    handle_errors {
        rewrite * /{err.status_code}.html
        file_server
    }

    # Cache para assets estaticos
    @static path *.css *.js *.png *.jpg *.gif *.svg *.woff2
    header @static Cache-Control "public, max-age=2592000, immutable"

    # Cabeceras de seguridad
    header {
        X-Content-Type-Options "nosniff"
        X-Frame-Options "DENY"
        Referrer-Policy "strict-origin-when-cross-origin"
    }
}

Crea el directorio raiz web y una pagina de prueba:

sudo mkdir -p /var/www/mysite
echo '<h1>Hello from Caddy</h1>' | sudo tee /var/www/mysite/index.html
sudo chown -R caddy:caddy /var/www/mysite

HTTPS Automatico

El HTTPS automatico es la caracteristica distintiva de Caddy. Entender como funciona te ayuda a solucionar problemas y personalizar el comportamiento.

Como Funciona

Cuando Caddy encuentra un bloque de sitio con un nombre de dominio publico (no localhost ni una IP), automaticamente:

  1. Verifica DNS — Comprueba que el dominio resuelve a la IP publica del servidor
  2. Solicita un certificado — Contacta a Let’s Encrypt (o ZeroSSL como respaldo) via el protocolo ACME
  3. Completa el desafio HTTP-01 — Demuestra propiedad del dominio sirviendo un token en el puerto 80
  4. Instala el certificado — Configura TLS con el certificado y clave obtenidos
  5. Redirige HTTP a HTTPS — Crea una redireccion automatica en el puerto 80
  6. Programa la renovacion — Renueva el certificado antes de su expiracion (tipicamente 30 dias antes)

El Protocolo ACME

ACME (Automatic Certificate Management Environment) es el protocolo que Let’s Encrypt usa para verificar la propiedad del dominio. Caddy incluye un cliente ACME completo que soporta:

  • Desafio HTTP-01 — Sirve un archivo de token via HTTP en el puerto 80 (predeterminado)
  • Desafio TLS-ALPN-01 — Usa negociacion TLS en el puerto 443
  • Desafio DNS-01 — Crea un registro TXT DNS (requiere un plugin de proveedor DNS)

Configurando el Email ACME

Establece una direccion de correo electronico para notificaciones de expiracion de certificados y registro de cuenta:

{
    email admin@example.com
}

example.com {
    reverse_proxy localhost:3000
}

Usando una CA de Staging para Pruebas

Durante el desarrollo, usa el entorno staging de Let’s Encrypt para evitar limites de velocidad:

{
    acme_ca https://acme-staging-v02.api.letsencrypt.org/directory
}

example.com {
    reverse_proxy localhost:3000
}

Importante: Los certificados de staging no son confiables para los navegadores. Elimina la directiva acme_ca al pasar a produccion.

Certificados Internos (Auto-firmados)

Para desarrollo local o servicios internos que no necesitan certificados publicos:

{
    local_certs
}

localhost {
    reverse_proxy localhost:3000
}

Caddy generara un certificado auto-firmado e instalara su CA raiz en el almacen de confianza del sistema para que los navegadores lo acepten localmente.

Configuracion del Proxy Inverso

La directiva reverse_proxy de Caddy proporciona un proxy inverso completo con configuracion minima.

Proxy Inverso Basico

app.example.com {
    reverse_proxy localhost:3000
}

Esta unica linea redirige todo el trafico de app.example.com a un backend ejecutandose en el puerto 3000, con HTTPS automatico, HTTP/2 y reenvio adecuado de cabeceras.

Multiples Backends en un Dominio

Usa enrutamiento basado en rutas para redirigir diferentes paths a diferentes backends:

example.com {
    reverse_proxy /api/* localhost:8000
    reverse_proxy /admin/* localhost:9000

    # Todo lo demas sirve archivos estaticos
    root * /var/www/frontend
    file_server
}

Multiples Dominios (Hosts Virtuales)

app.example.com {
    reverse_proxy localhost:3000
}

api.example.com {
    reverse_proxy localhost:8000
}

admin.example.com {
    reverse_proxy localhost:9000 {
        header_up X-Custom-Header "admin-panel"
    }
}

Cada dominio obtiene automaticamente su propio certificado TLS.

Preservando la Informacion del Cliente

Caddy establece automaticamente las cabeceras X-Forwarded-For, X-Forwarded-Proto y X-Forwarded-Host. Puedes agregar o sobrescribir cabeceras:

app.example.com {
    reverse_proxy localhost:3000 {
        header_up Host {upstream_hostport}
        header_up X-Real-IP {remote_host}
        header_up X-Forwarded-Port {server_port}
    }
}

Soporte para WebSocket

Caddy redirige conexiones WebSocket de forma transparente — no se necesita configuracion adicional:

ws.example.com {
    reverse_proxy localhost:4000
}

Las cabeceras Upgrade y Connection son manejadas automaticamente por el proxy inverso de Caddy.

Balanceo de Carga

Caddy soporta balanceo de carga entre multiples instancias backend con varias politicas.

Round-Robin (Predeterminado)

app.example.com {
    reverse_proxy localhost:3001 localhost:3002 localhost:3003
}

Politicas de Balanceo de Carga

app.example.com {
    reverse_proxy localhost:3001 localhost:3002 localhost:3003 {
        lb_policy least_conn
    }
}

Politicas disponibles:

PoliticaDescripcion
randomElige un backend aleatorio
least_connEnvia al backend con menos conexiones activas
round_robinCicla por los backends secuencialmente (predeterminado)
firstSiempre usa el primer backend disponible
ip_hashEnruta basado en la IP del cliente para afinidad de sesion
uri_hashEnruta basado en el URI de la solicitud
headerEnruta basado en el valor de una cabecera de solicitud
cookieEnruta basado en el valor de una cookie para persistencia de sesion

Verificaciones de Salud

Habilita verificaciones de salud activas para detectar y remover backends no saludables:

app.example.com {
    reverse_proxy localhost:3001 localhost:3002 localhost:3003 {
        lb_policy least_conn

        health_uri /health
        health_interval 10s
        health_timeout 5s
        health_status 200

        # Verificaciones de salud pasivas
        fail_duration 30s
        max_fails 3
        unhealthy_latency 500ms
    }
}

Cabeceras, Compresion y Cache

Cabeceras de Respuesta Personalizadas

example.com {
    header {
        # Cabeceras de seguridad
        Strict-Transport-Security "max-age=63072000; includeSubDomains; preload"
        X-Content-Type-Options "nosniff"
        X-Frame-Options "DENY"
        Referrer-Policy "strict-origin-when-cross-origin"
        Permissions-Policy "camera=(), microphone=(), geolocation=()"

        # Remover identificacion del servidor
        -Server

        # Control de cache para contenido dinamico
        Cache-Control "no-store, no-cache, must-revalidate"
    }

    reverse_proxy localhost:3000
}

Compresion

Habilita compresion transparente con encode:

example.com {
    encode zstd gzip

    reverse_proxy localhost:3000
}

Caddy negocia automaticamente el mejor algoritmo de compresion basado en la cabecera Accept-Encoding del cliente. Zstandard (zstd) es preferido cuando esta soportado, ya que proporciona mejores ratios de compresion y descompresion mas rapida que gzip.

Cache de Assets Estaticos

example.com {
    @static path *.css *.js *.png *.jpg *.gif *.svg *.woff2 *.ico
    header @static Cache-Control "public, max-age=31536000, immutable"

    @dynamic not path *.css *.js *.png *.jpg *.gif *.svg *.woff2 *.ico
    header @dynamic Cache-Control "no-cache, must-revalidate"

    reverse_proxy localhost:3000
}

Ejecutando Caddy como Servicio systemd

La instalacion del paquete APT crea un servicio systemd automaticamente. Aqui estan los comandos esenciales:

# Iniciar Caddy
sudo systemctl start caddy

# Detener Caddy
sudo systemctl stop caddy

# Reiniciar Caddy (breve inactividad)
sudo systemctl restart caddy

# Recargar configuracion sin inactividad
sudo systemctl reload caddy

# Habilitar Caddy para iniciar en arranque
sudo systemctl enable caddy

# Verificar estado del servicio
sudo systemctl status caddy

# Ver logs
sudo journalctl -u caddy --no-pager -f

El Archivo de Servicio de Caddy

El archivo de unidad systemd predeterminado se encuentra en /lib/systemd/system/caddy.service. Ejecuta Caddy como el usuario caddy y carga /etc/caddy/Caddyfile:

[Unit]
Description=Caddy
Documentation=https://caddyserver.com/docs/
After=network.target network-online.target
Requires=network-online.target

[Service]
Type=notify
User=caddy
Group=caddy
ExecStart=/usr/bin/caddy run --environ --config /etc/caddy/Caddyfile
ExecReload=/usr/bin/caddy reload --config /etc/caddy/Caddyfile --force
TimeoutStopSec=5s
LimitNOFILE=1048576
LimitNPROC=512
PrivateTmp=true
ProtectSystem=full
AmbientCapabilities=CAP_NET_BIND_SERVICE

[Install]
WantedBy=multi-user.target

Nota: Si instalaste Caddy manualmente (no desde el paquete), necesitas crear este archivo de servicio tu mismo y agregar el usuario caddy con sudo useradd --system --home /var/lib/caddy --shell /usr/sbin/nologin caddy.

Verificando la Instalacion

Despues de iniciar Caddy, verifica que esta sirviendo tu sitio:

# Verificar que Caddy esta escuchando
sudo ss -tlnp | grep caddy

# Probar HTTPS (reemplaza con tu dominio)
curl -I https://example.com

# Verificar detalles del certificado
echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null | openssl x509 -noout -subject -dates

Referencia de Directivas del Caddyfile

Aqui tienes una referencia de las directivas del Caddyfile mas utilizadas:

DirectivaPropositoEjemplo
reverse_proxyRedirigir solicitudes a servidores backendreverse_proxy localhost:3000
file_serverServir archivos estaticos desde discofile_server
rootEstablecer el directorio raiz del documentoroot * /var/www/html
encodeHabilitar compresion de respuestasencode gzip zstd
headerEstablecer, agregar o remover cabeceras de respuestaheader X-Frame-Options "DENY"
redirRedirigir solicitudes a una nueva URLredir /old /new permanent
rewriteReescribir el URI de la solicitud internamenterewrite /app/* /index.html
basicauthProteger rutas con HTTP Basic Authbasicauth /admin/* { ... }
tlsConfigurar ajustes TLS manualmentetls internal
logConfigurar registro de accesolog { output file /var/log/caddy/access.log }
handleAgrupar directivas para exclusividad mutuahandle /api/* { ... }
handle_pathComo handle, pero elimina el prefijo coincidentehandle_path /api/* { ... }
respondDevolver una respuesta estaticarespond "OK" 200
importIncluir otro archivo o snippetimport /etc/caddy/snippets/*
php_fastcgiRedirigir solicitudes PHP a PHP-FPMphp_fastcgi unix//run/php/php-fpm.sock

Snippets Reutilizables

Define bloques de configuracion reutilizables con snippets:

# Definir un snippet
(security_headers) {
    header {
        Strict-Transport-Security "max-age=63072000; includeSubDomains; preload"
        X-Content-Type-Options "nosniff"
        X-Frame-Options "DENY"
        Referrer-Policy "strict-origin-when-cross-origin"
        -Server
    }
}

# Usar el snippet en bloques de sitio
app.example.com {
    import security_headers
    reverse_proxy localhost:3000
}

api.example.com {
    import security_headers
    reverse_proxy localhost:8000
}

Solucion de Problemas

Problemas con Certificados

Si Caddy no puede obtener un certificado, verifica estas causas comunes:

# Verificar resolucion DNS
dig +short example.com

# Asegurar que los puertos 80 y 443 son accesibles
sudo ss -tlnp | grep -E ':80|:443'

# Verificar si otro servicio esta usando el puerto 80
sudo lsof -i :80

# Ver logs de Caddy para errores ACME
sudo journalctl -u caddy --no-pager | grep -i "acme\|certificate\|tls"

Causas comunes de fallas en certificados:

  • DNS no apunta a tu servidor — El dominio debe resolver a la IP publica del servidor
  • Puerto 80 bloqueado por firewall — Requerido para el desafio HTTP-01
  • Otro servicio usando el puerto 80 — Detener Nginx, Apache o cualquier otro servidor web
  • Limites de velocidad — Let’s Encrypt limita la emision de certificados a 5 por dominio por semana

502 Bad Gateway

Esto significa que Caddy no puede alcanzar el backend upstream:

# Verificar que el backend esta ejecutandose
curl -I http://localhost:3000

# Verificar si el backend esta vinculado a localhost o a todas las interfaces
sudo ss -tlnp | grep 3000

# Solucion comun: asegurar que el backend escucha en 127.0.0.1, no en 0.0.0.0

Errores de Permisos

# Asegurar que el usuario caddy tiene acceso de lectura al directorio raiz web
sudo chown -R caddy:caddy /var/www/mysite

# Verificar permisos de archivos
ls -la /var/www/mysite/

# Si Caddy no puede enlazar a puertos 80/443
sudo setcap 'cap_net_bind_service=+ep' /usr/bin/caddy

Validacion de Configuracion

# Siempre validar antes de recargar
caddy validate --config /etc/caddy/Caddyfile

# Formatear el Caddyfile (arreglar indentacion)
caddy fmt --overwrite /etc/caddy/Caddyfile

# Probar con un adaptador especifico (ej., para configuracion JSON)
caddy adapt --config /etc/caddy/Caddyfile

API de Administracion de Caddy

Caddy expone una API de administracion local en localhost:2019 para configuracion en tiempo de ejecucion:

# Ver configuracion actual como JSON
curl http://localhost:2019/config/

# Verificar certificados cargados
curl http://localhost:2019/pki/ca/local

# Recargar configuracion via API
curl -X POST http://localhost:2019/load \
  -H "Content-Type: text/caddyfile" \
  --data-binary @/etc/caddy/Caddyfile

Resumen

Caddy elimina la complejidad de la configuracion del servidor web al proporcionar HTTPS automatico, una sintaxis de Caddyfile minima y configuraciones predeterminadas listas para produccion. Ya sea que estes sirviendo archivos estaticos, redirigiendo a una aplicacion backend con proxy inverso, o balanceando carga entre multiples instancias, Caddy maneja el trabajo pesado — incluyendo la gestion de certificados TLS — para que puedas concentrarte en construir tu aplicacion.

Para mas informacion sobre configuracion de proxy inverso con Nginx, consulta nuestra Guia Completa de Proxy Inverso con Nginx. Si necesitas gestionar certificados manualmente con Certbot para servidores que no usan Caddy, revisa Automatizar Certificados SSL con Let’s Encrypt y Certbot.