A small freedom area.

simple_vhost with NGiNX

Sat 16 Apr 2011

nginx, sysadmin, trick

When I migrated from lighttpd to nginx, I really missed the mod_simple_vhost, and was desperately looking for an alternative. But actually, it was simpler than expected.

Virtual hosts

The principle is simple: you have one (or more) domain names. For this blog, we'll consider you own example.org, with a few CNAME like foobar.example.org, ihazcheezburger.example.org and pikachu.example.org.

The naive solution to handle them would be:

server {
    server_name example.org;
    location / {
        root /srv/http/vhosts/example.org;
        index index.html index.htm;
    }
}

server {
    server_name foobar.example.org;
    location / {
        root /srv/http/vhosts/foobar.example.org;
        index index.html index.htm;
    }
}

server {
    server_name ihazcheezburger.example.org;
    location / {
        root /srv/http/vhosts/foobar.example.org;
        index index.html index.htm;
    }
}

server {
    server_name pikachu.example.org;
    location / {
        root /srv/http/vhosts/pikachu.example.org;
        index index.html index.htm;
    }
}

And so forth. It gets quickly painful to maintain, and the risk of error increases. Let's see how we can avoid this.

root my $vpath

Here is the (incomplete) trick:

server {
    server_name _;
    set $vpath /srv/http/vhosts/$host;
    if (!-d $vpath) {
        set $vpath /srv/http/vhosts/example.org;
    }
    root $vpath;
}

$host contains the requested host. We check if a directory exists for this domain in the /srv/http/vhosts directory. If not, we serve the default one, which is example.org here.

And finally, root selects the corresponding vhost directory.

Your tree will look like this:

% ls -l /srv/http/vhosts
drwxr-xr-x  4 ubitux ubitux 4.0K Aug 13 15:24 example.org
drwxr-xr-x  5 ubitux ubitux 4.0K Aug 15  2009 foobar.example.org
drwxr-xr-x  3 ubitux ubitux 4.0K Aug 13 15:24 ihazcheezburger.example.org
drwxr-xr-x  2 ubitux ubitux 4.0K Jan 10  2010 pikachu.example.org

There is still one issue to solve: if you keep the configuration in this state, you will notice the host is always _. We can fix that with the server_name_in_redirect option:

server {
    server_name _;
    server_name_in_redirect off;
    set $vpath /srv/http/vhosts/$host;
    if (!-d $vpath) {
        set $vpath /srv/http/vhosts/example.org;
    }
    root $vpath;
}

index