The HAProxy Serving-Static-Content Hack

HAProxy is a load balancer. If you request a URL from it, the expectation is that it will forward/proxy that request to one of its backend servers. But there's a widely used hack to allow HAProxy itself to serve static content.

How It Works

HAProxy error pages can be set individually per 'backend'. If a 'backend' doesn't have a 'server' line (or the server is unavailable - the original intention of this functionality), HAProxy returns a 503 error. So we catch requests for a particular file with an 'acl' command, and then send them to a 'backend' without a 'server', where HAProxy throws a 503 error (no server available). That doesn't sound great, but a quirk of HAProxy has the error pages being constructed with not only the content of the error page ... but also (and importantly) the full Header. This means we can return a different code, such as a 200 along with our custom content. HAProxy will still log the request as a 503 error, so either keep that in mind when reading the logs or silence the errors.

We use it for a check: if the page is available, the load balancer itself is still running as expected. Alerting can be done if the page ceases to be available. (Others have found many other uses for this devious and fascinating misappropriation of HAProxy resources, such as rewriting a site's robots.txt file for it by putting HAProxy in front of the site and trapping that one filename ...)

Caveats

From HAProxy's documentation: "The files should not exceed the configured buffer size (BUFSIZE), which generally is 8 or 16 kB, otherwise they will be truncated. It is also wise not to put any reference to local contents (eg: images) in order to avoid loops between the client and HAProxy when all servers are down, causing an error to be returned instead of an image. For better HTTP compliance, it is recommended that all header lines end with CR-LF and not LF alone."

Code

/etc/haproxy/haproxy.cfg:

frontend port80
    acl is_pingdom path /lb_ping.html
    use_backend pingdom-check if is_pingdom

backend pingdom-check
    mode http
    errorfile 503 /etc/haproxy/errors/200pingdom.http

/etc/haproxy/errors/200pingdom.http:

HTTP/1.0 200 Found
Cache-Control: no-cache
Connection: close
Content-Type: text/html

<html>
<head>
<title>Up</title>
</head>
<body>
<p>Up</p>
</body>
</html>

You could also change the "Content-Type" to "text/plain" and the content to text. There are undoubtedly many other options.

Bibliography