20

I'm currently re-configuring HAProxy using 1.5dev-17. What I'd like to do is return a 404 error when there is no backend to use for a particular request.

Our current configuration uses the default_backend to route to our django app servers, but when there are a whole lot of probing requests (like a pen-test) that match none of the other configured backends, our django servers grind to a halt as they try to serve these invalid requests, eventually returning a 404.

I'd like to serve the 404 from HAProxy rather than delegating to the django backends. I'm currently achieving this with a hack:

frontend www
    ...
    default_backend nomatch

backend nomatch
    errorfile 503 /var/www/http/404.http

And within the 404.http file I set the 404 status code in the headers. This works, but feels very wrong. Is there a better way of achieving this with HAProxy? Or should I use a regular backend and just let that handle responding with a 404?

2
  • What's the contents of the 404.http file? Apr 29, 2014 at 23:55
  • 3
    @JasonFloyd HTTP/1.0 404 Not Found followed by some other headers, then a blank line, then the <html> content. Apr 30, 2014 at 1:39

3 Answers 3

16

If you would be okay with any of the following response codes: 200, 400, 403, 405, 408, 429, 500, 502, 503, or 504.

Then you could do something like this:

frontend www
  ...
  default_backend no-match

backend no-match
  mode http
  http-request deny deny_status 400

edit: newer versions off HAProxy also support 404 as return code: https://docs.haproxy.org/2.4/configuration.html#3.8-errorfile

2

After wanting something similar this is the same thing I came up with. It felt wrong but it works very well in practice and is much cleaner than trying to blacklist particular urls. Just be sure to leave a comment so no one comes across it thinking it's incorrect.

0

This is not what the OP asked for, but in case you the reader stumbled across here while using TCP mode (like I did), the corresponding directive you want to use is tcp-request content. So you would have:

frontend my-tcp
  ...
  default_backend no-match

backend no-match
  tcp-request content reject

Of course in TCP mode there's no HTTP response code. You can also use silent-drop instead of reject if you so wish.


Note that you CANNOT use tcp-request connection because it cannot be used in a backend section. If you try to put it in a frontend section instead, haproxy will warn you:

a 'tcp-request' rule placed after a 'use_backend' rule will still be processed before

... which means it's overriding all your use_backend and default_backend directives.

While you technically CAN use tcp-response content, there's no good reason to do so in this use case (as compared to using tcp-request content.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .