4

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.

user13097
  • 221
  • 2
  • 7

2 Answers2

3

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
2

With a modern HAProxy (tested with 2.2 LTS), the syntax is intuitive:

frontend http *:80
    acl path_certbot path_beg /.well-known/acme-challenge/
    http-request redirect scheme https unless { ssl_fc } || path_certbot
    use_backend certbot_80 if path_certbot
    default_backend std_backend

backend certbot
    server certbot localhost:80

backend std_backend
    <your_backend>
  • the first line creates a named condition (path_certbot) that is true it the url starts with /.well-known/acme-challenge/
  • the second line redirects (with a HTTP/302) all the incoming requests to https, unless the request was already https, or the path_certbot condition is activated
muxator
  • 121
  • 1