2

I have the following haproxy config that adds the access-control-allow-origin header on successful 200 requests with the below config. My problem is, when I hit timeouts or haproxy itself (not my upstream server) throws an error for some other reason, this header doesn't get added. How do I add this header on e.g. 504 responses as well?

global log /dev/log local0 log /dev/log local1 notice chroot /var/lib/haproxy stats socket /run/haproxy/admin.sock mode 660 level admin stats timeout 30s user haproxy group haproxy daemon ca-base /etc/ssl/certs crt-base /etc/ssl/private ssl-default-bind-ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA> ssl-default-bind-ciphersuites TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256 ssl-default-bind-options ssl-min-ver TLSv1.2 no-tls-tickets defaults log global mode http option httplog option dontlognull timeout connect 5s timeout client 30s timeout server 30s errorfile 400 /etc/haproxy/errors/400.http errorfile 403 /etc/haproxy/errors/403.http errorfile 408 /etc/haproxy/errors/408.http errorfile 500 /etc/haproxy/errors/500.http errorfile 502 /etc/haproxy/errors/502.http errorfile 503 /etc/haproxy/errors/503.http errorfile 504 /etc/haproxy/errors/504.http frontend www-https bind *:80 bind *:443 ssl crt /etc/ssl/cert.io.pem http-response add-header access-control-allow-origin "myCoolWebsite.com" redirect scheme https code 301 if !{ ssl_fc } mode http default_backend myBackend backend myBackend server myServer 123.456.789.101:2345 

Edit: I've mostly solved this problem by adding a custom error file for 504 like below. Only problem is I couldn't figure out how to dynamically set the access-control-allow-origin to only the domain currently requesting instead of *. This is a problem, as some browsers have issues/throw on receiving responses with *. Any ideas how I can do this?

// 504.http HTTP/1.0 504 Gateway Time-out Cache-Control: no-cache Connection: close Content-Type: text/html Access-Control-Allow-Origin: * Access-Control-Allow-Methods:\ GET,\ HEAD,\ OPTIONS,\ POST,\ PUT Access-Control-Allow-Credentials:\ true Access-Control-Allow-Headers:\ Origin,\ Accept,\ X-Requested-With,\ Content-Type,\ Access-Control-Request-Method,\ Access-Control-Request-Headers,\ Authorization { "html": { "body": { "h1": "504 Gateway Time-out", "#text": "The server didn't respond in time." } } } 

1 Answer 1

1
+50

Setting headers dynamically on error documents is a limitation of HAProxy and there is currently no out-of-the-box feature available to achieve this directly. Since the error is processed before it even hits your backend servers, dynamically setting the Access-Control-Allow-Origin header is difficult.

A commonly suggested workaround for this use-case involves sending error responses through a dedicated backend. In this backend, you can execute scripts or use an application that can inspect the request and add headers dynamically.

Here are the steps in HAProxy configuration:

frontend www-https bind *:80 bind *:443 ssl crt /etc/ssl/cert.io.pem redirect scheme https code 301 if !{ ssl_fc } mode http use_backend errorBackend if { status eq 504 } default_backend myBackend backend errorBackend mode http errorfile 504 /etc/haproxy/errors/504.http http-response set-header Access-Control-Allow-Origin %[hdr(origin)] server errSrv localhost:2346 backend myBackend server myServer 123.456.789.101:2345 

When haproxy itself returns an error (like a 504 due to a timeout) the error flag is raised before getting to the backend, and it'll return the pre-configured error page directly, without passing the request to backend. Therefore, in this situation haproxy won't be able to process the headers which involve dynamic properties (e.g. varying on the requesting domain).

The workaround of sending errors to a dedicated backend makes haproxy behave like this:

  1. A client request comes to the frontend.
  2. Haproxy tries to forward the request to the backend.
  3. If the backend times out (which would usually trigger a 504 directly from haproxy), we instead direct the request to a dedicated 'error backend'.
  4. The 'error backend' creates the 504 message including headers based on the original request (as the 'error backend' works like the ordinary backend).
  5. This customized error message is then sent back to the client.

The trick is that we're not actually allowing haproxy to trigger a direct error response. The timeout will now result in switching to another backend which can process request-based dynamic headers. Hence, it does create another level of abstraction in the configuration, which can be considered as a new layer.

1
  • I don't think its version specific but I don't think this works as intended... even the config check says as much anonymous acl will never match because it uses keyword 'status' which is incompatible with 'frontend use-backend rule' . It kind of makes sense, how would you redirect to a backend in the frontend if you already have a status ? Commented Dec 9, 2024 at 14:47

You must log in to answer this question.