production-evyos-systems-an.../proxy-md.md

2.9 KiB
Raw Permalink Blame History

version: '3.8'

services:
  nginx:
    image: owasp/modsecurity:nginx
    container_name: secure_nginx
    ports:
      - "80:80"
    volumes:
      - ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
      - ./nginx/html:/usr/share/nginx/html:ro
      - ./nginx/modsecurity/modsecurity.conf:/etc/modsecurity/modsecurity.conf:ro
      - ./nginx/log:/var/log/nginx
    restart: always

  fail2ban:
    image: crazymax/fail2ban:latest
    container_name: fail2ban
    volumes:
      - ./fail2ban/jail.local:/data/jail.local:ro
      - ./fail2ban/filter.d:/data/filter.d:ro
      - ./nginx/log:/var/log/nginx:ro
      - fail2ban-data:/data
    restart: always
    cap_add:
      - NET_ADMIN
      - NET_RAW

volumes:
  fail2ban-data:
worker_processes 1;

events {
    worker_connections 1024;
}

http {
    include       mime.types;
    default_type  application/octet-stream;

    modsecurity on;
    modsecurity_rules_file /etc/modsecurity/modsecurity.conf;

    log_format main '$remote_addr - $remote_user [$time_local] "$request" '
                    '$status $body_bytes_sent "$http_referer" '
                    '"$http_user_agent" "$http_x_forwarded_for"';

    access_log /var/log/nginx/access.log main;

    limit_req_zone $binary_remote_addr zone=limit1:10m rate=5r/s;

    server {
        listen 80;
        server_name localhost;

        root /usr/share/nginx/html;
        index index.html;

        add_header X-Frame-Options "SAMEORIGIN" always;
        add_header X-XSS-Protection "1; mode=block" always;
        add_header X-Content-Type-Options "nosniff" always;
        add_header Referrer-Policy "no-referrer-when-downgrade" always;
        add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;

        location / {
            limit_req zone=limit1 burst=10 nodelay;
            try_files $uri $uri/ =404;
        }
    }
}

nginx/html/index.html

<!DOCTYPE html>
<html>
<head>
    <title>ModSecurity + Fail2Ban</title>
</head>
<body>
    <h1>Güvenlik Duvarı Aktif!</h1>
</body>
</html>

nginx/modsecurity/modsecurity.conf

SecRuleEngine On
SecRequestBodyAccess On
SecResponseBodyAccess Off

SecRule REQUEST_HEADERS:User-Agent "curl" "id:10001,phase:1,deny,status:403,msg:'Curl client blocked'"

# Basit rate limit sayacı
SecAction "id:10010,phase:1,initcol:ip=%{REMOTE_ADDR},pass,nolog"
SecRule IP:REQCOUNT "@gt 20" "id:10011,phase:2,deny,status:429,msg:'Too many requests'"
SecAction "id:10012,phase:2,pass,nolog,setvar:ip.reqcount=+1"

fail2ban/jail.local

[nginx-req-limit]
enabled = true
filter = nginx-req-limit
action = iptables[name=HTTP, port=http, protocol=tcp]
logpath = /var/log/nginx/access.log
maxretry = 5
findtime = 60
bantime = 3600

fail2ban/filter.d/nginx-req-limit.conf

[Definition]
failregex = <HOST> -.* "(GET|POST).*HTTP.*" 429
ignoreregex =

mkdir -p nginx/html nginx/modsecurity fail2ban/filter.d docker-compose up -d