Nginx Proxy Manager o la manera sencilla de manejar acceso a tus servicios docker
Cualquier servidor necesita manejar el tráfico de entrada HTTP y HTTPs a los servicios que manejamos a nivel interno. En este artículo queremos explicar el funcionamiento de un servicio llamado Nginx Proxy Manager para realizar esta gestión.
Requisitos
- Acceso a un DNS real
- Conexión a nuestro router
- Creación de una DMZ
- Servidor con Docker y Docker Compose
¿Qué es Reverse Proxy o Proxy Reverso?
Nginx es un servidor HTTP que permite realizar la redirección a otro servidor web o proxy inverso como se llama técnicamente.
Como puede verse el servidor proxy recibe la petición y la redirige al servidor web que la procesa, esto evidentemente lo hace por configuración, el Nginx debe saber que URL/Petición corresponde a qué servidor.
Este tipo de proxies sirven también para bastionar los servicios que estén detrás de del proxy con una cobertura HTTPS, es decir nos permitirá tener certificados TLS en el servidor proxy para evitar tener que hacer esta configuración en cada uno de los servicios internos que queremos exponer.
Para ello NPM (Nginx Proxy Manager) usa internamente lestencrypt para gestionar y solicitar los certificados TLS que se aplicarán en cada vhost.
Configuración DNS
En nuestro caso el servidor Nginx va a ser colocado en una máquina Docker que arrancará en el puerto 80 y 443 que debe ser accesible mediante una ip pública y un nombre dns real. Para ello nosotros usamos un cliente de DDNS llamado dinaip, tal como explicamos ya en el blog.
Pero con una pequeña salvedad, que debemos crear un registro dns que los angloparlantes llaman wildcard, vamos un * de toda la vida. Lo que queremos conseguir es que podamos asociar diferentes nombres DNS a un mismo servidor.
Imagina que tu servidor está disponible en la IP fija, entonces deberías crear un registro de tipo A que tenga como nombre de host *.nombre_servidor dentro de la configuración de zonas de tu dominio.
Por lo que cualquier URL que sea *.nombre_servidor.dominio.com será válida.
En nuestro caso cualquier nombre por delante de mordor.cursosdedesarrollo.com, por ejemplo wordpress.mordor.cursosdedesarrollo.com
Nosotros recomendamos que se tenga siempre que sea posible una IP fija en la conexión a internet donde esté el servidor, sino tendremos que usar algún mecanismo DDNS
Si podemos hacer uso de terraform para acceder al sistema de DNS de nuestro proveedor en la nube también podríamos hacer uso de esta wildcard
Una vez que hayas cambiado la configuración lo suyo es que compruebes si el dns está configurado correctamente con el comando nslookup
$ nslookup servicio.servidor.dominio.com
Si queremos acceder al servidor con el nombre que queramos a nivel interno, dentro de nuestra red y no desde internet podemos configurar nuestro /etc/hosts o nuestro servidor DNS local para que apunte al servidor con los nombres que queramos. Internamente nostros usamos Pihole. Cómo configurarlo lo veremos en otra entrada más adelante.
Configuración de Nginx Proxy Manager con Docker Compose
Lo primero que debemos confirmar es que no tenemos ningún servicio ocupando los puertos 80 y 443 en la máquina que nos ocupa. Su estás usando portainer esto debería ser bastante sencillo vete a los contenedores muestra todos y verás si esos puertos está ocupados.
Si lo están deberás llevar esos servicios a otros puertos para que podamos levantar adecuadamente Nginx Proxy Manager (npm a partir de ahora)
Con esto ya configurado podemos empezar con la instalación del servicio, para empezar deberemos crear una carpeta para este proyecto por ejemplo
$ mkdir nginx-proxy-manager
$ cd nginx-proxy-manager
Crearemos un fichero docker-compose.yaml:
version: '3.8' services: web: image: nginx container_name: nginx_docker restart: always networks: - npm app: image: 'jc21/nginx-proxy-manager:latest' container_name: npm_server restart: unless-stopped ports: # These ports are in format <host-port>:<container-port> - '80:80' # Public HTTP Port - '443:443' # Public HTTPS Port - '81:81' # Admin Web Port # Add any other Stream port you want to expose # - '21:21' # FTP # Uncomment the next line if you uncomment anything in the section environment: # Uncomment this if you want to change the location of # the SQLite DB file within the container DB_SQLITE_FILE: "/data/database.sqlite" #Uncomment this if IPv6 is not enabled on your host DISABLE_IPV6: 'true' networks: - npm volumes: - ./data:/data - ./letsencrypt:/etc/letsencrypt networks: npm: name: npm driver: bridge
Este fichero tiene bastante chicha así que vamos a explicarlo poco a poco.
Como vemos tenemos tres servicios a arrancar:
- app: es la aplicación en, veremos que usa los puerto 80, 443 y un uĺtimo puerto que es el gestor de npm, en este caso lo exponemos como el puerto 81, aunque internamente usa el 81
- db: es la bbdd mariadb que se usa para guardar todas las configuraciones
- web: en el servidor nginx que procesará las peticiones
Además disponemos de dos volúmenes:
- data: donde meterá todos los ficheros de configuración
- lestencrypt: donde meterá todos los certificados generados
Por otro lado las redes:
- npm: es la red principal de NPM y es la que deberemos compartir con otros servicios si queremos poder llegar a ellos con nuestro proxy. Como se puede ver es de tipo bridge
Como vemos sólo hay unos puertos expuestos que son los de NPM pero ni están expuestos los de Mariadb ni los de nginx.
Ahora sólo deberíamos ejecutar el docker-compose up -d para arrancarlo:
$ docker-compose up -d
Acceso al Nginx Proxy Manager
Si todo va bien deberíamos poder acceder al servicio de configuración en este caso:
Primer Login
Una vez entremos al servicio tendremos que loguearnos con los datos por defecto:
Email: admin@example.com
Password: changeme
Y tendríamos que entrar al Dashboard principal de NPM
En este caso tenemos el menú de usuario, que ya tengo configurado y el menú de acceso.
Lo primero que debemos hacer es cambiar el usuario en la parte de Users, donde podremos cambiar el email del usario y la contraseña con el menú de tres puntos del final de cada fila de usuario
Red de Docker
Cuando hayamos arrancado NPM con Docker Compose nos debería haber creado una red, que podemos mirarla por ejemplo desde portainer en en el host en el apartado de networks
Esta red seguramente la haya llamado nginx-proxy-manager_npm y es la que deberemos configurar en el resto de docker compose para que hagan uso de la misma para poder acceder a los contenedores que arranquemos más tarde.
Nosotros por ejemplo lo hacemos par muchos servicios:
En vuestro caso sólo deberían aparecer los contenedores que acabamos de levantar, pero esta bien que recuerdes que más tarde deberían aparecer todos los contenedores que asocies a esta red.
Portainer
Imagina que quieres arrancar portainer pero que pueda ser accesible desde internet pero usando NPM como paraguas para acceder a él con soporte de HTTPS.
Entonces lo primero que debemos hacer es modificar o crear un docker-compose.yml que arranque portainer y que pueda accederse a él desde la red de NPM, veamos un ejemplo:
version: '3.2' services: portainer: image: portainer/portainer-ce:2.11.0 container_name: portainer ports: - "9000:9000" #- "9443:9443" - "8000:8000" volumes: - ./volumes/portainer_data:/data - /var/run/docker.sock:/var/run/docker.sock restart: always networks: - npm - portainer networks: portainer: name: portainer driver: bridge npm: external: true
Como vemos aquí no hay mucha modificación respecto a un portianer normal y corriente salvo por la parte de las redes (networks), tanto el contenedor como el fichero docker compose definen la red nginx-proxy-manager_npm como red externa con el parámetro external a true, a parte de definir una red propia para portainer.
Ahora deberemos levantar portainer de la manera habitual
$ docker-compose up -d
Si todo ha ido bien deberías poder acceder a portainer desde http://servidor:9000/ como siempre y si vamos a portainer en el apartado de redes debería aparecer el contenedor dentro de la red nginx-proxy-manager_npm, como vimos antes.
De esta manera el contenedor de npm debería tener visibilidad al contenedor de portainer
Proxy Hosts
Todo esto para ahora empezar configurando los proxy hosts en NPM.
Para ello dentro del Nginx Proxy Manager vía web entraremos al apartado de Hosts->Proxy Hosts donde daremos de alta los diferentes servicios dependiendu de su URL de entrada.
Para ello deberemos configurar dos proxy host, uno para el uso interno y otro para el externo.
Acceso Interno
Empezaremos con el uso interno por lo que pulsamos en el botón Add Proxy Host y nos saldrá un diálogo donde meteremos la configuración.
Como vemos en domain names indicamos el nombre o ip de la máquina, en nuestro caso portainer que hemos asociado con la IP del servidor.
Elegimos el esquema http, en el forward hostname/ip podemos poner o el nombre del contenedor de portainer o la ip que tenga ese contenedor dentro de la red de NPM, e indicamos el puerto de acceso.
Después podremos salvar y acceder a través de la url http://portainer/
Recuerda que si no tienes el registro dns o la modificación del del fichero hosts esta redirección no te funcionará, repasa el apartado de Configuración de DNS
Acceso externo
Si todo ha ido bien con la configuración del acceso interno, podemos pasar a la configuración del servicio desde fuera, para ello recuerda que debe existir un registro DNS que apunte a tu servidor con el nombre que vayas a usar en el acceso externo.
Como en el caso anterior deberemos crear un nuevo Proxy Host, pero esta vez cambiando el domain name por el nombre que le hayamos dado
Cabe recordar que en el ejemplo de la captura vemos un domain name que se ha configurado un registro A con una wildcard *.mordor apuntando a la IP del servidor
Pero esta vez ya podremos configurar la parte de los certificados SSL/TLS dentro de la pestaña SSL:
Conviene recordar que el despleguable del certificado SSL seleccionaremos “Request new certificate with letsencrypt” para que cuando lo guarde pida a letsencrypt que genere el certificado SSL para ese dominio. Si tuviéramos otro certificado anterior podríamos seleccionarlo. Pero en nuestro caso pondremos el correo de registro en letsencrypt y aceptaremos los términos de uso.
Como vemos en esa misma pantalla podremos forzar a usar SSL, soportar http2 y el uso de HSTS entre otros…
Guardamos y si todo ha ido bien en poco tiempo habrá solicitado el certificado y asociado a ese nombre de dominio.
Por lo que si entramos a https://nombre_dominio/ deberíamos entrar al servicio indicado pero con el candado reconocido por nuestro navegador sin mucho problema.
Configuración con MariaDB
Si quisiéramos configurar el entorno con una base de datos MariaDB tendríamos que usar el siguiente fichero docker-compose.yaml
version: '3.8' services: web: image: nginx container_name: nginx_docker restart: always networks: - npm app: image: 'jc21/nginx-proxy-manager:latest' container_name: npm_server restart: unless-stopped ports: # These ports are in format <host-port>:<container-port> - '80:80' # Public HTTP Port - '443:443' # Public HTTPS Port - '81:81' # Admin Web Port # Add any other Stream port you want to expose # - '21:21' # FTP # Uncomment the next line if you uncomment anything in the section environment: # Uncomment this if you want to change the location of # the SQLite DB file within the container DB_SQLITE_FILE: "/data/database.sqlite" #Uncomment this if IPv6 is not enabled on your host DISABLE_IPV6: 'true' networks: - npm volumes: - ./data:/data - ./letsencrypt:/etc/letsencrypt networks: npm: name: npm driver: bridge
Conclusiones
Como hemos visto es un proceso algo complejo al principio por el tema DNS y de redes pero una vez establecido pordemos hacer el uso que nosotros queramos sin mucho problema.
Conviene recordar que lo suyo es que hagamos esto con contenedores docker pero podríamos extenderlos a otros servicios no ejecutados desde docker.
Comments
Leave a Reply
Internamente nostros usamos Pihole. Cómo configurarlo lo veremos en otra entrada más adelante.
ESO LO DIJISTE Y NO ENCUENTRO ESA INFORMACION
CREES PODER HACERLA!
GRACias
tambien vi que montaste
AUTHELIA
explica sobre eso tambien
gracias
Puedo usar VIRTUAL_HOSTNAME en nginx proxy manager?
Buenas. En esta página puedes ver como incorporar configuraciones extra en nginx proxy manager. https://nginxproxymanager.com/advanced-config/