Proteger aplicaciones Docker publicadas con Nginx Proxy Manager y Authelia 2FA

Introducción

Cuando publicamos aplicaciones Docker en Internet —paneles de administración, gestores de contenedores, herramientas de monitorización, interfaces de backup, dashboards o cualquier servicio sensible— es habitual colocarlas detrás de un proxy inverso como Nginx Proxy Manager. Esto permite acceder a cada aplicación mediante un subdominio, gestionar certificados HTTPS y evitar tener que recordar puertos.

Sin embargo, esta configuración por sí sola no siempre es suficiente. Si una aplicación queda expuesta directamente por su puerto Docker, por ejemplo:

http://IP_DEL_SERVIDOR:3552

cualquier protección configurada en el proxy puede saltarse. Además, muchas aplicaciones solo incorporan autenticación básica mediante usuario y contraseña. Para servicios críticos, especialmente aquellos que administran Docker, servidores, copias de seguridad o infraestructura, es recomendable añadir una capa adicional de seguridad.

La solución que se plantea en este manual consiste en:

Internet  ↓Nginx Proxy Manager  ↓Authelia con doble factor de autenticación  ↓Aplicación Docker protegida

De esta forma, antes de llegar a la aplicación real, el usuario debe autenticarse en Authelia y superar una verificación en dos pasos. Solo después Nginx Proxy Manager permitirá el acceso al contenedor interno.

Este enfoque se basa en el mecanismo auth_request de nginx, que permite autorizar una petición en función de la respuesta de un servicio externo de autenticación. Si la subpetición devuelve una respuesta válida, nginx deja pasar al usuario; si no, lo redirige o bloquea el acceso.

Qué vamos a conseguir

Al terminar este procedimiento tendremos:

https://app.ejemplo.com  ↓Nginx Proxy Manager  ↓Authelia: usuario + contraseña + 2FA  ↓Aplicación Docker interna

Y evitaremos esta situación insegura:

http://IP_DEL_SERVIDOR:PUERTO  ↓Aplicación Docker directamente expuesta

La aplicación protegida no tendrá publicado su puerto en el host. Solo será accesible desde la red Docker interna compartida con Nginx Proxy Manager.

Por qué usar esta solución

Existen varias alternativas para proteger aplicaciones Docker publicadas:

1. Usar solo el login propio de la aplicación.2. Restringir el acceso por IP.3. Acceder exclusivamente por VPN.4. Usar autenticación básica de nginx.5. Implementar SSO/OIDC en cada aplicación.6. Usar Authelia delante de Nginx Proxy Manager.

La opción de usar únicamente el login propio de cada aplicación es cómoda, pero insuficiente para servicios sensibles. La restricción por IP puede ser útil, pero no siempre es práctica si accedemos desde redes móviles, ubicaciones cambiantes o varios dispositivos. Una VPN es una solución excelente, pero puede ser más incómoda si queremos mantener accesos web publicados de forma controlada.

La autenticación básica de nginx añade una pequeña barrera, pero no aporta segundo factor. En cambio, Authelia permite centralizar autenticación, políticas de acceso y 2FA para múltiples servicios. Además, se integra bien con nginx y Nginx Proxy Manager mediante snippets reutilizables. La documentación oficial de Authelia contempla integraciones específicas tanto con nginx como con Nginx Proxy Manager.

Arquitectura final

La arquitectura que se busca es esta:

Internet  ↓Puerto 443 del VPS  ↓Nginx Proxy Manager  ↓Authelia  ↓Red Docker interna "proxy"  ↓Aplicación protegida

Ejemplo práctico:

auth.ejemplo.com  → Autheliaapp.ejemplo.com   → Aplicación Docker protegida

Nginx Proxy Manager será el único servicio expuesto públicamente en los puertos 80 y 443. Authelia y la aplicación protegida estarán disponibles únicamente dentro de una red Docker compartida.

Docker Compose crea redes internas para que los contenedores puedan comunicarse por nombre de servicio, y también permite definir redes externas reutilizables entre varios proyectos Compose.

Requisitos previos

Para seguir este manual se parte de un servidor Linux con:

