Fail2Ban Docker - bảo vệ server Docker và Nginx reverse proxy

Fail2Ban cho Docker: chặn bot qua DOCKER-USER

Fail2Ban Docker nghe đơn giản nhưng hay cấu hình sai ở production: ban IP trong INPUT chain nhưng traffic vào container lại đi qua FORWARD/NAT, khiến bot vẫn chạm được Nginx hoặc service publish port. Cách ổn hơn là để Fail2Ban chạy trên host, đọc log thật của Nginx/SSH, rồi ban IP qua chain DOCKER-USER trước khi Docker forward packet vào container.

Fail2Ban Docker - bảo vệ server Docker và Nginx reverse proxy
Ảnh: server infrastructure minh họa cho cấu hình Fail2Ban trên Docker host.

Khi nào cần Fail2Ban cho Docker?

Nếu server đang publish Nginx reverse proxy, app panel, SSH hoặc API public ra Internet, bạn sẽ thấy log 404 scan, brute-force, request quá tốc độ hoặc thử path nhạy cảm. Nginx limit_req giúp giảm request rate ở layer HTTP, còn Fail2Ban giúp chặn IP ở firewall khi hành vi xấu lặp lại.

Bài này dùng bối cảnh Ubuntu/Debian host chạy Docker Engine, Nginx container hoặc Nginx Proxy Manager có log mount ra host. Nếu bạn đang dùng Nginx native, phần jail vẫn áp dụng, chỉ cần đổi logpath.

Vấn đề chính: Docker bỏ qua một phần firewall thông thường

Fail2Ban Docker: ban IP đúng vị tríInternet BotDOCKER-USERDROP banned IPDocker NATFORWARD chainNginx/AppcontainerFail2Ban đọc log Nginx/SSHmatch regex → thêm rule vào DOCKER-USERRule ở INPUT chain có thể không chặn được traffic publish port; DOCKER-USER chạy trước chain Docker quản lý.
Sơ đồ: Fail2Ban nên chèn rule vào DOCKER-USER để chặn IP trước khi traffic vào container.

Docker tạo rule firewall để NAT và forward traffic cho container. Tài liệu Docker lưu ý không nên sửa rule Docker tự tạo, và Docker/ufw có thể không tương thích như nhiều người nghĩ: traffic vào port publish có thể bị route trước khi chạm rule ufw INPUT. Vì vậy nếu chỉ ban ở INPUT chain, bạn có thể tưởng đã chặn nhưng container vẫn nhận traffic.

DOCKER-USER là chain được Docker dành cho rule do admin thêm vào trước khi packet đi tiếp vào chain Docker quản lý. Đây là nơi phù hợp để Fail2Ban chèn rule drop/reject cho IP xấu.

Bước 1: cài Fail2Ban trên Docker host

Với Ubuntu/Debian:

sudo apt update
sudo apt install -y fail2ban
sudo systemctl enable --now fail2ban
fail2ban-client version

Không nên chạy Fail2Ban “mỗi container một bản” nếu mục tiêu là bảo vệ toàn host. Chạy trên host giúp quản lý firewall nhất quán, đặc biệt cho SSH và các port publish.

Bước 2: đảm bảo Nginx log nằm trên host

Fail2Ban chỉ ban được khi đọc được log. Với Docker Compose, mount log Nginx ra host:

services:
  nginx:
    image: nginx:1.27-alpine
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx/conf.d:/etc/nginx/conf.d:ro
      - /var/log/docker-nginx:/var/log/nginx

Nếu dùng Nginx Proxy Manager, log thường nằm trong volume/data của NPM. Hãy xác định đúng file access/error log trước khi viết jail.

Bước 3: cấu hình banaction dùng DOCKER-USER

Tạo action riêng để chèn rule vào DOCKER-USER. Ví dụ với iptables:

sudo tee /etc/fail2ban/action.d/docker-user.conf >/dev/null <<'EOF'
[Definition]
actionstart = iptables -N f2b-<name> 2>/dev/null || true
              iptables -C DOCKER-USER -j f2b-<name> 2>/dev/null || iptables -I DOCKER-USER -j f2b-<name>
              iptables -C f2b-<name> -j RETURN 2>/dev/null || iptables -A f2b-<name> -j RETURN

actionstop = iptables -D DOCKER-USER -j f2b-<name> 2>/dev/null || true
             iptables -F f2b-<name> 2>/dev/null || true
             iptables -X f2b-<name> 2>/dev/null || true

actioncheck = iptables -n -L DOCKER-USER >/dev/null

actionban = iptables -I f2b-<name> 1 -s <ip> -j DROP

actionunban = iptables -D f2b-<name> -s <ip> -j DROP
EOF

Cảnh báo: nếu host dùng nftables backend hoặc distro custom firewall, hãy kiểm tra backend trước. Đừng flush toàn bộ iptables/nftables trên server production vì có thể làm rớt kết nối và phá rule Docker.

Bước 4: jail cho SSH

SSH thường nên bảo vệ trước. Với systemd journal:

sudo tee /etc/fail2ban/jail.d/sshd-local.conf >/dev/null <<'EOF'
[sshd]
enabled = true
backend = systemd
port = ssh
maxretry = 5
findtime = 10m
bantime = 1h
EOF

