Guía Paso a Paso: Búnker de Seguridad con Nginx y Docker
Nginx
Docker Compose
Backend API
Ciberseguridad
Objetivo de esta guía: Documentar la arquitectura de defensa perimetral para aislar un backend del acceso público. Se aplican políticas de restricción máxima (Zero Trust y Mínimo Privilegio) limitando drásticamente el tamaño de las peticiones, mitigando ataques DDoS y auditando el tráfico mediante un proxy inverso Nginx contenedorizado.
1. Entendiendo la Arquitectura de Aislamiento
La seguridad real empieza por la arquitectura física de la red. En lugar de exponer la base de datos o la aplicación directamente a internet, creamos capas de protección sucesivas (Arquitectura de Defensa en Profundidad).
Concepto Clave: El Backend y la Base de Datos se ejecutan en una red privada virtual de Docker (secure_net). No tienen puertos expuestos al servidor físico host. El único que puede comunicarse con ellos es Nginx, y Nginx solo acepta peticiones que vengan del proxy principal (Apache) a nivel local.
graph LR
User((App Frontend/Web)) -- HTTPS/443 --> Apache[Apache Reverse Proxy]
subgraph "Servidor Host (Linux)"
Apache -- 127.0.0.1:8081 --> Nginx[Docker Nginx :80]
subgraph "Docker Network (secure_net)"
Nginx -- Proxy Pass --> Backend[Docker Backend API :8080]
Backend -- Internal --> DB[(Base de Datos :5432)]
end
end
style Apache fill:#ffecb3,stroke:#fbc02d,stroke-width:2px
style Nginx fill:#c8e6c9,stroke:#388e3c,stroke-width:2px
style Backend fill:#ffcc80,stroke:#e65100,stroke-width:2px
style DB fill:#bbdefb,stroke:#1976d2,stroke-width:2px
2. Aislamiento Físico (Docker Compose)
El primer paso es configurar nuestro entorno de contenedores para cortar el acceso directo al backend y establecer a Nginx como el único embudo de entrada.
services:
api_backend:
build: .
container_name: app_backend
restart: always
# ELIMINADO: El bloque 'ports' se suprime para hacerlo invisible al exterior
networks:
- secure_net
proxy_nginx:
image: nginx:alpine
container_name: app_nginx
ports:
# RESTRICCIÓN MÁXIMA: Nginx expone su puerto 80 SOLO al localhost (127.0.0.1)
- "127.0.0.1:8081:80"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
depends_on:
- api_backend
networks:
- secure_net
Justificación de Seguridad: Al atar Nginx estrictamente a 127.0.0.1, bloqueamos por diseño que un atacante intente saltarse Apache escaneando o atacando la IP pública del servidor por el puerto 8081. Nginx será completamente sordo a peticiones externas no enrutadas.
3. Defensas Activas: Cortafuegos Restrictivo en Nginx
Asumiendo que todo tráfico entrante es potencialmente hostil, se configuran reglas en Nginx con umbrales extremadamente bajos, ajustados milimétricamente al uso real de la API.
http {
# 1. Ocultar huella del servidor a los atacantes (Evita perfilado de CVEs)
server_tokens off;
# 2. Zona de memoria para control estricto de IP (10MB) a un ritmo de 5 peticiones/seg
limit_req_zone $binary_remote_addr zone=api_limit:10m rate=5r/s;
upstream backend_servers {
server api_backend:8080;
}
# ...
}
3.1. Reglas de Protección (Bloque server)
Dentro del servidor Nginx, aplicamos barreras diseñadas para estrangular cargas maliciosas antes de que consuman ciclos de CPU o memoria en el Backend.
Json manda unos 3kb, con 56k se tiene un margen de seguridad amplio para cualquier petición legítima, pero se bloquea cualquier intento de subida de archivos o inyección de payloads gigantes.
server {
listen 80;
# BARRERA 1: Bloqueo de Payloads Pesados (Restricción a 56 Kilobytes, o menos).
client_max_body_size 56k;
# BARRERA 2: Timeouts Anti-Zombies (Corte agresivo a 10s)
client_body_timeout 10s;
client_header_timeout 10s;
send_timeout 10s;
location / {
# BARRERA 3: Ejecución implacable del Rate Limiting
limit_req zone=api_limit burst=10 nodelay;
proxy_pass http://backend_servers;
}
}
- Límite Asfixiante de 56k: Calculado basándose en el peso real máximo de un JSON legítimo de la aplicación. Bloquea instantáneamente (Error 413) intentos de desbordamiento de búfer o subida de binarios.
- Timeouts Agresivos (10s): Mitiga ataques tipo "Slowloris", cortando conexiones de clientes que envían datos a cuentagotas para agotar los hilos disponibles.
- Burst=10 nodelay: Permite una ventana de 10 peticiones rápidas para carga inicial, pero a partir de ahí bloquea sin piedad cualquier ráfaga de fuerza bruta devolviendo Error 503.
4. Auditoría y Trazabilidad (Logs)
Dado que la API opera detrás de múltiples proxies (Apache -> Nginx -> Docker), las IP entrantes se enmascaran como locales. Se implementa una trazabilidad absoluta para extraer el origen real del tráfico.
# 1. Formato personalizado para capturar la IP real y el Vector de Ataque
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
# 2. Aplicar la política de logs
access_log /var/log/nginx/access.log main;
location / {
# 3. Inyectar la IP real a las cabeceras hacia el Backend
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://backend_servers;
}
4.1. Comandos de Inspección (Respuesta a Incidentes)
Comandos operativos para auditar el sistema o reaccionar ante anomalías de tráfico.
docker logs -f app_nginx
docker logs app_nginx | grep "limiting requests"
docker logs app_nginx | grep "client intended to send too large body"