Reputation: 5118
I have been trying to do rate limiting in some api endpoints that I am hitting asynchronously, requests return 200 ok as expected before rate limiting, but when the limit is reached instead of returning a 429 error my api endpoints come back with CORS Error in the browser, I read here that it might be due to some headers, but I tried that and still I get the same cors error.
Sharing my humble nginx config below, in this example I would like to get a 429 when rate limit is reached for endpoint api.domain.com/custom/url
http {
limit_req_zone $binary_remote_addr zone=mylimit:10m rate=5r/m;
server {
listen 80;
server_name domain.com api.domain.com;
location .../my-acme-challenge/ {
root .../my-certbot;
}
location / {
return 301 https://$server_name$request_uri;
}
}
server {
listen 443 ssl;
server_name api.domain.com;
.../mychain.pem;
.../myprivkey.pem;
include .../my-options-ssl-nginx.conf;
ssl_dhparam .../my-ssl-dhparams.pem;
Relevant Piece !!!!!!
location /custom/url {
add_header Access-Control-Allow-Credentials 'true' always;
add_header Access-Control-Allow-Origin '*' always;
limit_req zone=mylimit burst=5 nodelay;
limit_req_log_level error;
limit_req_status 429;
proxy_pass http://myip:myport/custom/url;
}
location / {
proxy_pass http://myip:myport;
}
}
...
}
Any idea of what might be going on? Tried to simplify my config here as much as I could.
My nginx logs:
[error] 9#9: *51 limiting requests, excess: 5.697 by zone "mylimit", client: myip, server: api.example.com, request: "OPTIONS /custom/url HTTP/1.1", host: "api.example.com", referrer: "https://example.com/"
myip - - [23/Nov/2021:01:10:32 +0000] "OPTIONS /custom/url HTTP/1.1" 429 571 "https://example.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.45 Safari/537.36"
Update:
Curiously enough, when I copy the curl request from the network (right click > Copy > Copy as curl) I get this html page which appears to be an 429, but instead I should be getting this error in the browser when I hit with an async request not in curl.
Upvotes: 4
Views: 1665
Reputation: 5118
Answering in case someone else goes through the same situation, the problem was actually a composition of multiple things:
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Allow-Origin' 'https://example.com' always;
add_header 'Access-Control-Allow-Credentials' 'true' always;
add_header 'Access-Control-Allow-Methods' 'GET, HEAD, OPTIONS, POST, PUT, DELETE' always;
add_header 'Access-Control-Allow-Headers' 'Origin, X-Requested-With, contentType, Content-Type, Accept, Authorization, Pragma' always;
add_header 'Access-Control-Max-Age' 1728000;
add_header 'Content-Type' 'text/plain charset=UTF-8';
add_header 'Content-Length' 0;
return 204;
}
server {}
level (notice the always
keyword, this is pivotal for adding the headers to error responses) i.e: add_header 'Access-Control-Allow-Origin' 'https://example.com' always;
add_header 'Access-Control-Allow-Credentials' 'true' always;
add_header 'Access-Control-Allow-Methods' 'GET, HEAD, OPTIONS, POST, PUT, DELETE' always;
add_header 'Access-Control-Allow-Headers' 'Origin, X-Requested-With, contentType, Content-Type, Accept, Authorization, Pragma' always;
Upvotes: 2
Reputation: 9072
Adding your headers outside of the location
block should ensure they are included in the rate limiting response too.
server {
add_header Access-Control-Allow-Origin * always;
location / {
add_header Access-Control-Allow-Origin * always;
...
}
...
}
Upvotes: 0