Tư duy lại về bảo mật Web: Cách tiếp cận hợp nhất so với rời rạc
Sau khi máy chủ của tôi bị tấn công brute-force SSH vào lúc nửa đêm, tôi luôn ưu tiên bảo mật ngay từ bước thiết lập ban đầu. Kinh nghiệm đó dạy tôi rằng bảo mật không phải là thứ bạn “gắn thêm” vào sau; nó cần phải là nền tảng. Hầu hết chúng ta bắt đầu với một container Nginx cơ bản, sau đó nhận ra cần SSL nên cài thêm Certbot.
Sau đó chúng ta lo lắng về SQL injection, nên cố gắng biên dịch ModSecurity. Rồi khi thấy hàng nghìn lượt quét 404 trong log, chúng ta cài Fail2Ban trên host và cố gắng map log qua các Docker volume. Nó nhanh chóng trở thành một “lâu đài trên cát” đầy mong manh.
Cách tiếp cận rời rạc này có thể hiệu quả nếu bạn có một đội ngũ SecOps chuyên trách, nhưng với những ai đang quản lý nhiều dự án hoặc hạ tầng quy mô nhỏ và vừa, đó là một cơn ác mộng về bảo trì. Đây là lúc khái niệm "security-first gateway" (cổng ưu tiên bảo mật) phát huy tác dụng. Thay vì quản lý năm công cụ khác nhau, chúng ta sử dụng một web server duy nhất đã được tăng cường bảo mật (hardened) với các tính năng này tích hợp sẵn trong logic cốt lõi. BunkerWeb kế thừa Nginx và bao bọc nó bằng một lớp quản lý giúp tự động hóa những phần cấu hình bảo mật tẻ nhạt.
Tại sao chọn BunkerWeb? Ưu và nhược điểm từ thực tế
Tôi đã dành nhiều năm cấu hình các WAF (Web Application Firewall) truyền thống, và mặc dù chúng có khả năng tùy biến cao, nhưng lộ trình học tập rất dốc. BunkerWeb nằm ở một điểm giao thoa hoàn hảo giữa “bảo mật chỉ với một nút bấm” và “toàn quyền kiểm soát”.
Ưu điểm
- Hardening tự động: Áp dụng các cấu hình mặc định hợp lý cho Nginx security headers (HSTS, CSP, X-Frame-Options) ngay khi xuất xưởng.
- Tích hợp Docker nguyên bản: Có thể tự động phát hiện các container khác và cấu hình routing/protection dựa trên Docker labels.
- Cấu hình hợp nhất: Các quy tắc WAF, ngưỡng Fail2Ban và thiết lập Let’s Encrypt đều được xử lý qua biến môi trường (environment variables).
- WAF hiện đại: Kết hợp giữa phát hiện dựa trên chữ ký (signature-based – ModSecurity/Core Rule Set) và phân tích hành vi.
Nhược điểm
- Tiêu tốn tài nguyên: Vì chạy nhiều tiến trình nền (như database cục bộ để lưu trạng thái và logic dựa trên Python), nó tiêu thụ nhiều RAM hơn một image Nginx thuần túy.
- Sự trừu tượng hóa: Việc xử lý sự cố đôi khi có thể phức tạp vì bạn đang tương tác với lớp BunkerWeb thay vì trực tiếp chỉnh sửa các file cấu hình Nginx thô.
Cấu hình đề xuất của tôi: Mô hình Docker Orchestration
Có nhiều cách để triển khai BunkerWeb, nhưng tôi thấy phương pháp Docker Autoconf là dễ mở rộng nhất. Trong thiết lập này, BunkerWeb chạy như một container độc lập có quyền truy cập vào Docker socket. Khi bạn chạy một container ứng dụng mới, bạn chỉ cần thêm một vài labels, và BunkerWeb sẽ tự động tạo cấu hình reverse proxy, yêu cầu chứng chỉ SSL và kích hoạt bảo vệ WAF.
Cách tiếp cận “không sidecar” này giúp các container ứng dụng của bạn luôn tinh gọn. Ứng dụng không cần biết về SSL hay security headers; nó chỉ tập trung vào việc phục vụ mã nguồn, trong khi BunkerWeb đóng vai trò như một lá chắn kiên cố ở biên mạng của bạn.
Triển khai từng bước: Xây dựng cổng bảo mật của bạn
Tôi khuyên bạn nên bắt đầu với một thư mục riêng cho cổng bảo mật. Điều này giúp tách biệt các cấu hình cấp hạ tầng khỏi mã nguồn ứng dụng.
1. Cấu hình Docker Compose ban đầu
version: "3.8"
services:
bunkerweb:
image: bunkerze/bunkerweb:1.5.8
ports:
- "80:8080"
- "443:8443"
volumes:
- bw_data:/data
environment:
- API_WHITELIST_IP=127.0.0.1/32 172.18.0.0/16
- HTTP_PORT=8080
- HTTPS_PORT=8443
- USE_CLIENT_IP=yes
- USE_REAL_IP=yes
- REAL_IP_FROM=172.18.0.0/16
- REAL_IP_HEADER=X-Forwarded-For
bw-autoconf:
image: bunkerze/bunkerweb-autoconf:1.5.8
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
environment:
- DATABASE_URL=sqlite:////data/db.sqlite3
volumes:
- bw_data:/data
volumes:
bw_data:
Một mẹo tôi rút ra được: luôn chỉ định API_WHITELIST_IP bao gồm dải mạng Docker của bạn. Điều này cho phép dịch vụ autoconf giao tiếp với instance chính một cách bảo mật.
2. Kích hoạt các tính năng bảo mật cốt lõi
BunkerWeb đi kèm với nhiều tính năng bị tắt theo mặc định để tránh làm hỏng ứng dụng. Đối với môi trường production, tôi luôn bật WAF và bộ chặn bot xấu (bad bot blocker). Bạn có thể thêm các thông số này vào phần environment của dịch vụ bunkerweb:
environment:
# ... các biến trước đó ...
- USE_WAF=yes
- USE_ANTIBOT=yes
- USE_LIMIT_REQ=yes
- LIMIT_REQ_RATE=10r/s
- USE_GZIP=yes
- SERVER_TOKENS=off
Bằng cách đặt SERVER_TOKENS=off, bạn ngăn Nginx rò rỉ số phiên bản trong các trang báo lỗi—một bước đơn giản nhưng quan trọng để giảm thiểu bề mặt tấn công.
3. Triển khai một ứng dụng được bảo vệ
Bây giờ, hãy xem việc thêm một ứng dụng web dễ dàng như thế nào. Giả sử bạn có một ứng dụng Node.js đơn giản. Bạn không cần sửa cấu hình gateway. Thay vào đó, bạn thêm các labels vào file docker-compose.yml của ứng dụng:
services:
my-app:
image: node:alpine
# ... cấu hình ứng dụng ...
labels:
- "bunkerweb.SERVER_NAME=example.com"
- "bunkerweb.USE_LETS_ENCRYPT=yes"
- "bunkerweb.USE_REVERSE_PROXY=yes"
- "bunkerweb.REVERSE_PROXY_URL=/"
- "bunkerweb.REVERSE_PROXY_HOST=http://my-app:3000"
networks:
default:
external:
name: bunkerweb_network
BunkerWeb phát hiện các label này, kích hoạt quy trình Let’s Encrypt DNS hoặc HTTP challenge, và bắt đầu điều hướng traffic. Nếu ai đó cố gắng tấn công SQL injection vào example.com, WAF của BunkerWeb sẽ chặn nó trước khi nó kịp chạm tới container Node.js của bạn.
Sau khi triển khai: Giám sát và Bảo trì
Tự động hóa rất tuyệt vời, nhưng tin tưởng mù quáng thì rất nguy hiểm. Tôi khuyên bạn nên kiểm tra log thường xuyên để xem WAF đang chặn những gì. Bạn có thể xem log của BunkerWeb bằng lệnh:
docker compose logs -f bunkerweb
Nếu bạn thấy traffic hợp lệ bị chặn (false positive), bạn có thể tinh chỉnh các quy tắc WAF bằng biến môi trường WAF_RESOURCES hoặc bằng cách đưa các ID quy tắc cụ thể vào danh sách trắng. Theo kinh nghiệm của tôi, bộ quy tắc Core Rule Set (CRS) mặc định khá khắt khe, vì vậy bạn có thể cần tắt các quy tắc cụ thể cho các ứng dụng phức tạp như WordPress hoặc Nextcloud.
Một mẹo khác: hãy để mắt đến trạng thái Fail2Ban. BunkerWeb lưu giữ danh sách các IP bị cấm trong database nội bộ. Nếu bạn vô tình tự khóa mình, bạn sẽ cần truy cập vào container và sử dụng công cụ bwcli để gỡ lệnh cấm IP của mình. Có hơi rắc rối một chút, nhưng đó là cái giá nhỏ để đổi lấy một máy chủ không bị các bot quấy phá khi bạn đang ngủ.
Bảo mật là một quá trình liên tục. Mặc dù BunkerWeb đảm nhận phần việc nặng nhọc là WAF và SSL, bạn vẫn cần cập nhật hệ điều hành host và vá lỗi các Docker image. Nhưng với thiết lập này, ít nhất bạn đã đóng được những lỗ hổng “cửa trước” phổ biến nhất bằng một giải pháp duy nhất và dễ bảo trì.

