global daemon log stdout format raw local0 info maxconn 2000 # For normalize-uri expose-experimental-directives defaults mode http log global timeout connect 5s timeout client 30s timeout server 30s timeout check 5s retries 3 option httplog option dontlognull option redispatch frontend http bind :80 mode http http-request redirect scheme https unless { ssl_fc } frontend www bind :443 ssl crt /certs/fullcert.pem # 2 general purpose tags in this stick-table (name defaults to frontend name, i.e. www) stick-table type ipv6 size 1m expire 2d store gpt(2) http-request track-sc0 src http-request normalize-uri path-merge-slashes http-request normalize-uri path-strip-dot http-request normalize-uri path-strip-dotdot # Drop the connection immediately if the requester previously requested the honeypot path) http-request silent-drop if { sc_get_gpt(0,0) gt 0 } # Protect all paths except /robots.txt, /.well-known/*, and /favicon.ico acl unprotected_path path -m reg ^/(robots.txt|\.well-known/.*|favicon\.ico|_challenge)$ # Matches the default config of anubis of triggering on "Mozilla" acl protected_ua hdr(User-Agent) -m beg Mozilla/ # Set stick table index 0 to 1 if request is for honeypot path http-request sc-set-gpt(0,0) 1 if { path -m beg /blokmeplz/ } http-request silent-drop if { path -m beg /blokmeplz/ } acl accepted sc_get_gpt(1,0) gt 0 http-request return status 200 content-type "text/html; charset=UTF-8" hdr "Cache-control" "max-age=0, no-cache" lf-file /usr/local/etc/haproxy/challenge.html if !unprotected_path protected_ua !accepted use_backend challenge if { path -m beg /_challenge } http-response set-header Strict-Transport-Security "max-age=16000000; includeSubDomains; preload;" default_backend main backend challenge mode http option http-buffer-request # The parameter to table must match the stick table used in the frontend. http-request track-sc0 src table www acl challenge_req method POST http-request set-var(txn.tries) req.body_param(tries) http-request set-var(txn.ts) req.body_param(ts) http-request set-var(txn.host) hdr(Host),host_only http-request set-var(txn.hash) src,concat(;,txn.host,),concat(;,txn.ts,),concat(;,txn.tries),sha2,hex acl ts_recent date,neg,add(txn.ts) ge -60 # 4 is the difficulty, should match "diff" in challenge.html. acl hash_good var(txn.hash) -m reg 0{4}.* http-request sc-set-gpt(1,0) 1 if challenge_req ts_recent hash_good http-request return status 200 if challenge_req hash_good http-request return status 400 content-type "text/html; charset=UTF-8" hdr "Cache-control" "max-age=0" string "Bad request" if !challenge_req OR !hash_good backend main mode http balance leastconn option httpchk GET /health http-check expect status 200 server badblocks-personal-site badblocks-personal-site:4321 check resolvers docker resolve-prefer ipv4 init-addr none resolvers docker nameserver dns1 127.0.0.11:53 resolve_retries 3 timeout resolve 1s timeout retry 1s hold valid 10s hold obsolete 30s