Robert Važan

How to route server traffic through VPN

Short guide on how to connect to a server in the cloud via VPN without getting lost in details of setting up a full-blown enterprise VPN.

I've got a server on the Internet. Protecting some standard services like SSH is not a big deal as they are designed to be secure. The standard method to protect all kinds of application traffic is to wrap it in VPN. This is however quite non-trivial as I have discovered. Let's look at the options.

So we have a single client and a single server. VPN is running on both the client and the server. Server has both a public IP and a VPN IP. Client's IP address is mostly irrelevant.

The first thing to try is to run the insecure apps on VPN IP address. Most apps happily bind to all IP addresses on the server. A simple firewall rule can then block the binding to public IP address, which means that the insecure service can be subsequently contacted only via private VPN IP address.

So far so good. The trouble is that some server-side apps do not like being run on private IP address. This happens quite a lot when the app has both a public interface and a private administration interface. Some apps insist that their administrative interface runs on the same IP address as their public interface.

It is possible to write firewall rewriting rule that makes the app believe it is using public IP address when in fact it is being accessed through a private IP address. That however breaks down very quickly with most web-based apps that embed the public IP address in the generated content. So even if the browser initially connects through a private IP, subsequent pages are fetched through the public IP address embedded in links.

I would have to make the client rewrite the public IP address into private IP address. That would actually force the browser to use VPN all the time. There's a catch though. If I rewrite server's IP address to private VPN address, then even the VPN traffic (that is directed to the public address) would be recursively routed through the VPN, which would prevent it from ever reaching the server.

Sure, I could add an exception for the VPN port. That way all traffic except VPN traffic would be rerouted through the VPN. Good. Except that I now need quite complicated firewall rules on the client, which happens to be Windows, which is not particularly designed to do this kind of magic.

There's a home router between the client and the server. It's some Linux, but unfortunately it's not open to modifications. I could force it by flashing new ROM on it, but that's risky and I don't want to ruin a good router. I am not keen on buying new networking hardware either. Let's see what we can do with Windows.

There is one more trick to try. Let's change DNS settings. Web-based apps, which are the problematic ones, are usually very happy to embed domain name instead of IP address in links embedded in generated pages. By manipulating the DNS, it's possible to enforce use of particular IP address.

Good. So how to do it? I've used one nice little utility called Acrylic DNS Proxy. It's a simple DNS proxy that has built-in ability to perform simple redirections. It's a bit annoying in that it will use OpenDNS by default, which hijacks TLD wildcard records to display ads whenever you mistype some domain name, but that can be easily fixed by switching to Google DNS servers.

What I did was to introduce one local DNS record for my server that pointed to private VPN IP address of the server.  Public DNS records at my hosting company continued to point to the public IP address, which means that all site visitors would use the public IP address while I was the only one who would use the private IP address.

With this setup, I don't need any firewall rewrite rules at all. All I need is a few access control rules that make sure the private administrative interface of any server-side app is reachable only through the VPN.

The only gotcha is that it is now difficult to test what users of my server see. Since I have created my own view of the server, it is easy to introduce bugs that break the server for everyone except myself. Not a big deal though. All I need to test the server is one small computer or a virtual machine with default DNS settings. One has to be constantly aware of the issue though.