Managing site maintenance with Varnish 3.x


Error message

Deprecated function: The each() function is deprecated. This message will be suppressed on further calls in menu_set_active_trail() (line 2405 of /var/www/

Recently I had to push out a few updates to a site that required a few big interface changes that I didn't want the public to see while I was making them. The application is running under Apache and we're using Varnish 3.x as a reverse proxy.

I wanted to be able to have a white list of IPs that can access the site and be able to display a custom error page to the user letting them know that the site is undergoing maintenance. If I were only running Apache I could do it easily in the vhost for the site, but we're using Varnish so we need to stop the request once it hits the server. I could do it with iptables and block traffic to port 80 and 443, but I wanted to display a message to the end user letting them know that the site is under maintenance.

Varnish makes this really easy, all you have to do is define access control lists and populate it with the IP address of machines you want varnish to whitelist.

acl admins {
    ''; # The IP address of my machine

And inside of your sub vcl_recv function you would put a check in to make sure that the client.ip is not included in the admins acl.

if (!(client.ip ~ admins)) {
    error 503 'Service Unavailable';

Finally, we need to display a custom error message to the end user. Because we're using the 503 error code we can use the sub vcl_error directive to generate a page to return to the user.

sub vcl_error {
    if (obj.status == 503) {
        set obj.http.Content-Type = "text/html; charset=utf-8";
        synthetic {"
            <!DOCTYPE html>
                    <title>Site Maintenance</title>
                    <h1>We're doing some maintenance!</h1>
                    <p>This site will be back shortly, we're doing a bit of maintenance.</h1>
    return (deliver);

So, there we go, we have our acl defined with our IPs that varnish will talk to, we have our check to make sure the client.ip is able to talk to varnish, and finally we have our error message. You can put anything in there and even load it from a file if needed.