Docker instaladoDocker Compose instaladoNginx Proxy Manager funcionandoUno o varios servicios Docker publicados mediante subdominiosAcceso SSH al servidorUn dominio propio apuntando al servidor

En los ejemplos se usarán estos datos ficticios:

Dominio principal: ejemplo.comDominio de Authelia: auth.ejemplo.comDominio de la aplicación protegida: app.ejemplo.comRed Docker compartida: proxyUsuario de Authelia: usuario_adminRuta de Authelia: /opt/autheliaRuta de Nginx Proxy Manager: /opt/nginx-proxy-manager

Sustituye estos valores por los tuyos.


1. Comprobar los contenedores actuales

Primero conviene ver qué contenedores están funcionando y qué puertos tienen publicados:

docker ps --format "table {{.Names}}\t{{.Image}}\t{{.Ports}}"

Un ejemplo de salida problemática sería:

NAMES          IMAGE                         PORTSmi_app         imagen/mi_app:latest          0.0.0.0:3552->3552/tcpnpm            jc21/nginx-proxy-manager      0.0.0.0:80-81->80-81/tcp, 0.0.0.0:443->443/tcp

Aquí la aplicación mi_app está publicada directamente en el host:

0.0.0.0:3552->3552/tcp

Eso significa que se puede acceder a ella por:

http://IP_DEL_SERVIDOR:3552

aunque también esté detrás de Nginx Proxy Manager.

El objetivo es que la aplicación aparezca así:

mi_app    imagen/mi_app:latest    3552/tcp

Es decir, que el puerto exista dentro del contenedor, pero no esté publicado en el host.


2. Crear una red Docker compartida

Vamos a crear una red Docker llamada proxy, que será compartida por Nginx Proxy Manager, Authelia y las aplicaciones protegidas.

docker network create proxy

Si la red ya existe, Docker mostrará un aviso. No pasa nada.

Podemos comprobar las redes existentes con:

docker network ls

Deberíamos ver algo como:

NETWORK ID     NAME      DRIVER    SCOPExxxxxxxxxxxx   proxy     bridge    local

3. Conectar Nginx Proxy Manager a la red compartida

Nginx Proxy Manager debe estar en la red proxy para poder resolver por nombre interno a Authelia y a las aplicaciones protegidas.

Primero identificamos el nombre real del contenedor:

docker ps --format "table {{.Names}}\t{{.Image}}\t{{.Ports}}"

Supongamos que el contenedor se llama:

nginx_proxy_manager-app-1

Podemos conectarlo manualmente a la red:

docker network connect proxy nginx_proxy_manager-app-1

Esto sirve para probar, pero no es suficiente para que sea permanente. Si el contenedor se recrea, puede perder esta red. Por eso hay que consolidarlo en el compose.yaml de Nginx Proxy Manager.

Localizar el compose de Nginx Proxy Manager

Podemos usar las etiquetas de Docker Compose:

docker inspect nginx_proxy_manager-app-1 --format 'Working dir: {{ index .Config.Labels "com.docker.compose.project.working_dir" }}Config file: {{ index .Config.Labels "com.docker.compose.project.config_files" }}Project: {{ index .Config.Labels "com.docker.compose.project" }}Service: {{ index .Config.Labels "com.docker.compose.service" }}'

Si el archivo existe, hacemos copia:

cd /opt/nginx-proxy-managercp compose.yaml compose.yaml.bak

Si el archivo no existe, puede reconstruirse siempre que se conserven los volúmenes data y letsencrypt, que son los que guardan la configuración y certificados de Nginx Proxy Manager.

Un ejemplo de compose.yaml válido sería:

name: nginx_proxy_managerservices:  app:    image: jc21/nginx-proxy-manager:latest    restart: unless-stopped    ports:      - "80:80"      - "81:81"      - "443:443"    volumes:      - ./data:/data      - ./letsencrypt:/etc/letsencrypt      - ./snippets:/snippets    networks:      - default      - proxynetworks:  proxy:    external: true

Nginx Proxy Manager utiliza habitualmente los puertos 80, 443 y 81 para HTTP, HTTPS y la interfaz de administración, respectivamente.

