TL;DR: Cách khắc phục nhanh
Nếu log của bạn tràn ngập IP proxy, bạn cần module ngx_http_realip_module. Thêm các dòng sau vào tệp cấu hình Nginx—thường là bên trong block http hoặc server—để chỉ định cho Nginx những nguồn nào cần tin tưởng:
# Tin tưởng các dải IP của Cloudflare
set_real_ip_from 103.21.244.0/22;
set_real_ip_from 103.22.200.0/22;
# ... thêm các dải IP khác nếu cần ...
# Xác định header chứa IP thực
real_ip_header CF-Connecting-IP;
real_ip_recursive on;
Áp dụng các thay đổi bằng lệnh sudo nginx -s reload.
Tại sao điều này lại xảy ra?
Khi bạn đặt Nginx đứng sau một dịch vụ như Cloudflare hoặc AWS Load Balancer, kết nối TCP trực tiếp sẽ đến từ IP của proxy. Theo mặc định, Nginx ghi nhận "người hàng xóm" trực tiếp này là client. Điều này khiến log của bạn hiển thị các địa chỉ 172.x.x.x hoặc 10.x.x.x thay vì IP của người thực sự đang truy cập trang web.
Các proxy thường chuyển tiếp IP gốc thông qua một HTTP header đặc biệt. Các header phổ biến bao gồm X-Forwarded-For hoặc CF-Connecting-IP. Nhiệm vụ của bạn là yêu cầu Nginx bỏ qua IP của proxy và sử dụng giá trị từ các header đó để thay thế.
Cấu hình từng bước
1. Kiểm tra hỗ trợ Module
Hầu hết các bản build Nginx hiện đại đều bao gồm module real_ip sẵn có. Bạn có thể kiểm tra bằng lệnh sau:
nginx -V 2>&1 | grep --color 'with-http_realip_module'
Nếu kết quả làm nổi bật --with-http_realip_module, bạn đã sẵn sàng. Nếu không, bạn có thể cần cài đặt gói nginx-extras hoặc biên dịch lại từ nguồn.
2. Danh sách trắng (Whitelist) các Proxy tin cậy
Vấn đề bảo mật rất quan trọng ở đây. Bạn chỉ nên tin tưởng IP header từ các nguồn mà bạn thực sự kiểm soát hoặc sử dụng. Việc tạo danh sách trắng giúp ngăn chặn "IP spoofing" (giả mạo IP), nơi người dùng độc hại gửi một header giả để che giấu danh tính.
Trường hợp A: Làm việc với Cloudflare
Cloudflare sử dụng các dải IP cụ thể. Hãy tạo một tệp cấu hình riêng tại /etc/nginx/conf.d/cloudflare.conf để giữ cấu hình gọn gàng:
# Dải IP IPv4 của Cloudflare (Danh sách rút gọn làm ví dụ)
set_real_ip_from 173.245.48.0/20;
set_real_ip_from 103.21.244.0/22;
set_real_ip_from 141.101.64.0/18;
set_real_ip_from 108.162.192.0/18;
set_real_ip_from 190.93.240.0/20;
set_real_ip_from 188.114.96.0/20;
set_real_ip_from 162.158.0.0/15;
set_real_ip_from 104.16.0.0/13;
# Dải IP IPv6 của Cloudflare
set_real_ip_from 2400:cb00::/32;
set_real_ip_from 2606:4700::/32;
# Cloudflare luôn gửi IP thực trong header này
real_ip_header CF-Connecting-IP;
Trường hợp B: Đứng sau AWS ALB hoặc HAProxy
Nếu bạn đang sử dụng Load Balancer nội bộ, hãy sử dụng dải CIDR của VPC (ví dụ: 172.31.0.0/16) hoặc IP riêng cụ thể của bộ cân bằng tải:
set_real_ip_from 172.31.0.0/16; # Ví dụ dải IP VPC của AWS
set_real_ip_from 10.0.0.0/8; # Mạng nội bộ
real_ip_header X-Forwarded-For;
real_ip_recursive on;
Mẹo nhỏ: Luôn sử dụng real_ip_recursive on; nếu bạn có nhiều lớp proxy, chẳng hạn như Cloudflare truyền qua AWS ALB rồi mới đến Nginx. Điều này yêu cầu Nginx kiểm tra toàn bộ danh sách IP trong header và chọn IP cuối cùng không nằm trong danh sách tin cậy của bạn.
3. Điều chỉnh định dạng Log
Khi real_ip được kích hoạt, biến tiêu chuẩn $remote_addr sẽ tự động cập nhật. Nếu bạn sử dụng định dạng log tùy chỉnh, hãy đảm bảo nó tham chiếu đến $remote_addr. Một thiết lập điển hình trong nginx.conf sẽ như sau:
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent"';
Cách xác minh kết quả
Kiểm tra Access Log
Mở terminal và theo dõi log của bạn trong thời gian thực:
tail -f /var/log/nginx/access.log
Truy cập trang web từ điện thoại hoặc VPN. Bây giờ bạn sẽ thấy IP công cộng thực tế của mình (ví dụ: 1.2.3.4) thay vì địa chỉ nội bộ 10.x.x.x.
Phương pháp dùng Script
Đặt một tệp info.php đơn giản vào thư mục web để xem Nginx đang truyền gì cho ứng dụng của bạn:
<?php
echo "IP thực: " . $_SERVER['REMOTE_ADDR'];
?>
Các lỗi thường gặp cần tránh
- **Tin tưởng toàn bộ internet:** Đừng bao giờ sử dụng `set_real_ip_from 0.0.0.0/0;`. Làm như vậy sẽ cho phép bất kỳ ai cũng có thể giả mạo IP của họ chỉ bằng cách thêm header `X-Forwarded-For` vào yêu cầu.
- **Quên IPv6:** Nếu khách truy cập sử dụng IPv6 nhưng bạn chỉ liệt kê dải IPv4 vào danh sách trắng, log sẽ hiển thị lại IP proxy đối với những người dùng đó.
- **Danh sách IP cũ:** Cloudflare cập nhật các dải IP của họ vài tháng một lần. Hãy cân nhắc sử dụng một script để tự động lấy danh sách IP mới nhất từ `https://www.cloudflare.com/ips-v4`.

