Nginx location 匹配规则:正则优先于普通前缀,但让位于前缀优先修饰符

来源:互联网 时间:2026-10-31

给后台加了一条IP白名单,只允许公司出口地址访问/admin。配置写进location /admin/,nginx -t通过,reload也做了。用手机流量一打开,后台照样能进。白名单规则本身没错,是这条location根本没有被用到。

location不是按配置文件里从上到下的顺序匹配的。它先找等号开头的精确匹配,找到就停。没有精确匹配就找^~和普通前缀,取最长的那条记下来。这条前缀如果带了^~,直接采用,正则不再参与。否则按文件里的先后顺序试正则,第一个命中的直接生效,前面记下的前缀被丢掉。所有正则都不中,才回到记下的那条前缀。

站上有一条location ~ \.php$,放在文件靠前的位置。后台地址/admin/index.php先被这条正则命中,于是走了PHP处理,那条带白名单的/admin/前缀匹配从头到尾没参与。这类问题的共同点是目标路径自带扩展名,而站里又有一条按扩展名匹配的正则。静态资源也一样,location ~* \.(jpg|png|css|js)$会把/upload/admin/logo.png从上传目录的规则里抢走。

你要判断命中哪一条,最省事的办法是给每个location加一行add_header,头名统一写X-Loc,值填各自的名字。刷新页面看响应头,命中的那条会带出来。这个头只在200和304这类状态码上输出,遇到404要加always参数。站上开了缓存的话记得强制刷新,浏览器会把旧的响应头一起缓存下来。

把一个前缀匹配改成^~开头,正则就不会再抢它。^~的意思是命中这条前缀之后,直接采用,不再往下试正则。上例改成location ^~ /admin/,后台路径全部落在这一块,白名单才开始起作用。代价是/admin/下面的.php也不会走那条全局PHP正则,如果这一块还需要跑PHP,得在块内再写一条location ~ \.php$,把fastcgi参数补齐,或者用include把公共片段引进来。另一种写法是把正则改成带排除条件的形式,用location ~ ^/(?!admin/).*\.php$,可读性差很多,接手的人容易看漏。还有一处容易忽略,前缀匹配区分大小写,/Admin/不会命中/admin/,要写成~*才是忽略大小写,但那是正则的写法,别和前缀混着用。

改完用nginx -T把合并后的完整配置打出来看一遍,include进来的文件也在里面,比逐个翻文件可靠。配置文件多的时候,同一条location可能在两个文件里各写了一份,后加载的会报duplicate location,日志里有明确提示。

现在后台的规则是^~ /admin/加块内一条PHP正则,白名单和程序都能跑。同类问题在/api/上也有过一次,/api/v2/的独立规则被/api/的正则盖住,版本号一直没生效,改法一样。加规则之前先把站上已有的正则列出来,看新路径会不会被哪一条先接住。

相关文章

标签:

A5创业网 版权所有