Validamos:

docker compose config

Aplicamos sin hacer down:

docker compose up -d

Comprobamos que NPM está en ambas redes:

docker inspect nginx_proxy_manager-app-1 --format '{{.Name}} -> {{range $net,$v := .NetworkSettings.Networks}}{{println $net}}{{end}}'

Resultado esperado:

/nginx_proxy_manager-app-1 -> nginx_proxy_manager_defaultproxy

4. Quitar la exposición directa de la aplicación Docker

Este paso es fundamental. No tiene sentido poner 2FA delante de Nginx Proxy Manager si la aplicación puede seguir abriéndose por su puerto directo.

Supongamos que tenemos una aplicación Docker con este compose.yaml:

services:  mi_app:    image: imagen/mi_app:latest    container_name: mi_app    restart: unless-stopped    ports:      - "3552:3552"

Ese bloque:

ports:  - "3552:3552"

publica el puerto en el host.

Hay que sustituirlo por:

expose:  - "3552"

y conectar el servicio a la red proxy:

services:  mi_app:    image: imagen/mi_app:latest    container_name: mi_app    restart: unless-stopped    expose:      - "3552"    networks:      - proxynetworks:  proxy:    external: true

La diferencia es importante:

ports  → publica un puerto del contenedor en el hostexpose → documenta/expone el puerto internamente para otros contenedores

Docker documenta la publicación de puertos como el mecanismo para hacer accesible un puerto del contenedor desde el host, mientras que las redes de Compose permiten que los servicios se comuniquen internamente por nombre.

Aplicamos:

cd /opt/mi_appdocker compose up -d --force-recreate

Comprobamos:

docker ps --format "table {{.Names}}\t{{.Image}}\t{{.Ports}}"

Resultado correcto:

mi_app    imagen/mi_app:latest    3552/tcp

Resultado incorrecto:

mi_app    imagen/mi_app:latest    0.0.0.0:3552->3552/tcp

También es incorrecto esto:

ports:  - "3552"

porque Docker puede asignar un puerto aleatorio del host, por ejemplo:

0.0.0.0:32768->3552/tcp

En ese caso la aplicación seguiría publicada, aunque en otro puerto.


5. Configurar el Proxy Host de la aplicación en NPM

En Nginx Proxy Manager vamos a editar o crear el Proxy Host de la aplicación.

Entramos en:

Hosts → Proxy Hosts → Add Proxy Host

o editamos uno existente.

En la pestaña Details:

Domain Names:app.ejemplo.comScheme:httpForward Hostname / IP:mi_appForward Port:3552

Activamos:

Cache Assets: OFFBlock Common Exploits: ONWebsockets Support: ON, si la aplicación usa WebSockets

En la pestaña SSL:

Request a new SSL CertificateForce SSL: ONHTTP/2 Support: ON

En este punto la aplicación debería seguir funcionando por:

https://app.ejemplo.com

pero ya no por:

http://IP_DEL_SERVIDOR:3552

Para probar la comunicación interna:

docker run --rm --network proxy curlimages/curl:latest -I http://mi_app:3552

Si devuelve HTTP/1.1 200, 302, 401 o similar, la red interna funciona.


6. Instalar Authelia

Creamos la estructura:

mkdir -p /opt/authelia/configcd /opt/authelia

Creamos el compose.yaml:

nano compose.yaml

Contenido:

services:  authelia:    image: authelia/authelia:latest    container_name: authelia    restart: unless-stopped    expose:      - "9091"    volumes:      - ./config:/config    networks:      - proxynetworks:  proxy:    external: true

Authelia utiliza ficheros YAML de configuración y puede desplegarse en Docker montando un directorio de configuración en /config.


7. Generar secretos para Authelia

Generamos tres valores secretos:

openssl rand -hex 32openssl rand -hex 32openssl rand -hex 32

No deben publicarse ni compartirse.

Los usaremos para:

jwt_secretsession.secretstorage.encryption_key

También podemos usar la propia CLI de Authelia para generar valores seguros, ya que Authelia documenta comandos específicos para generar valores aleatorios y hashes criptográficos.


8. Crear la configuración principal de Authelia

