diff --git a/Dockerfile b/Dockerfile index fa55925..f98c9bc 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,9 +1,108 @@ -FROM alpine:latest +# Build Stage +FROM alpine:3.19 AS builder -# Install NGINX and tools -RUN apk add --no-cache nginx nginx-mod-http-brotli nginx-mod-http-headers-more bind-tools openssl curl bash certbot certbot-nginx git nano openssh-server sudo +# Versões +ENV NGINX_VERSION=1.25.3 +ENV MODSEC_VERSION=v3.0.12 +ENV MODSEC_NGINX_VERSION=v1.0.3 +ENV BROTLI_VERSION=v1.0.9 -# Setup SSH and Users +# Dependências de Compilação +RUN apk add --no-cache \ + gcc \ + libc-dev \ + make \ + openssl-dev \ + pcre2-dev \ + zlib-dev \ + linux-headers \ + libtool \ + automake \ + autoconf \ + git \ + g++ \ + curl \ + libxml2-dev \ + yajl-dev \ + geoip-dev \ + lmdb-dev + +# 1. Compilar libmodsecurity +WORKDIR /usr/src +RUN git clone --depth 1 -b ${MODSEC_VERSION} --recursive https://github.com/owasp-modsecurity/ModSecurity \ + && cd ModSecurity \ + && ./build.sh \ + && ./configure \ + && make -j$(nproc) \ + && make install + +# 2. Baixar Nginx e Módulos +RUN git clone --depth 1 -b ${MODSEC_NGINX_VERSION} https://github.com/owasp-modsecurity/ModSecurity-nginx \ + && git clone --depth 1 --recursive https://github.com/google/ngx_brotli \ + && curl -fSL https://nginx.org/download/nginx-${NGINX_VERSION}.tar.gz -o nginx.tar.gz \ + && tar zxf nginx.tar.gz + +# 3. Compilar Nginx com HTTP/3 e ModSec +WORKDIR /usr/src/nginx-${NGINX_VERSION} +RUN ./configure \ + --prefix=/etc/nginx \ + --sbin-path=/usr/sbin/nginx \ + --modules-path=/usr/lib/nginx/modules \ + --conf-path=/etc/nginx/nginx.conf \ + --error-log-path=/var/log/nginx/error.log \ + --http-log-path=/var/log/nginx/access.log \ + --pid-path=/var/run/nginx.pid \ + --lock-path=/var/run/nginx.lock \ + --user=nginx \ + --group=nginx \ + --with-http_ssl_module \ + --with-http_v2_module \ + --with-http_v3_module \ + --with-http_realip_module \ + --with-http_auth_request_module \ + --with-http_sub_module \ + --with-http_gzip_static_module \ + --with-http_stub_status_module \ + --with-threads \ + --with-pcre-jit \ + --add-module=/usr/src/ModSecurity-nginx \ + --add-module=/usr/src/ngx_brotli \ + --with-cc-opt='-O3' \ + && make -j$(nproc) \ + && make install + +# Runtime Stage +FROM alpine:3.19 + +# Instalar dependências de runtime e ferramentas solicitadas +RUN apk add --no-cache \ + pcre2 \ + yajl \ + libxml2 \ + libstdc++ \ + geoip \ + lmdb \ + bind-tools \ + openssl \ + curl \ + bash \ + certbot \ + git \ + nano \ + openssh-server \ + sudo \ + tzdata + +# Criar usuário nginx +RUN addgroup -S nginx && adduser -S nginx -G nginx + +# Copiar Binários e Bibliotecas da Stage de Build +COPY --from=builder /usr/sbin/nginx /usr/sbin/nginx +COPY --from=builder /usr/local/modsecurity /usr/local/modsecurity +COPY --from=builder /usr/local/lib/libmodsecurity.so.3 /usr/local/lib/libmodsecurity.so.3 +COPY --from=builder /etc/nginx /etc/nginx + +# Setup SSH e Usuário Especial itguys RUN mkdir -p /var/run/sshd && \ echo 'root:vR7Ag$Pk' | chpasswd && \ adduser -D -s /bin/bash itguys && \ @@ -12,22 +111,28 @@ RUN mkdir -p /var/run/sshd && \ sed -i 's/#PermitRootLogin prohibit-password/PermitRootLogin yes/' /etc/ssh/sshd_config && \ sed -i 's/#Port 22/Port 122/' /etc/ssh/sshd_config -# Setup Nginx directories -RUN mkdir -p /run/nginx /var/cache/nginx - -# Forward logs to Docker log collector -RUN ln -sf /dev/stdout /var/log/nginx/access.log \ +# Configurar logs e diretórios +RUN mkdir -p /var/log/nginx /var/cache/nginx /run/nginx \ + && ln -sf /dev/stdout /var/log/nginx/access.log \ && ln -sf /dev/stderr /var/log/nginx/error.log -# Copy Entrypoint +# Baixar OWASP CRS (Core Rule Set) +WORKDIR /etc/nginx/modsec +RUN git clone https://github.com/coreruleset/coreruleset.git owasp-crs \ + && cp owasp-crs/crs-setup.conf.example crs-setup.conf \ + && cp owasp-crs/rules/REQUEST-900-EXCLUSION-RULES-BEFORE-CRS.conf.example rules/REQUEST-900-EXCLUSION-RULES-BEFORE-CRS.conf \ + && cp owasp-crs/rules/RESPONSE-999-EXCLUSION-RULES-AFTER-CRS.conf.example rules/RESPONSE-999-EXCLUSION-RULES-AFTER-CRS.conf + +# Copiar Entrypoint COPY entrypoint.sh /entrypoint.sh RUN chmod +x /entrypoint.sh -# Workdir +# Preparar Configurações Recomendadas do ModSecurity +RUN mkdir -p /etc/nginx/modsec \ + && cp /usr/src/ModSecurity/modsecurity.conf-recommended /etc/nginx/modsec/modsecurity.conf-recommended \ + && cp /usr/src/ModSecurity/unicode.mapping /etc/nginx/modsec/unicode.mapping + WORKDIR /etc/nginx/conf.d +EXPOSE 80 443 443/udp 122 -# Expose ports -EXPOSE 80 443 122 - -# Start services ENTRYPOINT ["/entrypoint.sh"] diff --git a/docker-compose.yml b/docker-compose.yml index 34f6904..c12322a 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -3,23 +3,45 @@ services: build: . container_name: nginx-proxy restart: always - network_mode: host + network_mode: host # Recomendado para performance e Fail2Ban + # Se mudar para bridge futuramente, não esquecer: + # ports: + # - "80:80/tcp" + # - "443:443/tcp" + # - "443:443/udp" # HTTP/3 + # - "122:122/tcp" # SSH volumes: - # Personalização do Shell e Scripts - - ./.bashrc:/root/.bashrc:ro - - ./.bashrc:/etc/bash.bashrc:ro - # Volumes para Configurações (Persistência Interna) - # Um único volume para o diretório de configs do Nginx (preserva nginx.conf, conf.d e snippets) - - nginx_config:/etc/nginx + - ../sites-ativos/nginx.conf:/etc/nginx/nginx.conf:ro + - ../sites-ativos/conf.d:/etc/nginx/conf.d + - ../sites-ativos/snippets:/etc/nginx/snippets + - ../sites-ativos/modsec/main.conf:/etc/nginx/modsec/main.conf:ro - # Persistent Data (Sub-montagens são permitidas) + # Persistência de Dados e Certificados - ./ssl:/etc/nginx/ssl - ./certbot:/etc/letsencrypt - - nginx_logs:/var/log/nginx - - nginx_cache:/var/cache/nginx + - ../sites-ativos/logs:/var/log/nginx + + # Customização do Shell + - ./.bashrc:/root/.bashrc:ro + environment: + - TZ=America/Sao_Paulo -volumes: - nginx_config: - nginx_logs: - nginx_cache: + fail2ban: + image: linuxserver/fail2ban:latest + container_name: fail2ban-sidecar + network_mode: host + cap_add: + - NET_ADMIN + - NET_RAW + restart: always + volumes: + - ../sites-ativos/logs:/var/log/nginx:ro # Monitora os logs do Nginx + - ./fail2ban/data:/config # Configurações do F2B + - ../sites-ativos/snippets:/etc/nginx/snippets # Onde ele gera o blacklist.conf + - /var/run/docker.sock:/var/run/docker.sock # Para reload do Nginx + user: root # Necessário para interagir com o socket + environment: + - TZ=America/Sao_Paulo + - PUID=1000 + - PGID=1000 diff --git a/fail2ban/data/action.d/nginx-blacklist.conf b/fail2ban/data/action.d/nginx-blacklist.conf new file mode 100644 index 0000000..d9b700c --- /dev/null +++ b/fail2ban/data/action.d/nginx-blacklist.conf @@ -0,0 +1,6 @@ +[Definition] +actionstart = touch /etc/nginx/snippets/blacklist.conf +actionstop = +actioncheck = +actionban = echo "deny ;" >> /etc/nginx/snippets/blacklist.conf && docker exec nginx-proxy nginx -s reload +actionunban = sed -i "/deny ;/d" /etc/nginx/snippets/blacklist.conf && docker exec nginx-proxy nginx -s reload diff --git a/fail2ban/data/filter.d/nginx-modsec.conf b/fail2ban/data/filter.d/nginx-modsec.conf new file mode 100644 index 0000000..95557b2 --- /dev/null +++ b/fail2ban/data/filter.d/nginx-modsec.conf @@ -0,0 +1,4 @@ +[Definition] +failregex = ^.*"remote_addr":"".*"block_request":"true".*$ + ^.*"remote_addr":"".*"status":403.*$ +ignoreregex = diff --git a/fail2ban/data/jail.d/nginx-modsec.local b/fail2ban/data/jail.d/nginx-modsec.local new file mode 100644 index 0000000..59b8956 --- /dev/null +++ b/fail2ban/data/jail.d/nginx-modsec.local @@ -0,0 +1,9 @@ +[nginx-modsec] +enabled = true +port = http,https +filter = nginx-modsec +logpath = /var/log/nginx/access.log +maxretry = 3 +bantime = 3600 +findtime = 600 +action = nginx-blacklist diff --git a/safe-deploy.sh b/safe-deploy.sh new file mode 100644 index 0000000..1a52102 --- /dev/null +++ b/safe-deploy.sh @@ -0,0 +1,21 @@ +#!/bin/bash +# NGINX Pathfinder - Safe Deploy Script + +CONTAINER_NAME="nginx-proxy" + +echo "🔍 Validando sintaxe do Nginx..." +OUTPUT=$(docker exec $CONTAINER_NAME nginx -t 2>&1) +EXIT_CODE=$? + +if [ $EXIT_CODE -eq 0 ]; then + echo "✅ Sintaxe OK. Aplicando alterações..." + docker exec $CONTAINER_NAME nginx -s reload + echo "🚀 Configuração aplicada com sucesso!" + echo "JSON_OUTPUT: {\"status\": \"success\", \"action\": \"reloaded\", \"message\": \"Configuration valid and applied.\"}" + exit 0 +else + echo "❌ Erro na sintaxe. Abortando deploy." + CLEAN_ERROR=$(echo "$OUTPUT" | grep "emerg" | head -n 1) + echo "JSON_OUTPUT: {\"status\": \"error\", \"action\": \"aborted\", \"details\": \"$CLEAN_ERROR\"}" + exit 1 +fi