我需要重定向到一个 URL,除非用户来自我们的内部 IP 地址或者如果他们正在访问特定路径。
我尝试过这个:
location ~* /foobar {
break;
}
location ~* / {
if ($remote_addr != 111.222.333.444) {
rewrite ^ https://external.tld/
}
}
但这似乎不起作用。这个特定的配置导致在访问https://mydomain.tld/foobar以及“欢迎使用 nginx!”页面。但是,访问https://mydomain.tld/foobar我们的 IP 地址之外确实正确重定向到https://external.tld/
答案1
由于您不想(或不允许)显示完整的服务器块,我会进行一些猜测。您的配置最有可能发生了什么?您创建了两个额外的位置块,用于处理任何传入请求。检查location
指令文档。唯一可以超越正则表达式匹配位置请求的位置类型是精确位置 ( location = /uri { ... }
) 和不检查正则表达式前缀位置 ( location ^~ /prefix { ... }
)。否则,将选择第一个正则表达式匹配的位置。
每个服务器块都有其根目录,即使没有使用指令明确指定root
。它是使用字首(在编译时间,可以使用nginx -V
命令检查)和/html
后缀。假设您的 nginx 前缀是/usr/share/nginx
。那么您的默认根目录将位于/usr/share/nginx/html
目录,除非使用指令明确指定root /some/path
。
服务请求时的默认 nginx 行为可以描述为try_files $uri $uri/ =404
。
假设我们有一个https://mydomain.tld/foobar
请求。为了处理它,您的 firstlocation ~* /foobar { break; }
将被选为第一个匹配的正则表达式位置。第一个指令break
意味着处理当前的ngx_http_rewrite_module
指令将被停止。但是这个 location 块中没有任何这些指令(除了一个break
)!是的,这意味着这个break
指令在这里是无用的。接下来,nginx 将检查文件是否存在/usr/share/nginx/html/foobar
,即目录中的索引文件/usr/share/nginx/html/foobar/
(默认为index.html
),如果两个检查都失败,则返回HTTP 404 Not Found
错误。
现在假设我们有一个https://mydomain.tld/
请求。您的第一个位置块不会匹配它,因此location ~* / { ... }
选择第二个位置块来处理此请求(此位置块将匹配任何可能的有效请求)。如果 IP 地址检查未通过,则将进行重定向。但如果通过,nginx 将以与上述相同的方式处理您的请求,index.html
从目录返回您的默认欢迎文件/usr/share/nginx/html/
。
看起来你不明白ngx_http_rewrite_module
已处理。请再次阅读文档的第一部分:
、、、和
break
指令按以下顺序处理:if
return
rewrite
set
- 该模块在服务器级别指定的指令将按顺序执行;
- 反复:
- 根据请求 URI 搜索位置;
- 按顺序执行在找到的位置内指定的该模块的指令;
- 如果请求 URI 被重写,则重复循环,但不会超过 10 次。
您可以在服务器块级别进行检查:
if ($uri = /foobar) {
break;
}
if ($remote_addr != 111.222.333.444) {
rewrite ^ https://external.tld/
}
上述break
指令将按预期工作,服务器级别的指令执行ngx_http_rewrite_module
将停止。这意味着该模块的任何其他指令(如、、set
等)(如果有)都应放置在if
return
rewrite
前上面的块。这不适用于ngx_http_rewrite_module
放置在位置级别的指令。
还有一个可能的警告。如果您的https://mydomain.tld/foobar
页面使用任何资产(脚本、样式、图像等),也应允许访问这些资产。例如,您可以使用块更改条件以允许以/foobar
前缀开头的任何内容if ($uri ~* ^/foobar) { break; }
。如果无法使用单个正则表达式检查它们的地址,则可以使用多个if (...) { break; }
块。