Virtual hosting, the IPv6 way

Mesh

Virtual Hosting, the IPv6 Way

 

Virtual Hosting: The act of hosting several web servers on a single piece of hardware

Before there were VM (Virtual Machines), Containers (light-weight VMs), VPS (Virtual Private Servers), there was a need to host multiple servers on a single machine. In the 1990s the internet was exploding, and everyone wanted to have their own web site. The concept of running multiple web servers on a single piece of hardware was created, and implemented in one of the first open source webservers, Apache.

Virtual Hosting, the Old Way

Apache implemented virtual hosting by having the server examine the HTTP Header looking for the Host Field. Based on the Host Field the web server would utilize a specific configuration for that Virtual web server, and serve up files based on that configuration.

A typical Apache Configuration would be:

<VirtualHost *:80>
    ServerAdmin webmaster@localhost
    ServerName www.makikiweb.com
    DocumentRoot /home/makiki/
    <Directory />
        Options FollowSymLinks
        AllowOverride None
    </Directory>
</VirtualHost>

The advantage of the Apache VirtualHost was that back in the days of IPv4, a single IP address could server many, many websites. This was good for the conservation of IPv4 address space.

However, sharing a single IP address means that you can’t get to the website by IP address alone:

IPv4 only addressing

Virtual Hosting, the IPv6 Way

With seemingly inexhaustible amount IPv6 address space, it is time to rethink how we implement Virtual Hosting. We no longer need to share a single IP address for a stable of servers.

It is possible to add many IP addresses to the web server host

$ ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether b8:27:cb:bf:52:9c brd ff:ff:ff:ff:ff:ff
    inet6 2001:db8:8:78::f03/64 scope global 
       valid_lft forever preferred_lft forever
    inet6 2001:db8:8:78::f02/64 scope global 
       valid_lft forever preferred_lft forever
    inet6 2001:db8:8:78::f01/64 scope global 
       valid_lft forever preferred_lft forever
    inet6 2001:db8:8:78::102/64 scope global 
       valid_lft forever preferred_lft forever
    inet6 2001:db8:8:78::101/64 scope global 
       valid_lft forever preferred_lft forever
    inet6 2001:db8:8:78::100/64 scope global 
       valid_lft forever preferred_lft forever
    inet6 2001:db8:8:78::1/64 scope global 
       valid_lft forever preferred_lft forever
    inet6 fe80::ba27:cbff:febf:529c/64 scope link 
       valid_lft forever preferred_lft forever

Now each Virtual web server can to have its own IPv6 address. This allows the web server to direct the request directly to the virtual server based on IP address. Using a more modern web server such as nginx also allows individual configuration for each virtual web server such as support for TLS (or not), Proxy Protocol (or not).

A typical nginx configuration for three virtual hosts would be:

# Server 1 on 2001:db8:8:78::102
server {
    listen [2001:db8:8:78::102]:80 proxy_protocol ;

    # setup to log original client IP address
    # incoming IPv4 requests from two proxies   
    set_real_ip_from  2001:db8:0:80:1000:3b:1:1;
    set_real_ip_from  2001:db8:0:82:1000:3b:1:1;
    real_ip_header    X-Forwarded-For;
    root /home/makiki;
    access_log /var/log/nginx/makiki.log;
    location / {
        index         index.html index.htm;
    }
}

# Server 2 on 2001:db8:8:78::f02
server {
    listen [2001:db8:8:78::f02]:80 ;
    root /home/makiki;
    access_log /var/log/nginx/makiki.log;
    location / {
        index         index.html index.htm;
    }
}

# Server 3 on 2001:db8:8:78::f03
server {
    listen [2001:db8:8:78::f03]:80 ;
    root /home/makikica;
    access_log /var/log/nginx/makikica.log; 
    location / {
            index         index.html index.htm;
    }

Each Virtual web server is listening on a unique address with specific configuration for that web server.

The example above shows:

  • Server 1 & 2 are simulating a dual-stack server with one server listening via the IPv4 reverse proxy, and Server 2 listening directly to IPv6. Both are serving the same content (same Document Root), and logging to the same log file. The log file will have both IPv6 and IPv4 addresses (provided by the proxy_protocol).
  • Server 3 is an IPv6-only server, serving different content.

Having an IP address for each web server also eliminates the dreaded “Sorry…” page, as the web server is no longer reliant on the Host Field to direct the request.

Conclusion

When implementing IPv6 networks and services, it is important to not fall into the same IPv4 design constraints and work-a-rounds in the past. Take some time to think outside the box and create a cleaner design, an IPv6 design.

Author: Craig Miller

IPv6 Advocate since 1998