Building simplicidade.org: notes, projects, and occasional rants

Tip: keep the Host header via nginx proxy_pass

For the past 2 or 3 years, my favorite web server is nginx. It replaced lighttpd on most of my production sites, and soon it will take over them all.

One of the roles nginx is performing is to act as a frontend server for Perl-based Web apps. This apps run under Starman or one of the other PSGI-compatible servers.

The simplest configuration block you need to use is this:

server {
    server_name my.site.com;

    location / {
        proxy_pass http://127.0.0.1:9999/;
    }
}

This will proxy the request to your Web app running at 127.0.0.1, port 9999.

The problem is that the Host HTTP header is rewritten to 127.0.0.1. In fact, the header is rewritten to whatever value you use as the host in the URL given to the proxy_pass directive.

With a bit of /etc/hosts manipulation you can use stuff like:

proxy_pass http://my_web_app.production:9999/;

But this makes the deployment process more complex because you need to keep /etc/hosts in sync with all your apps.

A cleaner alternative is to force the original Host header to be sent to the backend server, like this:

server {
    server_name my.site.com;

    location / {
        proxy_pass http://127.0.0.1:9999/;
        proxy_set_header Host $http_host;
    }
}

With this configuration, the backend server will receive whatever Host HTTP header your browser sent that matched this server block, which is particularly useful if you use a regular expression to match host names.

Or if you have multiple server_name's but want your backend to receive a fixed host name, use:

proxy_set_header Host "my.forced.hostname";

Either way, its much simpler to keep frontend and backend servers in sync, with regard to virtual host names.