Creamos:

nano /opt/authelia/config/configuration.yml

Contenido de ejemplo:

server:  address: 'tcp://:9091/'log:  level: 'info'totp:  issuer: 'ejemplo.com'identity_validation:  reset_password:    jwt_secret: 'PEGAR_AQUI_SECRETO_1'authentication_backend:  file:    path: '/config/users_database.yml'access_control:  default_policy: 'deny'  rules:    - domain: 'auth.ejemplo.com'      policy: 'bypass'    - domain: 'app.ejemplo.com'      policy: 'two_factor'session:  secret: 'PEGAR_AQUI_SECRETO_2'  cookies:    - domain: 'ejemplo.com'      authelia_url: 'https://auth.ejemplo.com'      default_redirection_url: 'https://app.ejemplo.com'      same_site: 'lax'      inactivity: '10m'      expiration: '1h'      remember_me: '1d'regulation:  max_retries: 3  find_time: '2m'  ban_time: '10m'storage:  encryption_key: 'PEGAR_AQUI_SECRETO_3'  local:    path: '/config/db.sqlite3'notifier:  filesystem:    filename: '/config/notification.txt'

La sección access_control permite definir qué dominios requieren una autenticación simple, doble factor, bypass o denegación. En este caso, auth.ejemplo.com queda accesible para poder iniciar sesión, mientras que app.ejemplo.com requiere doble factor.


9. Crear el usuario de Authelia

Authelia no guarda contraseñas en texto claro. Hay que generar un hash.

Ejecutamos:

docker run --rm -it authelia/authelia:latest authelia crypto hash generate argon2

Introducimos la contraseña cuando la pida.

El resultado tendrá un formato parecido a:

Digest: $argon2id$v=19$m=65536,t=3,p=4$...

En el fichero de usuarios hay que pegar solo la parte que empieza por $argon2id$, sin el prefijo Digest:. Authelia documenta el comando authelia crypto hash generate argon2 para generar hashes Argon2.

Creamos:

nano /opt/authelia/config/users_database.yml

Contenido:

users:  usuario_admin:    disabled: false    displayname: 'Administrador'    password: '$argon2id$v=19$m=65536,t=3,p=4$HASH_DE_EJEMPLO'    email: 'admin@ejemplo.com'    groups:      - 'admins'

Aplicamos permisos:

chmod 600 /opt/authelia/config/configuration.ymlchmod 600 /opt/authelia/config/users_database.yml

Arrancamos:

cd /opt/autheliadocker compose up -d

Comprobamos logs:

docker logs -f authelia

Resultado esperado:

Startup completeListening for non-TLS connections on '[::]:9091'

Si aparece un error como:

argon2 decode errorillegal base64 data

lo más probable es que se haya pegado mal el hash, por ejemplo incluyendo Digest: o algún carácter adicional.


10. Publicar Authelia en Nginx Proxy Manager

Ahora necesitamos acceder a Authelia desde:

https://auth.ejemplo.com

En Nginx Proxy Manager:

Hosts → Proxy Hosts → Add Proxy Host

Pestaña Details:

Domain Names:auth.ejemplo.comScheme:httpForward Hostname / IP:autheliaForward Port:9091Cache Assets:OFFBlock Common Exploits:ONWebsockets Support:OFF

Pestaña SSL:

Request a new SSL CertificateForce SSL: ONHTTP/2 Support: ON

Guardamos y probamos:

https://auth.ejemplo.com

Debería aparecer la pantalla de Authelia.


11. Preparar snippets en Nginx Proxy Manager

Para que Nginx Proxy Manager pueda consultar a Authelia antes de enviar tráfico a una aplicación, vamos a usar snippets.

La integración oficial de Authelia con Nginx Proxy Manager se basa en incluir bloques de configuración en el campo Advanced de cada Proxy Host protegido.

Creamos la carpeta de snippets si no existe:

mkdir -p /opt/nginx-proxy-manager/snippets

El compose.yaml de NPM debe montar esa carpeta dentro del contenedor:

volumes:  - ./data:/data  - ./letsencrypt:/etc/letsencrypt  - ./snippets:/snippets

