From dfdfda0e81fd74766671a79664ced7dcef81c4b6 Mon Sep 17 00:00:00 2001 From: NetworkCats Date: Wed, 11 Mar 2026 04:33:47 +0800 Subject: [PATCH] feat: add HAProxy dual-domain routing with separate IPv4 headers --- docker-compose.yml | 1 + haproxy/haproxy.cfg | 16 +++++++++++----- haproxy/ipv4_domain.lst | 2 ++ 3 files changed, 14 insertions(+), 5 deletions(-) create mode 100644 haproxy/ipv4_domain.lst diff --git a/docker-compose.yml b/docker-compose.yml index 35e7ea4..e189265 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -5,6 +5,7 @@ services: - "443:443" volumes: - ./haproxy/haproxy.cfg:/usr/local/etc/haproxy/haproxy.cfg:ro + - ./haproxy/ipv4_domain.lst:/usr/local/etc/haproxy/ipv4_domain.lst:ro - ${CERT_PATH:-./haproxy/certs}:/etc/haproxy/certs:ro - ${IPV4_CERT_PATH:-./haproxy/certs-ipv4}:/etc/haproxy/certs-ipv4:ro depends_on: diff --git a/haproxy/haproxy.cfg b/haproxy/haproxy.cfg index e05c057..d894004 100644 --- a/haproxy/haproxy.cfg +++ b/haproxy/haproxy.cfg @@ -19,7 +19,7 @@ defaults timeout http-keep-alive 5s frontend https_in - bind *:443 ssl crt /etc/haproxy/certs/origin.pem alpn h2,http/1.1 strict-sni + 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 @@ -28,11 +28,17 @@ frontend https_in # 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. - # HAProxy's own forwardfor is not enabled; real IP is set explicitly below via CF-Connecting-IP + # Identify IPv4-only domain traffic by Host header + acl is_ipv4_domain hdr(host) -f /usr/local/etc/haproxy/ipv4_domain.lst - # Overwrite standard headers directly with the real IP forcibly added by Cloudflare - http-request set-header X-Forwarded-For %[req.hdr(CF-Connecting-IP)] - http-request set-header X-Real-IP %[req.hdr(CF-Connecting-IP)] + # 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) diff --git a/haproxy/ipv4_domain.lst b/haproxy/ipv4_domain.lst new file mode 100644 index 0000000..01305c4 --- /dev/null +++ b/haproxy/ipv4_domain.lst @@ -0,0 +1,2 @@ +# IPv4-only domain name for dual-stack detection +# Add the domain (e.g., noipv6.org) on a new line below