Caddy con Docker en producción: guía práctica 2026
Caddy se ha consolidado como el proxy inverso más práctico para desplegar aplicaciones en Docker, y la razón es simple: te olvidás de los certificados SSL. Mientras que con Nginx tenés que andar configurando Certbot, cron jobs y rogando que la renovación no falle un domingo a las 3 AM, con Caddy ponés dos líneas en un Caddyfile y te genera, instala y renueva los certificados Let’s Encrypt solo. En esta guía vas a ver cómo integrarlo en tu stack Docker Compose, desde la configuración básica hasta el manejo de múltiples subdominios, basado en pruebas reales de despliegue en VPS.
Lo esencial
- HTTPS sin intervención manual: Caddy obtiene y renueva certificados TLS de Let’s Encrypt automáticamente, incluso para múltiples subdominios.
- Caddyfile reemplaza decenas de líneas de Nginx: un bloque de configuración simple alcanza para publicar un frontend o rutear una API.
- Único contenedor con puertos públicos: solo Caddy expone 80 y 443; tus apps quedan aisladas en la red interna de Docker.
- HTTP/2, HTTP/3 y WebSocket: soporte nativo sin instalar módulos extra, ideal para apps con comunicación en tiempo real.
¿Qué es Caddy exactamente y qué problema te resuelve?
Caddy es un servidor web y proxy inverso de código abierto, escrito en Go, que se compila en un solo binario sin dependencias externas. Su diferencial más importante es que incluye un cliente ACME integrado: apenas le decís qué dominio querés servir, él mismo pide el certificado a Let’s Encrypt, lo instala y lo renueva sin que muevas un dedo. No necesitás Certbot, no necesitás un script aparte, no necesitás acordarte cada 90 días.
El caso de uso más común en 2026 es tenerlo corriendo dentro de Docker como puerta de entrada a tus aplicaciones. Un docker-compose.yml típico tiene a Caddy exponiendo los puertos 80 y 443 hacia internet, mientras que los contenedores de tu backend, frontend o base de datos corren en una red interna sin puertos públicos. Caddy se comunica con ellos por el nombre del servicio (la magia del DNS interno de Docker) y todo el tráfico externo pasa por TLS automático.
Según la guía de despliegue, esta arquitectura cubre los cuatro requisitos básicos de cualquier app moderna en un VPS: HTTPS con certificados TLS, proxy inverso para APIs, servidor de estáticos para frontends SPA y ruteo flexible por dominio y subdominio. Todo con un solo binario y un archivo de configuración que podés leer sin tener que googlear cada directiva.
¿Cómo configurar HTTPS automático con Caddy en Docker?
La parte más impresionante —y la que me hizo cambiar de Nginx a Caddy hace dos años— es que el HTTPS sale andando sin que le expliques cómo. Escribís esto en tu Caddyfile: En nuestra guía completa de cloud hosting profundizamos sobre esto.
midominio.com {reverse_proxy localhost:3000}
Y listo. Caddy detecta que estás declarando un dominio público, contacta a Let’s Encrypt, pasa el desafío ACME (por HTTP o TLS-ALPN, según lo que tengas disponible), obtiene el certificado y redirige todo el tráfico HTTP a HTTPS automáticamente. Si alguna vez sufriste el infierno de depurar renewals de Certbot, sabés lo que vale esto.
Para producción en Docker, necesitás persistir dos volúmenes —caddy_data y caddy_config— que es donde Caddy guarda los certificados y su estado interno. Si no los persistís, cada vez que tirás y levantás el contenedor vas a pedir certificados nuevos, y Let’s Encrypt tiene rate limits que te van a dejar en la lona bastante rápido. El docker-compose mínimo sería algo así:
- Servicio caddy: imagen
caddy:latest, puertos 80 y 443 mapeados al host, volúmenes./Caddyfile:/etc/caddy/Caddyfile,caddy_data:/dataycaddy_config:/config. - Servicio app: sin
ports, soloexposeen el puerto interno (por ejemplo 3000), en la misma red de Docker que Caddy.
Caddy resuelve el nombre del servicio (app:3000) usando el DNS interno de Docker, así que no necesitás IPs fijas ni configuraciones extra. El punto clave acá es que Caddy es el único contenedor que ve internet —tus apps están blindadas detrás de la red interna, y eso ya te resuelve una capa de seguridad que con otras configuraciones tenés que armar a mano.
¿Cómo estructurar un Caddyfile para múltiples servicios?
Acá es donde Caddy se pone realmente práctico. La sintaxis usa bloques de sitio delimitados por llaves, y cada bloque puede tener su propio subdominio y su propia configuración independiente. Para una app típica con frontend y API, tendrías algo como: Más contexto en solución de problemas de hosting y dominio.
api.tudominio.com: bloque conreverse_proxy backend:4000y encabezados CORS si tu API los necesita.app.tudominio.com: bloque que sirve la carpeta de build de tu SPA conroot * /srvyfile_server, más untry_files {path} /index.htmlpara que el router del frontend maneje las rutas.- Caddy te permite manejar cada subdominio con su propia configuración, así que un problema en uno no afecta a los demás.
¿WebSockets? Funcionan sin configuración extra, Caddy los detecta por el upgrade de protocolo y los maneja transparente. Si tu app usa Socket.io o WebSockets nativos para notificaciones en tiempo real, no tenés que tocar nada en el proxy —algo que con Nginx requiere directivas adicionales de proxy_set_header Upgrade y Connection que siempre me hacían renegar.
También podés enrutar por path en vez de subdominio. Por ejemplo, tudominio.com/api/* va al backend y tudominio.com/* va al frontend. La directiva handle_path incluso te deja reescribir la ruta antes de pasarla al servicio interno, cosa de que tu API no se entere de que la llamaron con el prefijo /api. Para stacks chicos donde no querés complicarte con DNS de subdominios, esto es un golazo.
¿Cómo desplegar una app completa con Caddy y Docker Compose?
La arquitectura que vas a ver en prácticamente todos los despliegues de 2026 es esta: internet pega en Caddy, Caddy enruta por dominio o path hacia los contenedores internos, y todo corre en un solo VPS con Docker Compose. Nada de balanceadores de carga complicados para proyectos que recién arrancan.
Un docker-compose.yml típico tiene tres servicios: Caddy exponiendo 80 y 443, un contenedor de frontend con el build de tu SPA (o sirviendo estáticos), y un contenedor de backend con tu API. Los tres en la misma red definida como caddy_net. El frontend y el backend no tienen sección ports —solo expose— porque no necesitan ser accesibles desde afuera. Caddy los alcanza internamente y todo el tráfico externo va por TLS. Ya lo cubrimos antes en guía de cloud hosting para devops.
Para proyectos que necesitan hosting confiable en la región, si estás evaluando opciones de VPS o cloud local, buscá un proveedor con buena infraestructura y baja latencia para tráfico latinoamericano. Con eso más Caddy, tenés un stack prolijo y rápido en pocas horas.
¿Cómo manejar subdominios y redirecciones con Caddy?
Una necesidad común: tenés varios dominios que querés que apunten todos a uno solo. Caddy lo resuelve con la directiva redir. Por ejemplo, si compraste tudominio.com.ar y tudominio.com y querés que todo vaya a este último, harías:
- Bloque para el dominio alternativo:
tudominio.com.ar { redir https://tudominio.com{uri} }. El{uri}es un placeholder que mantiene la ruta original, así que el visitante no cae en la home si venía con un link específico. - Redirección HTTP a HTTPS: Caddy la hace automática sin que escribas nada. Apenas seteás un dominio, cualquier tráfico en puerto 80 se va a 443. No necesitás el bloque separado que sí precisás en Nginx.
La redirección se hace con código 301 (permanente) por defecto, que es lo que querés para SEO —los motores de búsqueda entienden que el contenido se movió definitivamente y transfieren la autoridad al dominio canónico. Si necesitás una redirección temporal (302), se la podés especificar, pero en general el default es el correcto.
Caddy vs Nginx: ¿cuál conviene para proyectos nuevos en 2026?
Mirá, usé Nginx por más de una década. Es un caño, no se cae nunca, y tiene una comunidad gigante. Pero para proyectos nuevos en 2026, Caddy me parece la opción más sensata —especialmente si estás en Docker y no heredaste configuraciones viejas que mantener. La diferencia más notoria está en cuánto escribís para cada tarea. Complementá con comparativa de pipelines CI/CD 2026.
| Tarea | Nginx | Caddy |
|---|---|---|
| Obtener SSL | Requiere Certbot + cron | Automático, cero configuración |
| Agregar un servicio | ~15 líneas de configuración | 3 líneas en un bloque |
| Redirigir HTTP a HTTPS | Bloque separado explícito | Automático por defecto |
| Habilitar HTTP/2 y HTTP/3 | Directivas explícitas + módulos | Habilitado por defecto |
| Sintaxis | Verbosa, con contexto heredado | Declarativa, legible sin docs |

En mi experiencia, Caddy es mucho más corto en líneas de configuración para los casos de uso más comunes. Y no es solo ahorro de tipeo —cada línea que no escribís es una línea que no puede tener un error de sintaxis o un comportamiento inesperado en producción.
Dicho esto, Nginx sigue siendo imbatible en escenarios muy específicos: si necesitás módulos de terceros compilados a medida, si tenés configuraciones con miles de bloques server que ya están probadas, o si tu equipo ya maneja Nginx y migrar no tiene sentido. Pero si arrancás de cero, Caddy te ahorra horas.
Errores comunes al usar Caddy con Docker
- No persistir los volúmenes
caddy_dataycaddy_config. Este es el error que veo más seguido. Si no los vinculás a volúmenes con nombre, cada vez que hacésdocker compose downyupde nuevo, Caddy pide certificados nuevos. Let’s Encrypt tiene un límite de certificados por dominio, así que si hacés demasiadas solicitudes en poco tiempo te quedás sin poder emitir y todo deja de funcionar. Con Nginx uno ya sabe que persiste/etc/letsencrypt, pero con Caddy hay que hacer el hábito de mapear/datay/config. - Usar
localhosten elreverse_proxyen vez del nombre del servicio. Dentro de Docker,localhostes el contenedor de Caddy mismo, no tu app. Si ponésreverse_proxy localhost:3000, Caddy se está apuntando a sí mismo y tu app nunca recibe tráfico. Usá el nombre del servicio tal cual lo definiste endocker-compose.yml:reverse_proxy miapp:3000. - No setear
try_files {path} /index.htmlpara SPAs. Si tu frontend es React, Vue o Svelte, el ruteo del lado del cliente necesita que cualquier ruta que no sea un archivo físico devuelvaindex.html. Sin esa directiva, cuando alguien refresca en/productos/42, Caddy busca el archivo/srv/productos/42, no lo encuentra, y devuelve 404. Por suerte muchos templates de Caddyfile ya incluyen esto, pero vale la pena chequearlo.
Preguntas Frecuentes
¿Cómo usar Caddy con Docker en producción?
Creás un docker-compose.yml con el servicio Caddy exponiendo puertos 80 y 443, mapeás tu Caddyfile como volumen en /etc/caddy/Caddyfile y persistís caddy_data y caddy_config en volúmenes con nombre. Tus aplicaciones van en la misma red interna de Docker sin puertos públicos, y Caddy las alcanza por nombre de servicio. Todo el tráfico externo viaja por HTTPS con certificados que se renuevan solos.
¿Qué es Caddy y cómo se compara con Nginx?
Caddy es un servidor web y proxy inverso con HTTPS automático integrado, mientras que Nginx requiere herramientas externas como Certbot para SSL. Caddy usa una sintaxis más corta y declarativa —3 líneas donde Nginx pide 15— y soporta HTTP/2, HTTP/3 y WebSocket sin configuración adicional. Nginx sigue siendo superior en escenarios con módulos personalizados o configuraciones muy maduras que ya están en producción hace años.
¿Cómo configurar HTTPS automático con Caddy?
No requiere configuración manual. Escribís un bloque de sitio con tu dominio y la directiva reverse_proxy o file_server en el Caddyfile, y Caddy contacta a Let’s Encrypt, completa el desafío ACME y obtiene el certificado automáticamente. También redirige HTTP a HTTPS sin que agregues reglas extra. Los certificados se renuevan antes de expirar sin intervención ni cron jobs.
¿Cómo funciona el Caddyfile para múltiples servicios?
El Caddyfile usa bloques de sitio delimitados por llaves, uno por dominio o subdominio. Dentro de cada bloque definís qué hace ese dominio: servir estáticos con file_server, rutear a un backend con reverse_proxy o redirigir con redir. Caddy permite configurar cada subdominio de forma independiente, así que una falla en uno no afecta a los demás.
¿Se puede usar Caddy como proxy inverso para una API?
Sí, y es uno de sus usos más comunes. En el Caddyfile ponés api.tudominio.com { reverse_proxy backend:4000 } y Caddy enruta todo el tráfico hacia el contenedor de tu API definido en Docker Compose. El soporte para WebSocket y encabezados personalizados funciona sin configuración extra, y podés manejar CORS directamente desde Caddy o delegarlo a tu aplicación, lo que te resulte más cómodo.
Conclusión
Caddy con Docker es la combinación más limpia que tenés en 2026 para poner una app en producción sin renegar con SSL. En menos de 50 líneas entre un docker-compose.yml y un Caddyfile resolvés HTTPS automático, proxy inverso, ruteo por subdominio, WebSockets y redirecciones —algo que con Nginx + Certbot te llevaba el triple de configuración y un dolor de cabeza cada 90 días. Si arrancás un proyecto nuevo y tu stack está containerizado, no hay mucha vuelta: usá Caddy y no mires atrás. Si heredaste un monstruo de Nginx con 20 reglas de reescritura y módulos custom, mantenelo, que tampoco está roto. Pero para lo nuevo, Caddy te ahorra tiempo que podés usar en cosas que importan más que debuggear renovaciones de certificados.
Fuentes
- Guía práctica de Caddy con Docker para producción (2026) – Artículo original con patrones de despliegue, docker-compose y arquitectura de contenedores.
- Guía de proxy inverso con Caddy – 1vps – Comparativa detallada entre Caddy y Nginx con benchmarks de líneas de configuración.
- Reverse proxy con HTTPS automático en 1 docker-compose – Tutorial paso a paso de Caddy con aplicaciones containerizadas.






