HAProxy – How to Process /.well-known Before Any Redirects

haproxy

I want to create a haproxy configuration that listens on port 80 and:

  1. use_backend when the path starts with /.well-known/acme-challenge, regardless of domain

  2. redirect http to https for other paths for several domains, e.g. a.test to https://a.test

I tried this configuration:

use_backend certbot_80 if { path -m reg ^/.well-known/acme-challenge/ } 
redirect prefix https://a.test if { hdr_reg(host) '^a\.test(?::.*)?$' }

But it doesn't work because haproxy processes redirect before use_backend.

This works:

acl certbot path -m reg ^/.well-known/acme-challenge/
redirect prefix https://a.test if ! certbot { hdr_reg(host)  '^a\.test(?::.*)?$' }
use_backend certbot_80 if certbot

But I have to specifically exclude the certbot condition in each redirect. And if I have more paths that I want to handle first, I'd have to exclude all of them in each redirect.

Is there a way to do it while keeping each condition separate from the others?

I was previously using pound, which processed mixed redirects and backends in order.

Best Answer

I'm afraid it is not possible to process use_backend before redirect statements. I believe HAPROXY evaluates redirects after it receives the entire HTTP request from the client and chooses a backend only after it discovers that the client will not be redirected.

You do not need to modify every redirect rule in order to add additional exclusion paths. You can use an unique ACL instead. For example, this configuration snippet would work:

acl noredirects path -m reg ^/.well-known/acme-challenge/
acl noredirects path -m beg /static/ /images/ /css/
acl noredirects req.hdr(host) -i httpsite.example.com
redirect prefix https://a.test if ! noredirects { req.hdr(host) -m reg ^a\.test(?::.*)?$ }
use_backend certbot_80 if noredirects

You can also process redirections on a backend. For example:

frontend http *:80
    acl certbot  path -m beg /.well-known/acme-challenge/
    acl httpsite path -m beg /public/
    use_backend certbot_80 if certbot
    use_backend httpbackend if httpsite
    default_backend redirector

backend redirector
    redirect prefix https://a.test if { req.hdr(host) -m reg ^a\.test(?::.*)?$ }
    redirect prefix https://b.test if { req.hdr(host) -m reg ^b\.test(?::.*)?$ }

backend httpbackend
    server httpserver httpserver.example.com:80
Related Topic