sudo fail2ban-client reload
sudo fail2ban-client status sshd

SSH không nhất thiết phải dùng DOCKER-USER nếu SSH chạy native trên host; jail mặc định thường đủ. DOCKER-USER quan trọng hơn với service publish qua Docker.

Bước 5: Nginx rate limit + Fail2Ban

Nginx có module ngx_http_limit_req_module dùng thuật toán leaky bucket để giới hạn request theo key như IP. Ví dụ:

# trong http {}
limit_req_zone $binary_remote_addr zone=login_per_ip:10m rate=5r/m;
limit_req_status 429;
limit_req_log_level warn;

server {
  location /wp-login.php {
    limit_req zone=login_per_ip burst=10 nodelay;
    proxy_pass http://wordpress:80;
  }
}

Sau đó để Fail2Ban đọc error log Nginx và ban IP nào vượt rate nhiều lần:

sudo tee /etc/fail2ban/filter.d/nginx-limit-req-local.conf >/dev/null <<'EOF'
[Definition]
failregex = limiting requests, excess: .* by zone "[^\"]+", client: <HOST>,
ignoreregex =
EOF

sudo tee /etc/fail2ban/jail.d/nginx-limit-req-local.conf >/dev/null <<'EOF'
[nginx-limit-req-local]
enabled = true
filter = nginx-limit-req-local
logpath = /var/log/docker-nginx/error.log
maxretry = 10
findtime = 10m
bantime = 1h
action = docker-user[name=nginx-limit-req-local]
EOF

sudo fail2ban-regex /var/log/docker-nginx/error.log /etc/fail2ban/filter.d/nginx-limit-req-local.conf
sudo fail2ban-client reload
sudo fail2ban-client status nginx-limit-req-local

Nếu bạn đang dựng reverse proxy cho container, có thể xem thêm bài Caddy reverse proxy cho Docker hoặc Linux logrotate cho Nginx, Docker và systemd để quản lý log bền hơn.

Kiểm tra ban có thật sự vào DOCKER-USER không

Checklist triển khai Fail2Ban Docker1. Mount log Nginx/container ra host2. Test failregex bằng fail2ban-regex với log thật3. Dùng action chèn rule vào DOCKER-USER4. Ban thử IP test, kiểm tra iptables -S DOCKER-USERProduction tip: giữ SSH/console dự phòng trước khi reload firewall hoặc Fail2Ban.
Checklist: các bước cần kiểm tra trước khi bật Fail2Ban cho Docker trên production.
sudo fail2ban-client set nginx-limit-req-local banip 203.0.113.10
sudo iptables -S DOCKER-USER
sudo iptables -S f2b-nginx-limit-req-local
sudo fail2ban-client set nginx-limit-req-local unbanip 203.0.113.10

Nếu rule không xuất hiện, kiểm tra tên action, quyền Fail2Ban, backend firewall và việc chain DOCKER-USER tồn tại. Với Docker mới hoặc cấu hình nftables, cần điều chỉnh action tương ứng.

Troubleshooting nhanh

  • Không match log: chạy fail2ban-regex với một dòng log thật, đừng đoán regex.
  • Ban rồi nhưng bot vẫn vào: rule có thể nằm sai chain; kiểm tra DOCKER-USER.
  • Không thấy IP thật: reverse proxy/CDN có thể làm log chỉ thấy IP proxy; cần cấu hình real IP đúng.
  • ufw đã deny nhưng container vẫn mở: đây là hành vi thường gặp do Docker NAT trước ufw INPUT.
  • Log quá lớn: cấu hình rotate, tham khảo bài logrotate đã link ở trên.

FAQ về Fail2Ban Docker

Có nên chạy Fail2Ban trong container không?

Có thể, nhưng với production đơn giản hơn là chạy Fail2Ban trên host để quản lý SSH, Nginx log và firewall tập trung. Container Fail2Ban cần mount log, capability mạng và cấu hình cẩn thận.

DOCKER-USER khác INPUT chain thế nào?

INPUT xử lý traffic vào chính host. Traffic đến port publish của container thường đi qua forward/NAT, nên rule trong DOCKER-USER phù hợp hơn để chặn trước khi packet vào Docker chain.

Fail2Ban có thay thế Nginx rate limit không?

Không. Nginx rate limit xử lý tốc độ request ở HTTP layer; Fail2Ban dùng log để ban IP lặp lại hành vi xấu ở firewall layer. Hai lớp này bổ sung cho nhau.

Dùng Cloudflare thì có cần Fail2Ban không?

Vẫn cần nếu origin còn public hoặc có SSH/API không qua Cloudflare. Nếu traffic web chỉ qua Cloudflare, hãy cấu hình allowlist Cloudflare IP và real IP header trước khi viết rule ban.

Kết luận

Fail2Ban Docker hiệu quả nhất khi bạn đọc đúng log, match đúng hành vi và ban ở đúng chain. Với service publish qua Docker, hãy ưu tiên DOCKER-USER, test bằng IP giả trước khi triển khai rộng và luôn giữ console/SSH dự phòng khi thay đổi firewall production.

Nguồn tham khảo: Fail2Ban documentation; Nginx ngx_http_limit_req_module; Docker packet filtering and firewalls.

Leave a Comment

Your email address will not be published. Required fields are marked *