Leaning on Algo to route Docker traffic through WireguardPublished on
Algo, wireguard, and dns helping to keep you from driving off the road
Part of the Wireguard series:
- WireGuard VPN Walkthrough
- Routing Select Docker Containers through Wireguard VPN
- Viewing WireGuard Traffic with Tcpdump
- Leaning on Algo to route Docker traffic through Wireguard (most recent and contains consolidates much of the previous articles)
I write about Wireguard often. It’s been a bit over a year since my initial article and a lot has changed. Enter algo. Within the last year, it has added support for Wireguard. While algo sets up a bit more than Wireguard, it is unparalleled in ease of deployment. After a couple of prompts, the server will be initialized and configs generated for your users.
In this article I’m going to touch on everything that I’ve written about before and try consolidate everything into a single post that I can refer back to. This article fits more into an advanced usage of Algo and wireguard though I try and make it clear when one can jettison the article if an advanced setup is not necessary.
The end goal is to setup a docker server where a subset of the containers are routed through our wireguard interface, as illustrated below. I will also touch upon routing an entire machine’s traffic through the VPN, which is a much easier process.
There are many ways to install algo, but I am opinionated. I will illustrate my way, but feel free to deviate.
Algo should be installed on a local machine. I use an Ubuntu VM, but you should also be able to work on Windows via WSL or on a Mac. While algo supports a local installation (where algo is installed on the same server as the VPN), I recommend against it as an algo installation will contain the configurations, and the private and public keys for all users – things that shouldn’t be on such a disposable server.
Algo does have an official docker image (15 pulls as of this writing, and I’m pretty sure I’m half of them). To clarify, this is not the VPN, the algo docker image is merely a way to simplify installing dependencies to run algo. Unfortunately since algo does not have any formal releases at this time, when I tried using the docker image the configuration code was out of date with the bleeding edge config in the repo, and caused DNS issues that made me scratch my head for several hours.
Now we choose a VPS provider. Literally any of them should be fine. I happen to like Vultr – they have a lot of options (like a $3.5/mo plan!). They are perfect for disposable servers. When testing out my methodology, I think I spun up a couple dozen servers in my attempts and in the end it only cost me 20 or so cents. So assuming the reader is following along, the post will contain a very small number of vultr specific instructions.
Before we get started, grab your api key from vultr: https://my.vultr.com/settings/#settingsapi. We need to save this key so algo can access.
We’ll be executing the following on our algo machine (which, to reiterate, is a machine sitting next to you or close by).
Up comes the editor. Edit the users who will be using this VPN. Keep in mind, algo will ask if you want the possibility of modifying this list, so one should have a pretty good idea of the users. It is more secure to disable modifications of users after setup. It may even be easier to spin up an entirely new VPN with all the users and migrate existing users.
Answer the questions as you see fit, except for one. Answer yes to:
Do you want to install a DNS resolver on this VPN server, to block ads while surfing?
We’ll need it to resolve DNS queries.
You also don’t need to input anything for the following question (as algo will pick it up automatically)
Enter the local path to your configuration INI file
Let the command run. It may take 10 minutes if you’re setting up a server halfway around the world.
Once algo is finished and you are not interested in routing select docker traffic through a wireguard interface, you can skip the rest of the article and read the official wireguard documentation on configuring clients.
Routing select docker traffic through Wireguard
Make sure that wireguard is already installed on the box that we’ll be running docker.
Before we hop onto that, we need to modify the wireguard config files that algo created. These config files are in
wg-quick format, and while amazingly convenient, it will route all traffic through the VPN, which may be undesirable. Instead we’re going to employ a method that will send specific docker container traffic through the VPN.
First, we need to remove the
wg-quick incompatibilities for our docker user (one of the users created in
Check the results:
CLIENT_CONFIG should look a little like:
/etc/wireguard/wg1.conf onto the docker machine
/etc/network/interfaces.d/wg1 onto the docker machine.
Setup Docker Networking
Create our docker network:
At this point, if running Debian, you should be able to execute
ifup wg1 successfully. And to test wireguard execute:
The ip returned should be the same as the
It’s also important to test that our DNS is setup appropriately, as our wireguard server may resolve hosts differently. Additionally, we don’t want to leak DNS if that is important to you. Testing DNS is a little bit more nuanced as one can’t provide an interface for
dig to use, so we use emulate it by executing a dns query that comes from our docker subnet.
You can then geolocate the given IPs and see if they are located in the same area as the server (this really only works for domains that use anycast). Another way to verify is to execute
tcpdump -n -v -i wg1 port 53 and see the
dig command successfully communicate with 172.16.0.1 (alternatively one can verify that no traffic was sent on eth0 port 53).
To top our tests off:
--dns flag is critical, else docker will delegate to the host’s machine
/etc/resolv.conf, which we are trying to circumnavigate with our
wg1 interface config!
We won’t be having a perma docker network, so delete the network we created.
Instead we’ll be using docker compose, which encapsulates commandline arguments better. We’ll have docker compose create the subnet and dns for our container.
While the compose file ends up being more lines, the file can be checked into source control and more easily remembered and communicated to others.
And we’re done! Straying from official algo and wireguard docs did add a bit of boilerplate but hopefully it isn’t much and it’s easy to maintain.
I must mention that solution #1 in a previous article did not earn a shoutout here. To recap, solution #1 encapsulated wireguard into a docker container and routed other containers through the wireguard container. Initially, this was my top choice, but I’ve switched to the method illustrated here for reasons partly explained in that previous article. Wireguard is light enough and easy enough to gain insight through standard linux tools that having the underlying OS manage the interface outweighs the benefits brought by an encapsulated wireguard container.