Nginx不支持deny域名,因access模块仅识别IP/CIDR;须用map预处理$host变量并配合if($blocked_host) return 403实现域名黑名单,map必须置于http块或vhost顶部,且需注意phpEnv热重载限制与模块兼容性。

phpEnv 的 Nginx 配置不支持直接写 deny 域名
phpEnv 默认封装的是精简版 Nginx(常为 Tengine 或 OpenResty 衍生),其 ngx_http_access_module 仅支持基于 IP 地址或 CIDR 段的 deny,**不支持直接写域名(如 deny example.com)**。尝试这样写会导致 Nginx 启动失败,报错类似:invalid parameter "example.com"。
根本原因是:Nginx 在 access 阶段做 deny 判断时,请求尚未完成 DNS 解析(且不缓存 Host 域名匹配),deny 指令只接受预解析的 IP 形式。
真正可行的黑名单方案:用 map + return 403 拦截 Host 头
要按域名屏蔽访问,必须在 HTTP 请求头层面检查 $host 变量。推荐在 phpEnv 的站点配置文件(通常是 /phpenv/nginx/vhost/your-site.conf)中添加以下逻辑:
map $host $blocked_host {
default 0;
~*^(www\.)?bad-domain\.com$ 1;
~*evil-site\.org$ 1;
~*\.xyz$ 1; # 匹配所有 .xyz 后缀
}
<p>server {
listen 80;
server_name your-site.com;</p><pre class="brush:php;toolbar:false;">if ($blocked_host) {
return 403;
}
# 其余 location / root 等配置保持不变...}
-
map必须定义在http块(全局)或当前server块外,不能嵌套在server内;phpEnv 中建议加到 vhost 文件顶部 - 正则前加
~*表示忽略大小写;结尾的$很关键,防止bad-domain.com.hacker.net被误放行 - 避免在
if中用deny—— Nginx 官方明确不推荐在server或location中用if做访问控制,但此处仅用于简单return,是安全的
注意 phpEnv 的配置热加载限制
phpEnv 的 Nginx 不一定支持 nginx -s reload 热重载全部配置,尤其修改了 map 这类全局指令后,常见问题包括:
- 修改 vhost 后执行
phpenv restart nginx仍不生效 → 实际进程可能没真正重启,需手动killall nginx && phpenv start nginx - 多个 vhost 共享同一份
map定义时,若某一个 vhost 文件里重复定义同名map,Nginx 会启动失败并报"map" directive is duplicate - phpEnv 的日志默认不开启详细错误,如拦截无效,先检查
/phpenv/nginx/logs/error.log是否有map加载失败或正则语法错误
更严格的替代:结合 geo + map 控制多级条件
如果需要「只对特定来源 IP 段 + 特定 Host」组合拦截(比如只封海外 IP 访问某个恶意子域名),可以叠加 geo 模块:
geo $is_blocked_ip {
default 0;
192.168.3.0/24 1;
2001:db8::/32 1;
}
<p>map $host:$is_blocked_ip $final_block {
default 0;
"~<em>bad.com:1" 1;
"~</em>test.dev:1" 1;
}</p><p>server {
if ($final_block) {
return 403;
}</p><h1>...</h1><p>}</p>
这种写法把 IP 条件和域名条件拼成字符串再匹配,绕过了 if 多条件的语法限制。但要注意:geo 和 map 都必须在 http 块顶层定义,不能放在 server 里;且 phpEnv 若使用的是极简 Nginx(不含 geo 模块),该方案会直接失效 —— 建议先运行 nginx -V 2>&1 | grep -o with-http_geo_module 确认模块存在。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











