Tutoriales de VPS
Guía completa de proxy inverso con Caddy en VPS (2026): HTTPS automático, múltiples dominios y aplicaciones Docker explicados de una vez
Esta guía está dirigida a usuarios que ya tienen un VPS y quieren exponer de forma segura varios sitios web o aplicaciones Docker a la red pública. Aprenderás a instalar Caddy, configurar DNS, escribir un Caddyfile mínimo, hacer proxy inverso de puertos locales y servicios Docker, manejar WebSocket, sitios estáticos, registros, recargas, solución de problemas y endurecimiento de seguridad.
Guía completa de proxy inverso con Caddy en VPS (2026): HTTPS automático, múltiples dominios y aplicaciones Docker explicados de una vez
Si has desplegado Node.js, Next.js, WordPress, Directus, n8n, Vaultwarden, Uptime Kuma o cualquier aplicación autoalojada en un VPS, pronto te encontrarás con el mismo problema: las aplicaciones normalmente solo escuchan en 127.0.0.1:3000, localhost:8080 o un puerto interno de Docker, pero el acceso externo real requiere un dominio, HTTPS, renovación de certificados, redirección de HTTP a HTTPS, WebSocket, registros y gestión de múltiples sitios.
La solución tradicional suele ser Nginx más Certbot. Es potente, pero para los principiantes tiene dos puntos débiles: los bloques de configuración son fáciles de escribir mal y la renovación de certificados requiere mantenimiento adicional. Aquí está el valor de Caddy: solicita y renueva certificados TLS automáticamente de forma predeterminada, la sintaxis del Caddyfile es muy corta y es adecuado para organizar rápidamente varios servicios en un VPS en un punto de entrada mantenible.
Este artículo explica desde cero: cómo instalar Caddy en un VPS, cómo configurar DNS, cómo hacer proxy inverso de aplicaciones locales y aplicaciones Docker, cómo alojar varios dominios al mismo tiempo y cómo manejar WebSocket, archivos estáticos, registros, recargas y errores comunes.
Caddy es más adecuado para estos escenarios de VPS:
- Tienes varios servicios ejecutándose en distintos puertos, por ejemplo
3000,5678,8080. - Quieres acceder a diferentes aplicaciones mediante
app.example.com,api.example.com,status.example.comrespectivamente. - No quieres gestionar manualmente los certificados de Let's Encrypt ni las tareas de renovación.
- Quieres archivos de configuración cortos, legibles y fáciles de revertir.
- Despliegas aplicaciones autoalojadas, Docker Compose, sitios web personales, herramientas internas o servicios de pequeñas empresas.
Caddy no es "solo para principiantes". Su HTTPS automático, proxy inverso, servicio de archivos estáticos, compresión, registros, control de acceso y reescritura de encabezados son completos. Simplemente hace que la configuración predeterminada de los sitios HTTPS comunes sea más sencilla.
Antes de empezar, necesitas preparar:
- Un VPS, preferiblemente Ubuntu 22.04 / 24.04 o Debian 12.
- Un dominio y la capacidad de modificar los registros DNS.
- La dirección IPv4 o IPv6 pública del VPS.
- Los puertos
80y443abiertos en el servidor. - Una aplicación que ya se ejecute en un puerto local, por ejemplo
127.0.0.1:3000.
Primero confirma que la hora del servidor es correcta:
timedatectl
Si la hora es claramente incorrecta, la solicitud del certificado TLS puede fallar. La mayoría de los servidores en la nube tienen NTP habilitado de forma predeterminada, por lo que no se necesita ninguna acción adicional.
Supongamos que tu dominio es example.com y la IPv4 del VPS es 203.0.113.10.
Los registros DNS comunes son los siguientes:
A app.example.com 203.0.113.10
A api.example.com 203.0.113.10
A status.example.com 203.0.113.10
Si usas IPv6, añade un registro AAAA:
AAAA app.example.com 2001:db8::10
Si usas Cloudflare, hay dos modos:
- Si solo quieres que Caddy obtenga los certificados por sí mismo: primero configura la nube naranja en DNS only y considera el modo proxy después de que el certificado se emita correctamente.
- Si usas el proxy de Cloudflare: se recomienda usar el modo SSL/TLS Full o Full (strict), no Flexible, de lo contrario es fácil que se produzcan bucles de redirección.
El DNS tarda en propagarse. Puedes comprobarlo localmente:
dig app.example.com +short
Cuando devuelva la IP del VPS, continúa configurando Caddy.
La instalación desde el repositorio oficial es mejor para el mantenimiento a largo plazo, porque después puedes actualizar con el gestor de paquetes del sistema.
sudo apt update
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 -y caddy
Después de la instalación, comprueba el estado del servicio:
systemctl status caddy --no-pager
Confirma que Caddy se está ejecutando:
caddy version
Si usas UFW:
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw status
Si tu proveedor de nube tiene grupos de seguridad, también debes permitir el tráfico entrante TCP 80 y 443 en la consola del proveedor. Muchos casos de "fallo en la solicitud del certificado de Caddy" no se deben al Caddyfile, sino a que el grupo de seguridad no permite el puerto 80, por lo que Let's Encrypt no puede completar la validación HTTP-01.
El archivo de configuración principal de Caddy suele ser:
/etc/caddy/Caddyfile
Supongamos que tu aplicación se ejecuta en 127.0.0.1:3000 y el dominio es app.example.com. La configuración puede ser muy corta:
app.example.com {
reverse_proxy 127.0.0.1:3000
}
Edita el archivo:
sudo nano /etc/caddy/Caddyfile
Después de guardar, formatea primero:
sudo caddy fmt --overwrite /etc/caddy/Caddyfile
Luego comprueba la configuración:
sudo caddy validate --config /etc/caddy/Caddyfile
Finalmente recarga:
sudo systemctl reload caddy
Visita https://app.example.com. Si el DNS, los puertos y la aplicación funcionan correctamente, Caddy solicitará automáticamente el certificado y reenviará las solicitudes.
Muchos principiantes hacen que las aplicaciones escuchen directamente en 0.0.0.0:3000 y luego usan Caddy como proxy inverso. Normalmente esto no es una buena práctica.
Se recomienda:
公网用户 -> Caddy :443 -> 127.0.0.1:3000
Las razones son:
- Los usuarios externos solo pueden acceder a 80/443 y no pueden saltarse Caddy para acceder directamente al puerto de la aplicación.
- TLS, compresión, registros y encabezados de seguridad se gestionan de forma centralizada en Caddy.
- Los servicios de aplicación pueden ser más simples y no necesitan gestionar HTTPS por sí mismos.
- Los puntos de entrada entre varias aplicaciones son más claros.
Si la aplicación admite configurar la dirección de escucha, prioriza 127.0.0.1. Por ejemplo, una aplicación Node.js puede escuchar solo en la dirección local, y una aplicación Docker puede mapearse solo a 127.0.0.1:端口.
Un solo VPS puede ejecutar varios servicios. El Caddyfile se puede escribir así:
app.example.com {
reverse_proxy 127.0.0.1:3000
}
api.example.com {
reverse_proxy 127.0.0.1:4000
}
status.example.com {
reverse_proxy 127.0.0.1:3001
}
Cada bloque de sitio gestiona de forma independiente un dominio. Caddy gestionará automáticamente HTTPS para cada dominio.
Si varios dominios apuntan al mismo servicio, también se pueden escribir en el mismo bloque de sitio:
example.com, www.example.com {
reverse_proxy 127.0.0.1:3000
}
Supongamos que tu servicio Docker Compose escucha en 3000 dentro del contenedor. La forma más sencilla es exponer el puerto solo a la máquina local:
services:
app:
image: your-app:latest
ports:
- "127.0.0.1:3000:3000"
restart: unless-stopped
Luego Caddy hace proxy inverso al puerto local:
app.example.com {
reverse_proxy 127.0.0.1:3000
}
Esto es más seguro que mapear directamente 3000:3000, porque la red externa no puede acceder directamente a http://服务器IP:3000.
Si Caddy también se ejecuta en Docker, puedes poner Caddy y la aplicación en la misma red Docker y luego hacer proxy inverso usando el nombre del servicio. Pero para la mayoría de los usuarios de VPS de una sola máquina, instalar Caddy en el sistema y vincular las aplicaciones Docker a localhost es más intuitivo y más fácil de solucionar.
En la mayoría de los casos, no. El reverse_proxy de Caddy gestiona las solicitudes comunes de actualización a WebSocket.
Por ejemplo, Uptime Kuma, n8n, algunos paneles en tiempo real o API WebSocket normalmente pueden funcionar directamente:
ws.example.com {
reverse_proxy 127.0.0.1:8080
}
Si la documentación de la aplicación requiere conservar el encabezado Host, Caddy ya pasa la información de Host adecuada de forma predeterminada. Solo los upstream especiales requieren cambios adicionales de encabezados.
Caddy no solo puede hacer proxy inverso; también puede alojar directamente sitios estáticos.
Supongamos que los archivos estáticos están en /var/www/site:
example.com {
root * /var/www/site
file_server
}
Crea el directorio y establece los permisos:
sudo mkdir -p /var/www/site
echo '<h1>Hello Caddy</h1>' | sudo tee /var/www/site/index.html
sudo chown -R caddy:caddy /var/www/site
Si tu sitio web tiene tanto archivos estáticos como una API backend, también puedes combinarlos:
example.com {
root * /var/www/site
file_server
handle_path /api/* {
reverse_proxy 127.0.0.1:4000
}
}
Los sitios comunes pueden habilitar gzip y zstd:
app.example.com {
encode zstd gzip
reverse_proxy 127.0.0.1:3000
}
Esto suele ser útil para recursos de texto, API JSON, HTML, CSS y JS. Las imágenes y los vídeos normalmente ya están comprimidos y no se beneficiarán de forma notable.
Los encabezados de seguridad básicos se pueden añadir así:
app.example.com {
encode zstd gzip
header {
X-Content-Type-Options nosniff
X-Frame-Options DENY
Referrer-Policy strict-origin-when-cross-origin
}
reverse_proxy 127.0.0.1:3000
}
Nota: no copies a ciegas una Content-Security-Policy muy estricta. Una CSP incorrecta puede provocar que fallen recursos del frontend, inicios de sesión de terceros, scripts de analítica o la carga de imágenes. En producción, se recomienda empezar con encabezados simples y luego endurecer la CSP gradualmente.
Caddy tiene registros del sistema de forma predeterminada, pero también puedes escribir registros de acceso separados para un sitio:
app.example.com {
log {
output file /var/log/caddy/app.example.com.log
format json
}
reverse_proxy 127.0.0.1:3000
}
Asegúrate de que el directorio existe y pertenece al usuario de Caddy:
sudo mkdir -p /var/log/caddy
sudo chown -R caddy:caddy /var/log/caddy
sudo systemctl reload caddy
Ver los registros:
sudo journalctl -u caddy -f
sudo tail -f /var/log/caddy/app.example.com.log
Después de cada cambio en el Caddyfile, se recomienda seguir siempre este orden:
sudo caddy fmt --overwrite /etc/caddy/Caddyfile
sudo caddy validate --config /etc/caddy/Caddyfile
sudo systemctl reload caddy
Ver el estado del servicio:
systemctl status caddy --no-pager
Ver registros en tiempo real:
sudo journalctl -u caddy -f
Reiniciar Caddy:
sudo systemctl restart caddy
Normalmente se prefiere reload, porque carga de forma fluida cuando la configuración es válida; usa restart solo cuando el estado del servicio sea anómalo.
Comprueba en orden:
dig app.example.com +short
sudo ss -lntp | grep -E ':80|:443'
sudo ufw status
systemctl status caddy --no-pager
Confirma especialmente: si el DNS apunta al VPS actual, si Caddy escucha en 80/443 y si el firewall y el grupo de seguridad permiten el acceso.
Consulta los registros de Caddy:
sudo journalctl -u caddy --since "30 minutes ago"
Causas comunes:
- El DNS aún no ha surtido efecto.
- El puerto 80 no está abierto.
- El dominio resuelve a un servidor antiguo.
- Cloudflare Flexible SSL provoca problemas de redirección.
- El mismo dominio falla con frecuencia en poco tiempo, activando los límites de la CA.
Después de corregirlo, no reinicies sin parar. Confirma primero el DNS y los puertos, y luego recarga.
502 normalmente significa que Caddy es accesible, pero la aplicación upstream no responde.
Comprueba el puerto de la aplicación:
curl -I http://127.0.0.1:3000
sudo ss -lntp | grep 3000
Si incluso un curl local falla, el problema está en la aplicación, no en Caddy. Comprueba el proceso de la aplicación, el contenedor Docker, las variables de entorno y los registros de inicio.
Para aplicaciones Docker, comprueba:
docker ps
docker logs --tail=100 your-container-name
Si usaste handle_path, elimina el prefijo coincidente. Algunas aplicaciones necesitan conservar el prefijo de ruta; en ese caso, deberías usar handle o directamente reverse_proxy.
Por ejemplo:
example.com {
handle /api/* {
reverse_proxy 127.0.0.1:4000
}
handle {
reverse_proxy 127.0.0.1:3000
}
}
Los problemas de ruta aparecen más fácilmente en el escenario de "varias aplicaciones bajo un mismo dominio". Si la aplicación en sí no admite una ruta base, prioriza usar subdominios diferentes en lugar de forzarla bajo una subruta.
A continuación se muestra una plantilla adecuada para la mayoría de las configuraciones de VPS de una sola máquina:
{
email [email protected]
}
app.example.com {
encode zstd gzip
header {
X-Content-Type-Options nosniff
Referrer-Policy strict-origin-when-cross-origin
}
log {
output file /var/log/caddy/app.example.com.log
format json
}
reverse_proxy 127.0.0.1:3000
}
api.example.com {
encode zstd gzip
reverse_proxy 127.0.0.1:4000
}
status.example.com {
reverse_proxy 127.0.0.1:3001
}
El email global no es obligatorio, pero se recomienda rellenar una dirección de correo real para las notificaciones relacionadas con certificados ACME.
Si ya estás familiarizado con Nginx y tienes configuraciones empresariales complejas, bibliotecas de configuración históricas o requisitos del ecosistema Lua/OpenResty, seguir usando Nginx no supone ningún problema.
Si estás en las siguientes situaciones, Caddy suele ser más sencillo:
- Un solo VPS o un número reducido de VPS.
- La necesidad principal es el proxy inverso HTTPS y múltiples dominios.
- Muchas aplicaciones autoalojadas, pero la escala de tráfico no es extrema.
- Quieres reducir el mantenimiento de Certbot, renew hooks y plantillas de server block.
- Los miembros del equipo no todos tienen perfil de operaciones y quieres una mejor legibilidad de la configuración.
En pocas palabras: Nginx es más como una navaja suiza con muchas funciones, mientras que Caddy es más como un punto de entrada automatizado optimizado para sitios HTTPS modernos. Para VPS personales y escenarios autoalojados pequeños y medianos, Caddy es muy eficiente.
Antes de poner en producción, se recomienda hacer estas comprobaciones:
- Vincula los puertos de la aplicación solo a
127.0.0.1, no expongas directamente puertos como3000,8080. - Abre solo los puertos necesarios en el grupo de seguridad de la nube, por ejemplo 22, 80 y 443.
- Usa inicio de sesión SSH con clave y desactiva el inicio de sesión con contraseña.
- Después de modificar el Caddyfile, valida antes de recargar.
- Añade el propio inicio de sesión de la aplicación, contraseñas fuertes o inicio de sesión único para los servicios de backend.
- No expongas servicios de datos importantes directamente a la red pública solo porque tengas Caddy.
- Actualiza periódicamente el sistema y Caddy.
Caddy resuelve el punto de entrada web y TLS, pero no equivale a completar por ti el control de permisos de la capa de aplicación. Los sistemas de backend, los paneles de administración y los paneles de bases de datos siguen necesitando su propia autenticación y control de acceso.
Al desplegar varias aplicaciones en un VPS, Caddy puede combinar los problemas frecuentes de "dominio, HTTPS, renovación de certificados, proxy inverso y punto de entrada multisitio" en un Caddyfile muy corto.
La configuración mínima solo necesita:
app.example.com {
reverse_proxy 127.0.0.1:3000
}
Pero para un despliegue realmente estable, también hay que comprobar el DNS, los puertos 80/443, el firewall, los grupos de seguridad, las direcciones de escucha de las aplicaciones, los registros y el proceso de recarga. Siempre que configures como se describe en este artículo, podrás usar un solo VPS para alojar varios servicios HTTPS al mismo tiempo y ya no tendrás que escribir scripts adicionales para la renovación de certificados.