Cómo configurar Caddy como reverse proxy en Linux 2026: auto-HTTPS incluido
Caddy es el único servidor web mainstream que obtiene y renueva certificados TLS solo, sin que toques nada. Si quieres HTTPS sin pelearte con certbot cada 90 días, esta guía es para ti.
TL;DR — Lo que vas a tener al final
- Tiempo de setup: 30 minutos a 2 horas dependiendo de la complejidad del entorno.
- Requisitos: Acceso root, Linux moderno, conexión a internet para descargar dependencias.
- Resultado: Servicio funcional y estable, documentado paso a paso.
- Troubleshooting: Logs estándar en /var/log/, comandos de verificación al final de cada sección.
Por qué Caddy y no Nginx o Traefik
Caddy 2 existe desde 2020 y su propuesta es simple: HTTPS por defecto. Mientras que Nginx requiere que tú corras certbot y le pegues los certificados al server { listen 443 ssl; }, Caddy los solicita solo la primera vez que alguien llega al puerto 443 y los renueva solo cuando faltan 30 días para vencer.
En homelabs esto significa:
- Cero cron jobs para renovar certificados
- Cero scripts de
acme.shcolgados después de un reinicio - Misma config local y producción: el
Caddyfileque probás en casa funciona igual arriba - HTTP/3 habilitado por defecto: los visitantes negocian QUIC si su navegador lo soporta, sin tocar nada
La contra conocida: el ecosistema de módulos es más chico que el de Nginx. Si necesitas reglas muy específicas (rate limit a nivel de location, geoip, etc.), vas a extrañar Nginx. Pero para el 90% de los casos de homelab (varios servicios detrás de un único punto de entrada), Caddy es la opción más corta.
Requisitos
- Un servidor Linux con Debian 12+, Ubuntu 22.04+ o RHEL 9+
- Puertos 80 y 443 libres en el firewall (Caddy los necesita para ACME)
- DNS del dominio apuntando a la IP pública del servidor (registro A o AAAA)
- Acceso root o sudo
Paso 1: Instalar Caddy
El paquete oficial está en el repo apt.caddy.community. Agregalo antes de instalar, porque la versión de los repos de Debian/Ubuntu suele estar uno o dos releases atrás.
sudo apt install -y debian-keyring debian-archive-keyring
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 -y caddy
debian-keyring y debian-archive-keyring son las dependencias para que apt verifique la firma del repo nuevo. Si te salta el error NO_PUBKEY al hacer apt update, es que la importación con --dearmor no terminó bien: repetila y verifica que el archivo en /usr/share/keyrings/ no esté vacío.
Después de instalar, Caddy queda corriendo como servicio systemd escuchando en :80 y :443. verifica:
caddy version
# v2.x.x
sudo systemctl status caddy
# active (running)
Si systemctl status muestra inactive o failed, corré sudo journalctl -u caddy -n 50 para ver el motivo. El motivo más común en un server fresco es que el puerto 80 ya está ocupado por Nginx o Apache: paralo (sudo systemctl stop nginx) y reiniciá Caddy (sudo systemctl restart caddy).
Paso 2: Tu primer reverse proxy
El archivo de configuración principal es el Caddyfile, vive en /etc/caddy/Caddyfile. Por defecto viene con un localhost:2019 que es la API interna — sobreescribilo con tu config.
sudo nano /etc/caddy/Caddyfile
Pegá esta config mínima:
midominio.com {
reverse_proxy 127.0.0.1:8080
}
reverse_proxy 127.0.0.1:8080 le dice a Caddy: cuando alguien llegue a midominio.com, pasá la request al servicio local que escucha en el puerto 8080. El 8080 es el típico de una app web dev (Grafana, Jellyfin, un app de Node, etc.).
Validá la sintaxis antes de aplicar:
caddy validate --config /etc/caddy/Caddyfile
Si la validación pasa, recargá Caddy sin tirar conexiones activas:
sudo systemctl reload caddy
reload (no restart) hace que Caddy recargue la config manteniendo los workers vivos. Es el equivalente a nginx -s reload. Ahora abrí https://midominio.com en el navegador y deberías ver tu app detrás de HTTPS válido, con candado verde y todo — sin tocar un solo certificado.
Paso 3: Múltiples dominios en un solo servidor
El caso clásico del homelab: varios servicios, un único puerto público (443), cada uno en su subdominio.
grafana.midominio.com {
reverse_proxy localhost:3000
}
jellyfin.midominio.com {
reverse_proxy localhost:8096
}
docs.midominio.com {
reverse_proxy localhost:8000
}
Caddy enruta por Host automáticamente. No necesitas definir server { server_name ... } como en Nginx — el primer match gana y listo. Cada bloque obtiene su propio certificado de Let’s Encrypt sin que pongas nada: Caddy emite un cert por cada host distinto que ve en el config.
Para aplicar cambios sin tirar el server:
sudo systemctl reload caddy
Si un subdominio no levanta HTTPS, dos causas frecuentes: (1) el DNS no apunta al server todavía (dig +short grafana.midominio.com debe devolver tu IP), o (2) el puerto 80 está bloqueado por algún firewall/cloud — Let’s Encrypt solo emite si puede llegar al puerto 80 con HTTP-01 challenge.
Paso 4: Configuraciones avanzadas que vas a necesitar
Path-based routing
Si tienes un solo dominio y quieres servir varios servicios por path:
midominio.com {
reverse_proxy /api/* localhost:3000
reverse_proxy localhost:8080
}
/api/* matchea todo lo que empiece con /api/ y lo manda al backend 3000; el resto va al 8080. Útil cuando no quieres administrar DNS para subdominios separados.
Cache estático
Para que Caddy sirva él mismo los archivos estáticos sin pegarle al backend:
midominio.com {
reverse_proxy localhost:8080
@assets path /assets/*
handle @assets {
root * /var/www/miapp/public
file_server
header Cache-Control "public, max-age=31536000, immutable"
}
}
file_server sirve los archivos del directorio /var/www/miapp/public cuando matchea @assets. El header Cache-Control con immutable le dice al navegador que no pregunte de nuevo por un año — útil para bundles de frontend con hash en el nombre.
Logs estructurados
Los logs por defecto van a journald. Para sacarlos a un archivo JSON que puedas pipear a Loki o similar:
sudo nano /etc/caddy/Caddyfile
{
log default {
output file /var/log/caddy/access.log {
roll_size 100MiB
roll_keep 5
}
format json
}
}
roll_size 100MiB rota cuando llega a 100 MB; roll_keep 5 mantiene los últimos 5 archivos. Después de cambiar, recargá Caddy y verifica que el archivo exista:
sudo systemctl reload caddy
ls -lh /var/log/caddy/
Compresión Brotli
Caddy soporta gzip y zstd out-of-the-box. Para activar Brotli (mejor ratio que gzip, soportado por todos los navegadores modernos):
midominio.com {
encode zstd gzip # brotli no está en builds oficiales de Caddy; requiere compilar con xcaddy + módulo github.com/ksaitor/dnsrobotoftymebrotli
reverse_proxy localhost:8080
}
encode aplica zstd primero, luego gzip — el navegador negocia el que prefiera. Reducir el HTML/CSS/JS entre 60% y 80% es normal en sitios con mucho texto.
Paso 5: Proteger endpoints con autenticación básica
Si quieres que un subdominio pida usuario y contraseña antes de mostrar contenido (típico para herramientas internas):
admin.midominio.com {
basicauth {
admin $2a$14$xxxxxxxxxxxxxxxxxxxxxxx
}
reverse_proxy localhost:9000
}
El hash $2a$14$... se genera con:
caddy hash-password --algorithm bcrypt
# Ingresa la contraseña cuando la pida
# Output: $2a$14$...
Pegá ese hash en el bloque basicauth. No uses texto plano — Caddy acepta admin plaintext_password pero queda en el Caddyfile legible para cualquiera con acceso al archivo.
Para agregar más usuarios, agregá una línea por usuario con su hash correspondiente:
basicauth {
admin $2a$14$hash_admin
viewer $2a$14$hash_viewer
}
Paso 6: Troubleshooting real
“acme: error presenting challenge”
Caddy no logró completar el ACME HTTP-01 challenge contra Let’s Encrypt. Casi siempre es porque el puerto 80 no está accesible desde Internet. verifica tres cosas:
sudo ss -tlnp | grep ':80|:443'
# Caddy debe estar LISTEN en ambos
sudo ufw status
# 80/tcp y 443/tcp deben estar ALLOW
curl -I http://midominio.com/.well-known/acme-challenge/test
# Debe devolver 404 (no 502/timeout)
Si la IP está detrás de Cloudflare, asegurate que el proxy de CF esté activo (naranja, no gris) y que el SSL mode en CF sea Full o Full (Strict). Si está en Flexible, Caddy ve una conexión HTTP y el cert no se valida.
El cert se renovó pero el navegador sigue mostrando el viejo
El navegador cachea el cert viejo. Forzá una renovacion manual:
sudo caddy reload --config /etc/caddy/Caddyfile --address :2019
Si eso no alcanza, abrí el sitio en ventana privada o reiniciá el navegador. Para automatizar, puedes agregar un header Strict-Transport-Security "max-age=31536000" en el bloque del dominio — esto le dice al navegador “olvidate del cert viejo por un año”.
Caddy consume demasiada RAM
El binario de Caddy está escrito en Go y consume entre 30 MB y 80 MB en configs chicas. Si ves que pasa de 200 MB, el problema suele ser un reverse_proxy sin transport configurado que mantiene conexiones idle. Agregá:
reverse_proxy localhost:8080 {
transport http {
keepalive off
dial_timeout 10s
}
}
keepalive off cierra conexiones idle en lugar de mantenerlas abiertas para siempre. En setups con cientos de workers esto baja la RAM a la mitad.
Cómo verificar que todo funciona
Después de configurar, hay tres checks que confirman que Caddy está haciendo su trabajo:
# 1. HTTPS válido con cadena completa
curl -vI https://midominio.com 2>&1 | grep -E "subject:|issuer:|expire"
# subject: CN = midominio.com
# issuer: C = US, O = Let's Encrypt
# expire: Oct 18 12:00:00 2026
# 2. HTTP redirige a HTTPS
curl -I http://midominio.com
# HTTP/1.1 301 Moved Permanently
# Location: https://midominio.com
# 3. Cert renovado sin que hagas nada
sudo journalctl -u caddy --since "30 days ago" | grep -i "renewing|obtained"
# {"level":"info","msg":"renewing certificate","identifier":"midominio.com"}
El primer comando confirma que el cert es válido y emitido por Let’s Encrypt. El segundo confirma que Caddy redirige HTTP → HTTPS automáticamente. El tercero confirma que la renovación automática está funcionando — no deberías ver la fecha de expiración cerca, Caddy se encarga.
Resumen
Caddy en homelab 2026 es la opción más corta para tener HTTPS automático sin scripts de renovación. La config inicial lleva 10 minutos (instalar + Caddyfile de 4 líneas), y después puedes agregar subdominios, autenticación, logs y cache sin pelearte con módulos externos.
Próximos pasos si quieres profundizar:
- Configurar rate limiting si exponés APIs públicas
- Montar un load balancer entre varios backends
- Migrar de HTTP a HTTP/3 puro si tu CDN lo soporta
Lee también: [Cómo instalar Nginx desde cero](/nginx-reverse-proxy-configuracion-completa-2026/) si quieres comparar configs, o [WireGuard en OPNsense](/wireguard-opnsense-acceso-remoto/) si el reverse proxy vive detrás de un firewall.
Preguntas frecuentes
¿Por qué Cómo configurar Caddy como reverse proxy en Linux 2026: auto-HTTPS incluido es relevante para sysadmins Linux?
Forma parte del flujo diario de administración. Los conceptos explicados se aplican directamente a servidores en producción y resuelven problemas reales que enfrentan sysadmins hispanohablantes.
¿Qué necesito para empezar con Cómo configurar Caddy como reverse?
Distribución Linux actualizada (Debian, Ubuntu, RHEL, Fedora o Arch), acceso root, y conexión a internet. Para producción: entorno de staging separado antes de aplicar cambios.
¿Cuáles son los errores más comunes con Cómo configurar Caddy como reverse?
Los tres más frecuentes: (1) saltar la lectura de logs, (2) aplicar cambios directos en producción sin probar, (3) olvidar permisos y ownership. La documentación y un plan de rollback siempre.
¿Cuándo usar Cómo configurar Caddy como reverse y cuándo una alternativa?
Esta solución es ideal para el caso descrito. Alternativas como Docker, Ansible o configuración manual pueden ser mejores según contexto: portabilidad, escala y reproducibilidad son los factores clave.
¿Cómo migro desde una configuración previa a Cómo configurar Caddy como reverse?
Documentar el estado actual, probar la nueva configuración en staging, validar funcionalmente, y aplicar en producción con rollback plan listo. Los posts de SoyLinux incluyen troubleshooting para los problemas más comunes.
Lee también
- Guía Fedora 44: Novedades, Instalación y Upgrade para Sysadmins Linux
- Configura VLANs en Linux con nmcli: Guía paso a paso para sysadmins
- Protege tu SSH: Guía esencial para configurar Fail2ban en Linux
- Guía Definitiva: Configura Kubernetes con kubeadm en Ubuntu para Sysadmins Linux
- Configura Prometheus y Grafana: Guía DevOps para SysAdmins Linux

Pingback: MinIO self-hosted en 2026: tu propio S3-compatible storage
Pingback: Headscale: tu propio Tailscale self-hosted en 2026
Pingback: Exponer servicios de tu home lab a internet: 6 vías explicadas - Soy Linux
Pingback: Coolify vs Dokploy vs CapRover 2026: comparativa y guía de instalación
Pingback: Actualización Jellyfin 12: Mejoras en Rendimiento y Gestión de Medios - Soy Linux
Pingback: Cómo configurar un WAF open source (Coraza) frente a tu app en 2026 - Soy Linux