mirror of
https://github.com/NetworkCats/rustyip.git
synced 2026-11-13 16:17:46 +00:00
Each IP may now make 120 requests per minute instead of 60. Under load the limit drops to 60 RPM once the site reaches 600 RPS and to 30 RPM at 1000 RPS, instead of 30 and 15 RPM at 200 and 300 RPS. One page load makes three or four requests, and many visitors share an IP behind carrier-grade NAT or an office gateway, so the old limits throttled real users. The old global thresholds were also far below what the host can serve. Update the FAQ in every locale to match. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
68 lines
3.0 KiB
INI
68 lines
3.0 KiB
INI
global
|
|
log stderr local0 err
|
|
maxconn 4096
|
|
# TLS configuration optimized for Cloudflare-to-origin connections
|
|
ssl-default-bind-curves X25519:prime256v1:secp384r1
|
|
ssl-default-bind-ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384
|
|
ssl-default-bind-ciphersuites TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256
|
|
ssl-default-bind-options prefer-client-ciphers ssl-min-ver TLSv1.2 no-tls-tickets
|
|
|
|
defaults
|
|
log global
|
|
mode http
|
|
option httplog
|
|
option dontlog-normal
|
|
timeout connect 5s
|
|
timeout client 30s
|
|
timeout server 30s
|
|
timeout http-request 10s
|
|
timeout http-keep-alive 5s
|
|
|
|
frontend https_in
|
|
bind *:443 ssl crt /etc/haproxy/certs/origin.pem crt /etc/haproxy/certs-ipv4/origin.pem alpn h2,http/1.1 strict-sni
|
|
|
|
# Gzip compression
|
|
compression algo gzip
|
|
compression type text/html text/plain application/json text/css application/javascript
|
|
|
|
# Access to port 443 is already restricted to Cloudflare IPs at the UFW level
|
|
# Therefore, all requests reaching HAProxy come from Cloudflare; no additional ACL validation is required.
|
|
|
|
# Identify IPv4-only domain traffic by Host header
|
|
acl is_ipv4_domain hdr(host) -f /usr/local/etc/haproxy/ipv4_domain.lst
|
|
|
|
# HAProxy's own forwardfor is not enabled; real IP is set explicitly below via CF-Connecting-IP
|
|
# Main domain: standard headers
|
|
http-request set-header X-Forwarded-For %[req.hdr(CF-Connecting-IP)] if !is_ipv4_domain
|
|
http-request set-header X-Real-IP %[req.hdr(CF-Connecting-IP)] if !is_ipv4_domain
|
|
# IPv4-only domain: separate header to prevent confusion with the main domain
|
|
http-request set-header X-IPv4-Client-IP %[req.hdr(CF-Connecting-IP)] if is_ipv4_domain
|
|
http-request del-header X-Forwarded-For if is_ipv4_domain
|
|
http-request del-header X-Real-IP if is_ipv4_domain
|
|
|
|
# Rate limiting: tiered based on global request rate
|
|
# Track per-IP request rate (per minute)
|
|
stick-table type string len 45 size 100k expire 1m store http_req_rate(1m)
|
|
http-request track-sc0 req.hdr(CF-Connecting-IP)
|
|
# Track global request rate (per second)
|
|
http-request track-sc1 str(global) table global_rate_tracking
|
|
|
|
# Tier 3: global >= 1000 RPS -> limit each IP to 30 RPM
|
|
http-request deny deny_status 429 if { sc_http_req_rate(1,global_rate_tracking) ge 1000 } { sc_http_req_rate(0) gt 30 }
|
|
# Tier 2: global >= 600 RPS -> limit each IP to 60 RPM
|
|
http-request deny deny_status 429 if { sc_http_req_rate(1,global_rate_tracking) ge 600 } { sc_http_req_rate(0) gt 60 }
|
|
# Tier 1: default -> limit each IP to 120 RPM
|
|
http-request deny deny_status 429 if { sc_http_req_rate(0) gt 120 }
|
|
|
|
# Block /health from external access
|
|
acl is_health path /health
|
|
http-request deny deny_status 403 if is_health
|
|
|
|
default_backend app
|
|
|
|
backend global_rate_tracking
|
|
stick-table type string len 6 size 1 expire 10m store http_req_rate(1s)
|
|
|
|
backend app
|
|
server rustyip app:3000 check
|