From b8c277cba6175172931834c77f9c4f3968200e4a Mon Sep 17 00:00:00 2001 From: Ronak Kamboj Date: Thu, 26 Mar 2026 19:07:30 +0530 Subject: [PATCH 1/4] feat(nginx): implement rate limiting for both dev and prod setup --- nginx/nginx.dev.conf | 8 ++++++++ nginx/nginx.prod.conf | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/nginx/nginx.dev.conf b/nginx/nginx.dev.conf index fe6ec7b..ec7ee8c 100644 --- a/nginx/nginx.dev.conf +++ b/nginx/nginx.dev.conf @@ -1,3 +1,7 @@ +# --- RATE LIMIT ZONE (Dev Environment) --- +limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s; +limit_req_status 429; +limit_req_log_level warn; server { listen 80; @@ -6,11 +10,15 @@ server { # --- API proxy --- location = /banners { + limit_req zone=api_limit burst=10 nodelay; + proxy_pass http://api; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } location ^~ /banners/preview { + limit_req zone=api_limit burst=10 nodelay; + proxy_pass http://api; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; diff --git a/nginx/nginx.prod.conf b/nginx/nginx.prod.conf index 14a2bed..ad56ec2 100644 --- a/nginx/nginx.prod.conf +++ b/nginx/nginx.prod.conf @@ -1,3 +1,35 @@ +# --- CLOUDFLARE REAL IP SETUP --- +set_real_ip_from 173.245.48.0/20; +set_real_ip_from 103.21.244.0/22; +set_real_ip_from 103.22.200.0/22; +set_real_ip_from 103.31.4.0/22; +set_real_ip_from 141.101.64.0/18; +set_real_ip_from 108.162.192.0/18; +set_real_ip_from 190.93.240.0/20; +set_real_ip_from 188.114.96.0/20; +set_real_ip_from 197.234.240.0/22; +set_real_ip_from 198.41.128.0/17; +set_real_ip_from 162.158.0.0/15; +set_real_ip_from 104.16.0.0/13; +set_real_ip_from 104.24.0.0/14; +set_real_ip_from 172.64.0.0/13; +set_real_ip_from 131.0.72.0/22; +set_real_ip_from 2400:cb00::/32; +set_real_ip_from 2606:4700::/32; +set_real_ip_from 2803:f800::/32; +set_real_ip_from 2405:b500::/32; +set_real_ip_from 2405:8100::/32; +set_real_ip_from 2a06:98c0::/29; +set_real_ip_from 2c0f:f248::/32; + +# Set the header to the real client IP provided by Cloudflare +real_ip_header CF-Connecting-IP; + +# --- API rate limiting --- +limit_req_zone $http_cf_connecting_ip zone=api:10m rate=10r/s; +limit_req_status 429; +limit_req_log_level ; + # --- HTTPS thorugh Cloudflare Origin Certificate --- server { listen 443 ssl; @@ -10,11 +42,15 @@ server { # --- API proxy --- location = /banners { + limit_req zone=api burst=10 nodelay; + proxy_pass http://api; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } location ^~ /banners/preview { + limit_req zone=api burst=10 nodelay; + proxy_pass http://api; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; From 65a35eb36ba8530711b6fbbcc72064eb42b41358 Mon Sep 17 00:00:00 2001 From: Ronak Kamboj Date: Thu, 26 Mar 2026 19:48:21 +0530 Subject: [PATCH 2/4] refactor(dev): removed rate limiting --- nginx/nginx.dev.conf | 8 -------- 1 file changed, 8 deletions(-) diff --git a/nginx/nginx.dev.conf b/nginx/nginx.dev.conf index ec7ee8c..fe6ec7b 100644 --- a/nginx/nginx.dev.conf +++ b/nginx/nginx.dev.conf @@ -1,7 +1,3 @@ -# --- RATE LIMIT ZONE (Dev Environment) --- -limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s; -limit_req_status 429; -limit_req_log_level warn; server { listen 80; @@ -10,15 +6,11 @@ server { # --- API proxy --- location = /banners { - limit_req zone=api_limit burst=10 nodelay; - proxy_pass http://api; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } location ^~ /banners/preview { - limit_req zone=api_limit burst=10 nodelay; - proxy_pass http://api; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; From b5d4453ddfa9b5b7b3aefd3bc52450c17e459c02 Mon Sep 17 00:00:00 2001 From: Ronak Kamboj Date: Thu, 26 Mar 2026 19:48:38 +0530 Subject: [PATCH 3/4] refactor(production): improvised on the rate limiting more explained in the pr message --- nginx/nginx.prod.conf | 35 +++++++++++++++++++++++++++++++---- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/nginx/nginx.prod.conf b/nginx/nginx.prod.conf index ad56ec2..994b375 100644 --- a/nginx/nginx.prod.conf +++ b/nginx/nginx.prod.conf @@ -26,9 +26,23 @@ set_real_ip_from 2c0f:f248::/32; real_ip_header CF-Connecting-IP; # --- API rate limiting --- -limit_req_zone $http_cf_connecting_ip zone=api:10m rate=10r/s; +#limit how many simultaneous connections a single IP can hold open +limit_conn_zone $binary_remote_addr zone=limit_conn_per_ip:10m; + +limit_req_zone $binary_remote_addr zone=create_limit:10m rate=5r/m; +limit_req_zone $binary_remote_addr zone=preview_limit:10m rate=20r/m; +limit_req_zone $binary_remote_addr zone=api:10m rate=100r/m; + limit_req_status 429; -limit_req_log_level ; +limit_conn_status 429; +limit_req_log_level warn; + +#Auto blocking known scraping tools +map $http_user_agent $bad_bot { + default 0; + "" 1; + ~*(wget|curl|scrapy|python-requests|postman|insomnia) 1; +} # --- HTTPS thorugh Cloudflare Origin Certificate --- server { @@ -40,16 +54,29 @@ server { root /var/www/; + client_body_timeout 10s; + client_header_timeout 10s; + keepalive_timeout 15s; + send_timeout 10s; + # --- API proxy --- location = /banners { - limit_req zone=api burst=10 nodelay; + if ($bad_bot) { + return 403; #Forbidden + } + limit_conn limit_conn_per_ip 5; + limit_req zone=create_limit burst=3 nodelay; proxy_pass http://api; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } location ^~ /banners/preview { - limit_req zone=api burst=10 nodelay; + if ($bad_bot){ + return 403; #Forbidden + } + limit_conn limit_conn_per_ip 10; + limit_req zone=preview_limit burst=10 nodelay; proxy_pass http://api; proxy_set_header Host $host; From 64004081bde7fc5987e85b6803e8f3e1bfafd774 Mon Sep 17 00:00:00 2001 From: Ronak Kamboj Date: Thu, 26 Mar 2026 21:05:03 +0530 Subject: [PATCH 4/4] refactor(production): added hourly limit and allowed only the cloudflare ips --- nginx/nginx.prod.conf | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/nginx/nginx.prod.conf b/nginx/nginx.prod.conf index 994b375..7351a28 100644 --- a/nginx/nginx.prod.conf +++ b/nginx/nginx.prod.conf @@ -32,6 +32,8 @@ limit_conn_zone $binary_remote_addr zone=limit_conn_per_ip:10m; limit_req_zone $binary_remote_addr zone=create_limit:10m rate=5r/m; limit_req_zone $binary_remote_addr zone=preview_limit:10m rate=20r/m; limit_req_zone $binary_remote_addr zone=api:10m rate=100r/m; +limit_req_zone $binary_remote_addr zone=create_hourly:10m rate=50r/h; +limit_req_zone $binary_remote_addr zone=preview_hourly:10m rate=200r/h; limit_req_status 429; limit_conn_status 429; @@ -53,6 +55,29 @@ server { ssl_certificate_key /etc/nginx/ssl/key.pem; root /var/www/; + allow 173.245.48.0/20; + allow 103.21.244.0/22; + allow 103.22.200.0/22; + allow 103.31.4.0/22; + allow 141.101.64.0/18; + allow 108.162.192.0/18; + allow 190.93.240.0/20; + allow 188.114.96.0/20; + allow 197.234.240.0/22; + allow 198.41.128.0/17; + allow 162.158.0.0/15; + allow 104.16.0.0/13; + allow 104.24.0.0/14; + allow 172.64.0.0/13; + allow 131.0.72.0/22; + allow 2400:cb00::/32; + allow 2606:4700::/32; + allow 2803:f800::/32; + allow 2405:b500::/32; + allow 2405:8100::/32; + allow 2a06:98c0::/29; + allow 2c0f:f248::/32; + deny all; #if ip is not from the above list then they will get 403 client_body_timeout 10s; client_header_timeout 10s; @@ -66,6 +91,7 @@ server { } limit_conn limit_conn_per_ip 5; limit_req zone=create_limit burst=3 nodelay; + limit_req zone=create_hourly burst=50 nodelay; proxy_pass http://api; proxy_set_header Host $host; @@ -77,6 +103,7 @@ server { } limit_conn limit_conn_per_ip 10; limit_req zone=preview_limit burst=10 nodelay; + limit_req zone=preview_hourly burst=200 nodelay; proxy_pass http://api; proxy_set_header Host $host;