![]() |
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:
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.