Aplicamos:

cd /opt/nginx-proxy-managerdocker compose up -d

Comprobamos que el contenedor ve la carpeta:

docker exec -it nginx_proxy_manager-app-1 ls -la /snippets

12. Crear los snippets de Authelia

proxy.conf

nano /opt/nginx-proxy-manager/snippets/proxy.conf

Contenido:

proxy_set_header Host $host;proxy_set_header X-Original-URL $scheme://$http_host$request_uri;proxy_set_header X-Forwarded-Proto $scheme;proxy_set_header X-Forwarded-Host $http_host;proxy_set_header X-Forwarded-URI $request_uri;proxy_set_header X-Forwarded-Ssl on;proxy_set_header X-Forwarded-For $remote_addr;proxy_set_header X-Real-IP $remote_addr;client_body_buffer_size 128k;proxy_next_upstream error timeout invalid_header http_500 http_502 http_503;proxy_redirect http:// $scheme://;proxy_http_version 1.1;proxy_cache_bypass $cookie_session;proxy_no_cache $cookie_session;proxy_buffers 64 256k;send_timeout 5m;proxy_read_timeout 360;proxy_send_timeout 360;proxy_connect_timeout 360;

websocket.conf

nano /opt/nginx-proxy-manager/snippets/websocket.conf

Contenido:

proxy_set_header Upgrade $http_upgrade;proxy_set_header Connection "upgrade";

Este snippet es necesario para aplicaciones que usan WebSockets. En el caso de Arcane, por ejemplo, su documentación indica que detrás de un reverse proxy debe configurarse soporte WebSocket para que la interfaz funcione correctamente en tiempo real.

authelia-location.conf

nano /opt/nginx-proxy-manager/snippets/authelia-location.conf

Contenido:

set $upstream_authelia http://authelia:9091/api/authz/auth-request;location /internal/authelia/authz {    internal;    proxy_pass $upstream_authelia;    proxy_set_header X-Original-Method $request_method;    proxy_set_header X-Original-URL $scheme://$http_host$request_uri;    proxy_set_header X-Forwarded-For $remote_addr;    proxy_set_header Content-Length "";    proxy_set_header Connection "";    proxy_pass_request_body off;    proxy_next_upstream error timeout invalid_header http_500 http_502 http_503;    proxy_redirect http:// $scheme://;    proxy_http_version 1.1;    proxy_cache_bypass $cookie_session;    proxy_no_cache $cookie_session;    proxy_buffers 4 32k;    client_body_buffer_size 128k;    send_timeout 5m;    proxy_read_timeout 240;    proxy_send_timeout 240;    proxy_connect_timeout 240;}

authelia-authrequest.conf

nano /opt/nginx-proxy-manager/snippets/authelia-authrequest.conf

Contenido:

auth_request /internal/authelia/authz;auth_request_set $user $upstream_http_remote_user;auth_request_set $groups $upstream_http_remote_groups;auth_request_set $name $upstream_http_remote_name;auth_request_set $email $upstream_http_remote_email;proxy_set_header Remote-User $user;proxy_set_header Remote-Groups $groups;proxy_set_header Remote-Email $email;proxy_set_header Remote-Name $name;auth_request_set $redirection_url $upstream_http_location;error_page 401 =302 $redirection_url;

El bloque auth_request hace que nginx consulte a Authelia mediante una subpetición interna antes de dejar pasar la solicitud al backend protegido.

Comprobamos la configuración de nginx:

docker exec -it nginx_proxy_manager-app-1 nginx -t

Si todo está correcto:

docker exec -it nginx_proxy_manager-app-1 nginx -s reload

13. Proteger una aplicación concreta con Authelia

Ahora vamos a proteger app.ejemplo.com.

En Nginx Proxy Manager:

Hosts → Proxy Hosts → app.ejemplo.com → Edit

En Details:

Scheme:httpForward Hostname / IP:mi_appForward Port:3552Cache Assets:OFFBlock Common Exploits:ON

En Advanced, borramos cualquier configuración personalizada previa y añadimos:

