后端Nginx网站使用CDN、反代之后封禁用户真实IP
这篇文章说明在使用 CDN 或反向代理后,如何在 Nginx 后端正确获取用户真实 IP,并按真实 IP 进行封禁。
路径说明
- Nginx 配置目录:
/path/to/nginx/conf - 宝塔常见目录:
/www/server/nginx/conf - Nginx 主配置文件:
/path/to/nginx/conf/nginx.conf - 宝塔主配置文件:
/www/server/nginx/conf/nginx.conf - 站点配置文件(示例):
/path/to/nginx/conf/vhost/site.conf - 宝塔站点配置(示例):
/www/server/panel/vhost/nginx/site.conf
建议拆分两个文件:
waf_realip.conf:处理真实 IP 识别waf_blacklist.conf:处理黑名单封禁
两种写法与优劣
写法 A(推荐):real_ip + geo
- 优点:
- 语义清晰,和 Nginx 官方机制一致。
- 支持网段(CIDR)封禁,维护成本低。
- 对 IPv4/IPv6 都友好。
- 缺点:
- 需要先维护可信前置层 IP(
set_real_ip_from)。 - 初次配置步骤稍多。
- 需要先维护可信前置层 IP(
写法 B(可用):map 解析 X-Forwarded-For + 规则匹配
适合“先快速跑起来”的场景,示例:
map $http_x_forwarded_for $client_ip_from_xff {
default $remote_addr;
"~^\\s*(?<first>[^, ]+)" $first;
}这个写法可以兼容 IPv6(因为按逗号取第一段,不限制 :),也兼容常见 IPv4。
建议在 server 中使用 $client_ip_from_xff 做拦截变量,例如:
if ($client_ip_from_xff ~* "^8\\.8\\.8\\.") {
return 403;
}- 优点:
- 配置短,容易理解和上手。
- 能直接取
X-Forwarded-For第一跳。
- 缺点:
- 如果没限制可信来源,存在头伪造风险。
- 不适合大规模网段封禁(CIDR 维护不如
geo直观)。 - 对异常
X-Forwarded-For值需要额外防御。
推荐方案:real_ip + geo
1) 新建 waf_realip.conf
放在 http 块内加载,示例:
# 只信任你的前置层(CDN 回源 IP 或反代机器 IP)
# 以下仅示例,请改成你自己的来源 IP 段。
set_real_ip_from 127.0.0.1;
set_real_ip_from 10.0.0.0/8;
set_real_ip_from 172.16.0.0/12;
set_real_ip_from 192.168.0.0/16;
# 如果前置层透传的是 X-Forwarded-For
real_ip_header X-Forwarded-For;
real_ip_recursive on;如果你使用 Cloudflare,也可以改成:
real_ip_header CF-Connecting-IP;并把 set_real_ip_from 换成 Cloudflare 官方回源 IP 段。
可选:为了后续排错方便,可以加一个日志格式看真实来源 IP:
log_format realip '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';2) 新建 waf_blacklist.conf
同样建议在 http 块内定义变量:
geo $ip_is_blocked {
default 0;
8.8.8.0/24 1;
8.8.8.8/32 1;
8.8.4.4/32 1;
}然后在站点 server 块里拦截:
if ($ip_is_blocked) {
return 403;
}如果你还需要白名单,可再补一个白名单变量(白名单优先):
geo $ip_is_allowed {
default 0;
1.2.3.4/32 1;
10.10.0.0/16 1;
}
if ($ip_is_allowed = 0) {
if ($ip_is_blocked) {
return 403;
}
}引入方式
在 nginx.conf 的 http 段中引入:
include /path/to/nginx/conf/waf_realip.conf;
include /path/to/nginx/conf/waf_blacklist.conf;宝塔常见写法:
include /www/server/nginx/conf/waf_realip.conf;
include /www/server/nginx/conf/waf_blacklist.conf;完整示意(节选)如下:
http {
include mime.types;
default_type application/octet-stream;
include /www/server/nginx/conf/waf_realip.conf;
include /www/server/nginx/conf/waf_blacklist.conf;
server {
listen 80;
server_name example.com;
if ($ip_is_blocked) {
return 403;
}
location / {
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
}验证与重载
nginx -t
service nginx reload排错建议
- 如果封禁不生效,先看日志里
remote_addr是否已变成真实客户端 IP。 - 如果
remote_addr还是 CDN/反代 IP,说明set_real_ip_from或real_ip_header配置不对。 - 不要信任
0.0.0.0/0这类全量来源,否则可能被伪造头绕过。