Nginx全局IP限流排除特定路径配置问题求助
Ah, I see the issue here! The problem isn't with your /api/v1/ex/au/ and /api/v2/ex/au/ locations directly—those don't have limit_req rules applied. But when requests to those paths hit try_files, they get forwarded to /index.php, which matches your ~ \.php$ location. That location does have the rate limiting rules, so your excluded paths are still being throttled because the PHP handler is enforcing the limit.
Let's fix this with two clean solutions, depending on your Nginx version:
Solution 1: Use limit_req's if condition (cleanest, requires Nginx 1.17.6+)
We'll set a flag for excluded paths, then only apply rate limiting when the flag isn't set. This is the most straightforward approach if your Nginx version supports it.
Update your config like this:
geo $whitelist { default 0; include /etc/nginx/whitelisted_ips.txt; } map $whitelist $limitmap { 0 $binary_remote_addr; 1 ""; } limit_req_zone $limitmap zone=myratelimit:50m rate=10r/s; server { listen 443 ssl http2; ... # Initialize a flag to track if we should skip rate limiting set $skip_rate_limit 0; # Mark our excluded paths to skip rate limiting location ~ /api/v1/ex/au/ { set $skip_rate_limit 1; try_files $uri $uri/ /index.php$is_args$args; } location ~ /api/v2/ex/au/ { set $skip_rate_limit 1; try_files $uri $uri/ /index.php$is_args$args; } location / { # Only apply rate limiting if we're NOT skipping it limit_req zone=myratelimit burst=10 nodelay if=!$skip_rate_limit; limit_req_status 429; try_files $uri $uri/ /index.php$is_args$args; } location ~ \.php$ { # Same logic: skip rate limiting for excluded paths limit_req zone=myratelimit burst=10 nodelay if=!$skip_rate_limit; limit_req_status 429; try_files $uri $uri/ /index.php; fastcgi_pass unix:/run/php-fpm/www.sock; ... } }
The if=!$skip_rate_limit parameter tells limit_req to only enforce the rule when $skip_rate_limit is 0 (i.e., not an excluded path). When requests hit your /api/... locations, we set $skip_rate_limit to 1, so even when they forward to index.php, the PHP location skips rate limiting.
Solution 2: Update the $limitmap to exclude path-specific requests (compatible with older Nginx)
If you're running an older Nginx version (pre-1.17.6) that doesn't support the if parameter for limit_req, we can adjust the $limitmap variable to ignore excluded paths entirely.
# First, define which paths to exclude from rate limiting map $request_uri $skip_rate_limit { default 0; # Match the two excluded paths and all their subpaths ~^/api/v1/ex/au/ 1; ~^/api/v2/ex/au/ 1; } geo $whitelist { default 0; include /etc/nginx/whitelisted_ips.txt; } # Combine whitelist and skip flag: if either is true, $limitmap is empty (no limiting) map $whitelist$skip_rate_limit $limitmap { ~1 ""; # Matches any value where whitelist OR skip_rate_limit is 1 default $binary_remote_addr; } limit_req_zone $limitmap zone=myratelimit:50m rate=10r/s; server { listen 443 ssl http2; ... location ~ /api/v1/ex/au/ { try_files $uri $uri/ /index.php$is_args$args; } location ~ /api/v2/ex/au/ { try_files $uri $uri/ /index.php$is_args$args; } location / { limit_req zone=myratelimit burst=10 nodelay; limit_req_status 429; try_files $uri $uri/ /index.php$is_args$args; } location ~ \.php$ { limit_req zone=myratelimit burst=10 nodelay; limit_req_status 429; try_files $uri $uri/ /index.php; fastcgi_pass unix:/run/php-fpm/www.sock; ... } }
Here, we use a map to check if the request URI is in our excluded list. Then we combine that with the $whitelist variable: if either the IP is whitelisted or the path is excluded, $limitmap becomes an empty string. Since limit_req_zone uses $limitmap, an empty value means no rate limiting is applied—even when the request forwards to PHP.
How to verify the fix
- Reload Nginx to apply the config:
sudo nginx -s reload - Use
siegeagain to hit/api/v1/ex/au/—you should no longer get 429 errors. - Test a non-excluded path (like
/) to confirm rate limiting still works (you should get 429s when exceeding the 10r/s limit).
内容的提问来源于stack exchange,提问作者catalin

