global daemon maxconn 256 log stdout format raw local0 debug lua-load /etc/haproxy/scripts/register.lua stats socket /var/run/haproxy.sock mode 666 level admin stats socket *:2000 level admin defaults mode http timeout connect 5000ms timeout client 50000ms timeout server 50000ms program api command dataplaneapi -f /etc/haproxy/dataplaneapi.hcl --update-map-files no option start-on-reload frontend http-in bind *:80 acl is_existing_vhost hdr(host),lower,map_str(/etc/haproxy/hosts.map) -m found http-request silent-drop unless is_existing_vhost #debug only, /cdn-cgi/trace #http-request return status 200 content-type "text/plain; charset=utf-8" lf-file /etc/haproxy/trace.txt if { path /cdn-cgi/trace } # acl for blocked IPs/subnets acl blocked_ip_or_subnet src,map_ip(/etc/haproxy/blocked.map) -m found http-request deny deny_status 403 if blocked_ip_or_subnet # acl ORs for when ddos_mode_enabled acl ddos_mode_enabled_override hdr_cnt(xr3la1rfFc) eq 0 # note: global only enables POW not captcha atm until acl ddos_mode_enabled hdr(host),lower,map(/etc/haproxy/ddos.map) -m bool acl ddos_mode_enabled base,map(/etc/haproxy/ddos.map) -m bool # create acl for bools updated by lua acl captcha_passed var(txn.captcha_passed) -m bool acl pow_passed var(txn.pow_passed) -m bool acl validate_captcha var(txn.validate_captcha) -m bool acl validate_pow var(txn.validate_pow) -m bool # define excluded paths, and serve script files directly in haproxy acl is_excluded path /favicon.ico acl is_sha1_js path /js/sha1.js acl is_worker_js path /js/worker.js http-request return file /var/www/js/sha1.js status 200 content-type "application/javascript; charset=utf-8" hdr "cache-control" "public, max-age=300" if is_sha1_js http-request return file /var/www/js/worker.js status 200 content-type "application/javascript; charset=utf-8" hdr "cache-control" "public, max-age=300" if is_worker_js # check pow/captcha and show page if necessary acl on_captcha_url path /bot-check http-request use-service lua.hcaptcha-view if on_captcha_url !is_excluded http-request lua.decide-checks-necessary if !is_excluded !on_captcha_url ddos_mode_enabled #OR !is_excluded !on_captcha_url ddos_mode_enabled_override http-request lua.hcaptcha-check if !is_excluded !on_captcha_url validate_captcha #OR !is_excluded !on_captcha_url ddos_mode_enabled_override http-request lua.pow-check if !is_excluded !on_captcha_url validate_pow OR !is_excluded !on_captcha_url ddos_mode_enabled_override http-request redirect location /bot-check?%[capture.req.uri] code 302 if validate_captcha !captcha_passed !on_captcha_url ddos_mode_enabled !is_excluded OR validate_pow !pow_passed !on_captcha_url ddos_mode_enabled !is_excluded OR !pow_passed ddos_mode_enabled_override !on_captcha_url !is_excluded ##### X-Cache-Status header (may be sent in some non-cache responses because NOSRV can happen for other reasons, but should always be present in responses served by cache-use) http-response set-header X-Cache-Status HIT if !{ srv_id -m found } http-response set-header X-Cache-Status MISS if { srv_id -m found } default_backend servers cache basic_cache total-max-size 2500 max-object-size 31457280 max-age 86400 backend servers # simple example cache for files http-request set-var(txn.path) path acl can_cache var(txn.path) -i -m end .png .jpg .jpeg .jpe .ico .webmanifest .xml .apng .bmp .webp .pjpeg .jfif .gif .mp4 .webm .mov .mkv .svg .m4a .aac .flac .mp3 .ogg .wav .opus .txt .pdf .sid http-request cache-use basic_cache if can_cache http-response cache-store basic_cache if can_cache # placeholder servers, activated by LUA or the control panel server-template websrv 1-100 0.0.0.0:80 check disabled ssl verify none # use server based on hostname use-server %[req.hdr(host),lower,map(/etc/haproxy/backends.map)] if TRUE backend hcaptcha mode http server hcaptcha hcaptcha.com:443