IPv4 Proxy in a IPv6-only World

Mesh

Legacy Transition Device
a record player connected to a laptop

by Craig Miller

With the adoption rate of IPv6 surpassing 35% (as measured by Google), it is time to start thinking for the long term. It is time to create IPv6 systems, which IPv4 transition bolted to the side, rather than the other way around.

To this end, it is time to setup IPv6-only servers, such that when IPv4 is no longer needed, the transition device can be powered off, and no one will notice.

In this article, I won't be discussing how to setup a reverse-proxy, but rather how to setup your IPv6 web services to be compatible with a disposable IPv4 transition device, and just have a clean IPv6-only network left.

IPv4 Transition Device

There are lots of ways to support IPv4 in a transition device, such as NAT64/DNS64, or 464XLAT, or running a reverse proxy (often referred to as just "proxy").

The beauty of NAT64 is that as more traffic is IPv6 native, the proxy become less loaded. It is not something that you have to plan to increase, but rather it is a decreasing resource. Eventually, it will no longer be needed.

Applying the same thought process to a reverse proxy means that IPv6 traffic goes directly to your webserver, and only IPv4 traffic is directed to the IPv4 reverse-proxy.

Picking the correct path

The problem: IPv4 is scarce. The solution: IPv6 is plentiful

The traditional thinking up until this point has been to use Apache to create Virtual Servers based on host name. Many Virtual Servers would share a single IP address, but this is scarce thinking.

In an IPv6-only world, IP addresses are not scarce, and so therefore, it make sense to place each web service on its own IPv6 address (something we used to do with IPv4 before it became scarce).

Controlling the flow with DNS

It is possible to control the flow of clients making requests to your webserver, by placing different addresses for IPv4 and IPv6. That is, the IPv4 address is the IP address of the proxy not your server. Your DNS entries would look something like this:

myserver    IN  A       203.0.113.51    ;proxy address
myserver    IN  AAAA    2001:db8::102

This directs IPv4 requests to the reverse-proxy, while allowing the IPv6 requests to go directly to the web server.

Keeping Track of Client Access

Without proxy protocol enabled, all client requests will be logged as coming from the proxy. By using proxy protocol, we can log the original source IP of the client.

When using proxy protocol, the proxy will place the original client IP address in an extra HTTP field called X-Forwarded-For. When running proxy protocol on the web server, it is possible to extract the X-Forwarded-For field and log that as the source IP of the web request.

So far so good.

Apache: proxy protocol all or nothing

I have been using Apache since the beginning. In fact, since before the beginning, and we just called it NCSA HTTPd Server. Apache has served my needs for the past 23 years.

Apache supports proxy protocol and X-Forwarded-For field, but for the entire server, or set of Virtual Servers. It is not possible to run it on one Virtual Server, and off on another. There in lies the conundrum. You want proxy protocol for the IPv4 traffic, but not for the IPv6 traffic. Apache doesn't support this.

While it is possible to run multiple instances of Apache, one must recreate the entire /etc/apache directory, complete with all the modules you want for each instance. Kludgy.

Nginx: a more modern web server

Nginx, the second most popular web server in the world, does not suffer the history nor the constraints of the venerable Apache. I have dabbled with nginx in the past couple of years, but never put my main set of web servers on it. Now was the time to give it a try.

Nginx servers

The default configuration file of nginx is default.conf located in /etc/nginx/conf.d/. By creating more "conf" files in that directory, additional servers will be started/configured.

The power of nginx configuration lies in the server context:

server {
    some config;
}

Each server can listen to an individual address on your host. Since hosts can have multiple IPv6 addresses, it is possible to have nginx listen on each of those IPv6 addresses and serve up something completely different. You might think of them as Virtual Servers

For example you could have one server listing on address 2001:db8::101 with proxy protocol, and another listening on address 2001:db8::102 without proxy protocol. Each server can point it its own Document Root! They are truly independent servers, although if you do a ps -ef | grep nginx you will see that there is only a single master process that is running.

Real world example

In my main web server, I want to run two servers, one for IPv4 via the proxy, and one for IPv6 for direct requests. So the nginx servers will share the same Document Root, since they are serving the same information, but they will listen on different IPv6 addresses, and decode the proxy protocol (or not) differently.

# Config file for makikiweb IPv4 Access 

server {
    #listen 80 default_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/cvmiller/makiki;

    access_log /var/log/nginx/makiki.log;

    location / {
        index         index.html index.htm index.php;
    }
    location ~ \.php$ {
        fastcgi_index     index.php;
        fastcgi_pass       unix:/var/run/php/php7.3-fpm.sock;
        include           fastcgi.conf;
    }
}

# Config file for makikiweb IPv6 Access 

server {
    #listen 80 default_server;
    listen [2001:db8:8:78::f02]:80 ;

    root /home/cvmiller/makiki;

    access_log /var/log/nginx/makiki.log;

    location / {
        index         index.html index.htm index.php;
    }
    location ~ \.php$ {
        fastcgi_index     index.php;
        fastcgi_pass       unix:/var/run/php/php7.3-fpm.sock;
        include           fastcgi.conf;
    }
}

That's it! Nginx is now listening to two different IPv6 addresses, one configured for the Proxy, and one configured for direct access.

Turning off IPv4

By creating a transition device which sees less traffic as time goes on, your network design will be looking to the future, rather than bing held back by complicated IPv4 legacy support.

When it comes time to turn off IPv4 access to this webserver, just turn off the reverse-proxy, and delete your DNS A record, and you have lost the IPv4 baggage, and now have a clean IPv6-only operation.



9 July 2021