include /snippets/authelia-location.conf;location / {    include /snippets/proxy.conf;    include /snippets/websocket.conf;    include /snippets/authelia-authrequest.conf;    proxy_pass $forward_scheme://$server:$port;}

Guardamos.

Después validamos nginx:

docker exec -it nginx_proxy_manager-app-1 nginx -t

Si está correcto:

docker exec -it nginx_proxy_manager-app-1 nginx -s reload

14. Registrar el segundo factor

Entramos en ventana privada:

https://app.ejemplo.com

El flujo esperado será:

app.ejemplo.com  ↓redirige a auth.ejemplo.com  ↓usuario + contraseña  ↓registro o validación del segundo factor  ↓vuelve a app.ejemplo.com

Como hemos configurado notificación por fichero, el enlace de registro del segundo factor aparecerá en:

cat /opt/authelia/config/notification.txt

Abrimos el enlace, escaneamos el código QR con una aplicación TOTP como Aegis, 2FAS, Google Authenticator, Microsoft Authenticator u otra compatible, y terminamos el registro.

Authelia soporta segundo factor mediante TOTP y también llaves de seguridad WebAuthn, entre otros métodos.


15. Comprobaciones finales

Comprobar que la aplicación no está expuesta directamente

docker ps --format "table {{.Names}}\t{{.Image}}\t{{.Ports}}"

Resultado correcto:

mi_app    imagen/mi_app:latest    3552/tcp

Resultado incorrecto:

mi_app    imagen/mi_app:latest    0.0.0.0:3552->3552/tcp

Comprobar que NPM y la app comparten red

docker inspect mi_app --format '{{.Name}} -> {{range $net,$v := .NetworkSettings.Networks}}{{println $net}}{{end}}'

Debe aparecer:

proxy

Y para NPM:

docker inspect nginx_proxy_manager-app-1 --format '{{.Name}} -> {{range $net,$v := .NetworkSettings.Networks}}{{println $net}}{{end}}'

Debe aparecer también:

proxy

Comprobar resolución interna

docker run --rm --network proxy curlimages/curl:latest -I http://mi_app:3552

Debe responder con una cabecera HTTP.

Comprobar acceso externo

Desde el navegador:

https://app.ejemplo.com

Debe pasar primero por Authelia.

Desde fuera, esto no debería funcionar:

http://IP_DEL_SERVIDOR:3552

16. Añadir más aplicaciones protegidas

Para proteger otra aplicación Docker, se repite el mismo patrón.

Supongamos una nueva aplicación:

monitor.ejemplo.comcontenedor: monitorpuerto interno: 3000

Su compose.yaml debería tener:

services:  monitor:    image: imagen/monitor:latest    container_name: monitor    restart: unless-stopped    expose:      - "3000"    networks:      - proxynetworks:  proxy:    external: true

En Authelia añadimos una regla:

access_control:  default_policy: 'deny'  rules:    - domain: 'auth.ejemplo.com'      policy: 'bypass'    - domain: 'app.ejemplo.com'      policy: 'two_factor'    - domain: 'monitor.ejemplo.com'      policy: 'two_factor'

Reiniciamos Authelia:

cd /opt/autheliadocker compose restart authelia

En Nginx Proxy Manager creamos el Proxy Host:

Domain Names: monitor.ejemplo.comScheme: httpForward Hostname / IP: monitorForward Port: 3000

Y en Advanced:

include /snippets/authelia-location.conf;location / {    include /snippets/proxy.conf;    include /snippets/websocket.conf;    include /snippets/authelia-authrequest.conf;    proxy_pass $forward_scheme://$server:$port;}

17. Errores habituales y solución

Error: Could not resolve host: mi_app

Si al probar:

docker run --rm --network proxy curlimages/curl:latest -I http://mi_app:3552

aparece:

Could not resolve host

significa que el contenedor no está en la red proxy o no tiene ese nombre.

Comprobar redes:

docker inspect mi_app --format '{{.Name}} -> {{range $net,$v := .NetworkSettings.Networks}}{{println $net}}{{end}}'

Conectar temporalmente:

docker network connect --alias mi_app proxy mi_app

Y consolidar en el compose.yaml:

networks:  - proxy

Error: la aplicación aparece publicada en un puerto aleatorio

Si vemos:

0.0.0.0:32768->3552/tcp

probablemente en el compose se ha puesto:

ports:  - "3552"

Eso sigue publicando el servicio. Hay que eliminar ports: y usar:

expose:  - "3552"

Error: Authelia no arranca por el hash

Si los logs muestran:

argon2 decode errorillegal base64 data

revisar users_database.yml.

Debe ser:

password: '$argon2id$v=19$m=...'

No debe ser:

password: 'Digest: $argon2id$v=19$m=...'

Error: Failed to fetch al reiniciar desde un panel de Docker

Si se está gestionando desde una aplicación que a su vez depende de Docker, puede fallar al reiniciar su propio proyecto o la red que le da acceso. Para cambios en la infraestructura base —Nginx Proxy Manager, Authelia, redes Docker o el propio gestor Docker— es más seguro usar SSH:

docker compose up -d

Error: nginx no recarga

Comprobar:

docker exec -it nginx_proxy_manager-app-1 nginx -t

Si hay errores, revisar el bloque Advanced del Proxy Host y los snippets.


18. Copia de seguridad recomendada

Después de dejar todo funcionando, conviene guardar una copia de seguridad de las configuraciones:

tar -czf /root/backup-npm-authelia-apps-$(date +%F-%H%M).tgz \  /opt/authelia \  /opt/nginx-proxy-manager \  /opt/mi_app

También es recomendable guardar en un gestor de contraseñas:

Usuario de AutheliaContraseña de AutheliaCódigos de recuperación 2FA, si se generanUbicación de los ficheros configuration.yml y users_database.ymlDominio de AutheliaLista de aplicaciones protegidas

Nunca deben publicarse:

ContraseñasHashes realesSecretos de sesiónClaves de cifradoTokensIPs reales internas si no se desea exponer la arquitectura

19. Resultado final

Tras aplicar esta configuración, cualquier aplicación Docker publicada quedará protegida así:

Usuario externo  ↓HTTPS  ↓Nginx Proxy Manager  ↓Authelia  ↓usuario + contraseña + segundo factor  ↓aplicación Docker interna

Y la aplicación ya no será accesible por su puerto directo:

http://IP_DEL_SERVIDOR:PUERTO

Esto no convierte el servidor en invulnerable, pero sí mejora mucho la seguridad respecto a una publicación directa con simple usuario y contraseña.

La clave está en combinar varias capas:

1. No publicar puertos internos innecesarios.2. Usar una red Docker interna compartida.3. Publicar solo Nginx Proxy Manager.4. Añadir Authelia como barrera 2FA.5. Mantener el login propio de cada aplicación.6. Revisar logs y copias de seguridad.

20. Referencias y documentación consultada

Para la elaboración de este manual se ha utilizado documentación oficial y asistencia técnica interactiva:

  • Documentación oficial de Authelia sobre integración con nginx.
  • Documentación oficial de Authelia sobre integración con Nginx Proxy Manager.
  • Documentación oficial de Authelia sobre control de acceso y políticas two_factor.
  • Documentación oficial de Authelia sobre segundo factor de autenticación.
  • Documentación oficial de Authelia sobre configuración mediante ficheros YAML.
  • Documentación oficial de Authelia sobre generación de hashes Argon2.
  • Documentación oficial de nginx sobre el módulo auth_request.
  • Documentación de NGINX sobre autenticación mediante subpeticiones.
  • Documentación oficial de Docker Compose sobre redes y comunicación entre servicios.
  • Documentación oficial de Docker sobre publicación de puertos.
  • Documentación oficial de Nginx Proxy Manager sobre instalación y puertos utilizados.
  • Documentación oficial de Arcane sobre instalación, reverse proxy y WebSockets, usada como caso práctico de aplicación Docker sensible protegida detrás de Nginx Proxy Manager.
  • ChatGPT, de OpenAI, como asistente técnico utilizado para diseñar, depurar y documentar el procedimiento paso a paso, incluyendo la anonimización de datos privados y la adaptación del proceso a un formato publicable en tecnotizate.es.

Publicaciones Similares

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *