wireguard via algo: a simpler, faster(ish) alternative to IPSec

wireguard logo

tl;dr: I’m impressed with wireguard, and I’m impressed with algo, but using wireguard with the macOS and iOS clients makes things slower than I had hoped.

Wireguard, as an IPSec replacement

I’ve been experimenting with wireguard over the past few months. I’ve used IPSec for years, and the IKEv2 “road warrior” set up does what I need. It’s just, well, a bit slower than I would like.

There were two main reasons I was keen to give wireguard a try:

Server-side: algo, on a RPi 4

There are various ways you can install and configure wireguard, but I had wanted to give algo a try for a while.

algo is a set of ansible scripts, designed to make deploying both IPSec and wireguard with secure defaults incredibly easy.

It did.

I followed the instructions for a local installation with a “road warrior” setup, and it worked.

So I don’t really have much to say.

As an aside, there are two additional feature I like about algo:

In other words, they’re honest about their setup’s capabilities and limitations. They’re not claiming that using it is going to make you invisible, or unsurveillable, and for good reason. Given that so many VPN services claim to offer either or both of these things — whether they actually offer them is a different story — I found this refreshingly honest.

Client-side: a tweaked algo-generated profile with the macOS and iOS apps

##algo-generated profiles

One of the nice parts of algo is that it generates profiles to simply installation on the clients.

Unlike the server-side config, the profiles did not work without some manual intervention. I didn’t dig into why the generation routine failed; I’m afraid to say that I just fixed them and moved on.

The error, for those interested, was in the configuration of DNS.

The invalid line was:

DNS =,{'2001:db8:1e7:115:': None}

To be valid, the single quote marks and brackets around the IPv6 address, and the comment, need removing, and the IPv6 address needed an additional trailing semi-colon:

DNS =,2001:db8:1e7:115::

I ran a sed string across all the config files, so it wasn’t a significant hold-up.

Native apps

I installed the native macOS or iOS client from the relevant app store, and imported the fixed config. It worked.

On-demand activation

screenshot of on-demand config on macOS

Configuring on-demand activation within the client software is simple. This means you can have the VPN connect automatically if different conditions are met.

For example, if you want to connect to the VPN whenever you are on a cellular network, or on a Wi-Fi network other than ones that you’ve expressly whitelisted, you can do that easily.

By contrast, it took me quite a lot of trial and error to generate the necessary xml for the .mobileconfig provisioning file for IPSec.

It is not as fast as I had hoped

I was hoping that wireguard would achieve faster speeds than I was getting from my IPSec setup.

The RPI is on a LAN with a 500/500 Mbit Internet connection, and running a speed test shows that it can make use of pretty much all of that. So I had quite high hopes.

However, testing with iperf3 on a mixture of cellular, Wi-Fi, and wired connections suggests that wireguard was maxing out at about half the speed available to the device, whether on the LAN or outside it (e.g. over a cellular connection).

For example:

Practically, for my usage, this is not going to have a meaningful impact. I say this in the sense that very little I do is bandwidth-intensive, and I spent years with a VDSL connection which topped out at 28 Mbit without causing me any problems. And it does still have the edge over my IPSec setup.

That being said, it would be nice to get near native speeds, “just because”.

To be clear, I’m not blaming the wireguard protocol for this. And I was the extraordinarily lucky beneficiary of a considerable volume of unsolicited help from Jason Donenfeld, the chap behind wireguard. I’m attributing the slower speed to the fact that the current approach for macOS and iOS requires userspace software, rather than it being in the kernel. Perhaps, in time, that problem will go away.

(And, yes, I could reconsider my approach, so that I only route some traffic over the VPN, rather than everything. And, now that iOS and macOS support DNS-over-https via .mobileconfig (a post for another day), I can still use my network-based ad-blocking by forcing my own choice of DNS server, even over a cellular network. But, for now, I take some comfort from keeping some servers behind an additional degree of protection.)

I would recommend this setup

I set the system up in late November 2020, and I’ve been using it as my sole VPN since then. It was easy to deploy (aside from the profile issue, and even that was easy to fix), it is easy to manage, and it works well enough.

I love wireguard’s simplicity, with clean config files, and practical public/private key-based approach.

Admittedly, I’ve done a lot less travelling then would have been the case in the Times Before The Pandemic. But I do still try to go for a walk or a cycle occasionally, and whenever I’m outside the reach of the Wi-Fi network here, wireguard kicks in automatically.

It has not been flawless, in that there have been times when traffic just was not routing, and I’m not sure why. Forcing a reconnection usually flushes it through, although there have been a couple of times where I’ve needed to switch the IPSec connection instead. But it has been just a couple of times, so I have not dug into it any further.

(And there have been times when I’ve had trouble with my IPSec connection, including times when, for no reason I can determine, I’ve needed to disable 4G on my cellular connection, forcing my phone down to 3G, before it will connect.)