Por qué necesitas un proxy inverso en un VPS
Un VPS expone una única dirección IP pública. Si ejecutas tres aplicaciones Docker — una API, un front-end y una herramienta de administración — cada una ocupa un puerto diferente: 3000, 8080, 9000. Sin proxy inverso, tus visitantes deben escribir el puerto en la URL, los certificados SSL deben gestionarse aplicación por aplicación, y exponer todos esos puertos públicamente aumenta la superficie de ataque.
Un proxy inverso centraliza la entrada del tráfico: recibe todas las solicitudes en los puertos 80 y 443, inspecciona el nombre de dominio o la ruta, y luego reenvía la solicitud al contenedor correcto en la red interna. Las aplicaciones ya no exponen puertos públicos. SSL finaliza en el nivel del proxy, que redistribuye en HTTP simple sobre la red Docker privada.
Esta arquitectura ofrece tres ventajas concretas: un único punto de gestión de certificados, aislamiento de red de las aplicaciones, y la posibilidad de añadir o eliminar una app sin tocar las demás.
Lo que Nginx Proxy Manager simplifica
- Interfaz web: añade, modifica y elimina hosts proxy sin línea de comandos ni recarga manual
- SSL Let's Encrypt con un clic: NPM solicita, renueva e implementa certificados automáticamente via HTTP-01 o DNS-01
- Wildcard DNS: un único certificado para
*.midominio.comsi tu proveedor DNS soporta la API Certbot - Listas de acceso: autenticación HTTP básica o lista blanca de IPs directamente desde la interfaz
- Redirecciones y URLs personalizadas: HTTP a HTTPS, redirecciones 301/302, sin modificar nginx.conf
- Recarga sin interrupción: NPM recarga la configuración nginx en segundo plano, sin tiempo de inactividad
Requisitos previos
Para seguir esta guía, necesitas un VPS con Ubuntu 22.04 o Debian 12 con al menos 1 GB de RAM (2 GB recomendados si varias apps se ejecutan simultáneamente). Docker Engine y Docker Compose v2 deben estar instalados.
Los puertos 80 y 443 deben ser accesibles desde el exterior. Verifica que tu firewall (ufw o reglas del panel de control) los permita. Si usas un firewall cloud (grupo de seguridad, firewall VPS), abre estos dos puertos para el tráfico entrante.
Finalmente, debes tener al menos un nombre de dominio o subdominio apuntando a la IP de tu VPS. NPM puede gestionar múltiples dominios simultáneamente — el requisito mínimo es que exista un registro DNS A para cada dominio que quieras proxificar.
Instalar NPM con Docker Compose
Crear la estructura de directorios
Crea una carpeta dedicada y navega a ella:
mkdir -p /opt/npm && cd /opt/npmEsta carpeta contendrá el archivo Compose y los volúmenes persistentes de NPM (base de datos SQLite, certificados, logs).
Redactar docker-compose.yml
Crea el archivo
/opt/npm/docker-compose.ymlcon el siguiente contenido:services: app: image: jc21/nginx-proxy-manager:latest restart: unless-stopped ports: - "80:80" - "443:443" - "81:81" volumes: - ./data:/data - ./letsencrypt:/etc/letsencrypt networks: default: name: proxy-net external: falseEl puerto
81es la interfaz de administración. La redproxy-netse compartirá con tus otros contenedores para que sean accesibles sin exponer puertos públicos.Iniciar NPM
Lanza el contenedor en segundo plano:
docker compose up -dEspera de 30 a 60 segundos para que NPM inicialice su base de datos. Verifica que los tres puertos estén escuchando:
ss -tlnp | grep -E ':(80|81|443)'Primer inicio de sesión y cambio de contraseña
Abre
http://IP_DE_TU_VPS:81en tu navegador. Las credenciales por defecto son[email protected]/changeme.NPM te obliga a cambiar el correo electrónico y la contraseña en el primer inicio de sesión. Usa una dirección válida: se utilizará para las notificaciones de expiración de certificados Let's Encrypt.
Atención: el puerto 81 está expuesto públicamente. Configura inmediatamente una lista de acceso (ver sección "Listas de acceso") o filtra este puerto a nivel de firewall para restringirlo a tu IP.
Añadir un primer host proxy
Crear un nuevo host proxy
En la interfaz de NPM, haz clic en Proxy Hosts y luego en Add Proxy Host. Rellena el campo Domain Names con tu dominio, por ejemplo
app.midominio.com. Asegúrate de que el registro DNS A de este subdominio ya apunte a la IP de tu VPS — Let's Encrypt verificará esta resolución.Configurar el destino
En los campos Forward Hostname / IP y Forward Port, introduce el host y el puerto de tu aplicación. Si la aplicación se ejecuta en un contenedor Docker en la misma red
proxy-net, usa el nombre del servicio Docker como hostname (ejemplo:miappy puerto3000). Marca Block Common Exploits para activar las reglas de filtrado básicas.Activar Let's Encrypt
Pasa a la pestaña SSL en la misma ventana. En el menú desplegable, selecciona Request a new SSL Certificate. Marca Force SSL para redirigir automáticamente HTTP a HTTPS, y HTTP/2 Support para activar HTTP/2. Introduce tu correo electrónico, acepta los términos de Let's Encrypt y haz clic en Save.
NPM lanza inmediatamente la solicitud de certificado mediante el desafío HTTP-01. En menos de un minuto, tu dominio es accesible via HTTPS con un certificado válido.
Verificar el resultado
La lista de hosts proxy ahora muestra tu entrada con una insignia SSL verde. Prueba desde tu navegador o con curl:
curl -I https://app.midominio.comLa respuesta debe contener
HTTP/2 200y una cabeceraserver: nginx. La renovación del certificado es automática — NPM relanza la solicitud 30 días antes de la expiración.
Configurar un subdominio con redirección HTTPS forzada
Forzar HTTPS no es solo una buena práctica: es la base de la seguridad del transporte. Al crear o editar un host proxy, la pestaña SSL expone tres opciones complementarias.
Force SSL: NPM genera automáticamente un bloque return 301 https://$host$request_uri; en la configuración nginx del vhost. Cualquier solicitud HTTP es redirigida en el lado del servidor antes incluso de llegar a tu aplicación.
HSTS (HTTP Strict Transport Security): al marcar esta opción, NPM añade la cabecera Strict-Transport-Security: max-age=63072000; includeSubDomains; preload a las respuestas HTTPS. El navegador recuerda que este dominio debe contactarse siempre via HTTPS. Activa HSTS solo si estás seguro de mantener SSL.
HTTP/2 Support: activa el protocolo HTTP/2 del lado del cliente, sin ninguna modificación del lado de la aplicación. El multiplexado reduce la latencia percibida, especialmente en páginas con muchos recursos.
Caso avanzado: proxy para una app Docker sin puerto expuesto
Una de las ventajas más infrautilizadas de NPM es la capacidad de proxificar contenedores que no exponen ningún puerto público. La comunicación se realiza únicamente en la red Docker interna.
Para que un contenedor sea accesible por NPM sin exposición pública, ambos servicios deben compartir la misma red Docker. Ejemplo con una app Node.js en /opt/miapp/docker-compose.yml:
services:
web:
image: mi-imagen:latest
restart: unless-stopped
# Sin sección 'ports' — el contenedor no es accesible desde el host
networks:
- proxy-net
networks:
proxy-net:
external: trueAl declarar proxy-net como red externa y adjuntar el servicio a esta red, el contenedor web es accesible desde NPM por su nombre de servicio. En la interfaz de NPM, Forward Hostname será simplemente web y Forward Port el puerto interno de la app.
Esta arquitectura significa que incluso si un atacante compromete un contenedor, no puede llegar a otros servicios directamente desde el exterior — todo pasa por el proxy.
Listas de acceso: proteger el backoffice con autenticación
NPM permite restringir el acceso a ciertos hosts proxy mediante listas de acceso. Ve a Access Lists y luego a Add Access List. Dale un nombre a la lista, añade entradas bajo la pestaña Authorization (nombre de usuario + contraseña hasheada), y/o restringe por IP en Access.
Luego edita el host proxy que quieres proteger y selecciona esta lista en el campo Access List. NPM inyecta automáticamente un bloque auth_basic en la configuración nginx del vhost. Esto es especialmente útil para exponer herramientas de administración (Portainer, Grafana, interfaces de API internas) sin desplegar un servidor de autenticación completo.
Para el puerto 81 en sí (la interfaz NPM), la protección pasa por el firewall — restringe el acceso a este puerto a tu IP fija o una VPN.
Comparativa: Nginx Proxy Manager vs Caddy vs Traefik
Desplace la tabla
| Criterio | Nginx Proxy Manager | Caddy | Traefik |
|---|---|---|---|
| Configuración | Interfaz web gráfica, sin archivos que editar | Caddyfile declarativo, sintaxis concisa | YAML/TOML o etiquetas Docker, curva de aprendizaje más pronunciada |
| SSL automático | Let's Encrypt HTTP-01 y DNS-01, interfaz gráfica | Integrado de forma nativa, HTTP-01 y DNS-01 sin plugin | ACME integrado, requiere configuración YAML |
| Auto-descubrimiento Docker | No, configuración manual por host | No nativo, posible via etiquetas con caddy-docker-proxy | Nativo via etiquetas Docker, detecta servicios al iniciar |
| Caso de uso ideal | Desarrollador gestionando menos de 20 apps, prefiere UI sobre config | Stack simple a medio, configuración legible en archivo | Microservicios, Kubernetes, entornos dinámicos |
| Personalización avanzada | Limitada — snippets nginx personalizados posibles pero no recomendados | Alta via módulos y directivas Caddyfile | Muy alta, middlewares encadenables, plugins ricos |
| Recursos | ~50 MB RAM en reposo | ~30 MB RAM en reposo | ~40 MB RAM en reposo, más según plugins |
Límites de NPM y cuándo migrar a Traefik
NPM cubre la gran mayoría de casos de uso de desarrolladores que gestionan una decena de aplicaciones en uno o dos VPS. Empieza a mostrar sus límites en varios escenarios.
Configuración nginx avanzada: NPM genera sus archivos de configuración y los regenera con cada modificación desde la interfaz. Técnicamente es posible añadir snippets personalizados, pero pueden sobreescribirse durante una actualización. Si necesitas configuraciones nginx finas — limitación de tasa por ruta, caché proxy complejo, lógica de reescritura avanzada — NPM se convierte en una capa de fricción en lugar de una ayuda.
Entornos dinámicos: en una arquitectura de microservicios donde los contenedores aparecen y desaparecen frecuentemente, configurar manualmente cada host en NPM se convierte en un cuello de botella. HAProxy o Traefik, que detectan automáticamente los servicios via etiquetas Docker, están mejor adaptados a este contexto.
Kubernetes: NPM no tiene lugar en un clúster Kubernetes. Traefik tiene un Ingress Controller nativo; ingress-nginx es la otra opción común.
Regla práctica: si tu configuración cabe en la interfaz de NPM y no requiere scripts de automatización para mantenerse actualizada, NPM es la elección correcta. En cuanto te encuentres escribiendo scripts para interactuar con la API de NPM o gestionando archivos de configuración fuera de la interfaz, es la señal para evaluar Caddy o Traefik según tu contexto.