Setting up WireGuard between Linux and iOS

WireGuard is a modern VPN that’s designed to be easy to configure, performant, and secure. The ease-of-configuration is really important. If you’ve ever set up IPsec, you know what I mean. OpenVPN isn’t awful, but it isn’t good, either. WireGuard has both a Linux kernel implementation as well as a Go-based portable implementation that works on Mac and iOS. Official Windows support doesn’t exist yet, but is on the way.

I couldn’t find any information on configuring WireGuard to work with iOS. Here’s what I did to get it working.

On Linux:

Designated a /24 subnet in the RFC1918 space and set up wg0 according to the Wireguard quick start documentation. I actually configured it in /etc/network/interfaces like so:

auto wg0
     iface wg0 inet static
     address 10.108.45.1
     netmask 255.255.255.0
     pre-up ip link add $IFACE type wireguard
     pre-up wg setconf $IFACE /etc/wireguard/$IFACE.conf
     post-down ip link del $IFACE

Created /etc/wireguard/wg0.conf:

[Interface]
PrivateKey = my-private-key-goes-here
ListenPort = port-goes-here

# iPhone
[Peer]
PublicKey = public-key-goes-here
AllowedIPs = client-ip-address-goes-here/32

AllowedIPs is a bit of a misnomer. It’s not just an ACL for incoming packets; It’s also used to determine what traffic to route to each peer. The important thing here is to use /32 addresses in the AllowedIPs of the peers. If you use the entire /24 subnet, only the first peer using that subnet will work.

The iOS client side is where I had the most trouble. Part of the trouble is that the iOS app doesn’t show the state of the client. The other part is that since WireGuard is connection-less, even a bogus config will show up as active when you enable it.

Here’s what worked for me on iOS:

I created a key pair using the iOS app and put the public key in my Linux wg0.conf and restarted that interface.

Assign an address to the client from the /24 subnet. This needs to match the AllowedIPs line on the server. I used a /24 netmask on the iOS device, but /32 should work, too. I set the Listen port to 5555 to make it easy to verify incoming traffic using Wireshark, but that’s optional. A DNS server should be specified, because the existing one probably won’t be reachable with the VPN up. (Enabling Exclude Private IPs might fix that depending on the network you’re on.)

On the iOS peer config, enter the public key of the server and set the endpoint IP:port. For Allowed IPs, use 0.0.0.0/0. This will cause all traffic to be routed through the VPN endpoint while it’s active.

That’s it. Now activate the VPN and send some traffic through it. The ‘wg’ command on the Linux peer should show a handshake and data transferred in and out. To make Internet access work from the iOS device, you’ll probably want to set up NAT on the Linux peer.

Note that WireGuard is silent on the wire by default, so you won’t see a handshake unless you force traffic through it. The easiest way to do that is to use Safari to try to connect to the Linux peer’s IP address. (It doesn’t matter if it doesn’t have a web server running.) Using 0.0.0.0/0 for Allowed IPs on the client essentially forces a connection handshake because the iOS device will start sending traffic to the world through it on its own.

WireGuard roams peers between IPs effortlessly. Obviously one endpoint must have a fixed IP:port, but a peer roaming between Wi-Fi networks and LTE works beautifully.

TV standards are still a mess

I picked up a Vizio PQ65-F1 4K TV during the holiday sale season, and it’s a tremendous upgrade from our old LCD, an almost 10-year-old Sharp. The color and dynamic range are amazing and I don’t regret skipping OLED at all. I haven’t played with the built-in TV app platform at all, preferring instead to use an Apple TV 4K as the sole source device.

Sadly, TV’s continue to be anything but plug-and-play. For some reason the HDMI2 input does not work with Dolby Vision HDR (but works fine with HDR10). As far as I can tell this is not a limitation of the TV itself, so it must be a manufacturing defect. I wasted a lot of time isolating this problem. The TV itself has five HDMI inputs, and they’re not differentiated except that HDMI4 & HDMI5 require a minimum 1080P input, and HDMI1 supports the HDMI audio return channel (ARC).

Our Onkyo TX-NR545 receiver supports the latest HDMI/HDCP standards and HDR10 pass-through, but for some reason it cannot pass through Dolby Vision signals. This seems to just be a firmware limitation, but it’s an EOL product and Onkyo’s solution is to buy a new device. A workaround is to use HDMI ARC to pass audio from the TV to the receiver, and connect source devices directly to the TV. That works fine, but prevents using the latest audio formats (e.g., Dolby Atmos).

I’m still using a 3.0 audio setup, so I don’t care about Atmos right now, but it’s obnoxious to have to choose between having the latest audio standards and having the latest video standards (or buying a new receiver). There are some HDMI splitters (such as HDFury) that could work, but they’re 1/3 or more the price of a new receiver.

The TV works well as a dumb monitor; the Internet connection is completely optional. If connected to a network, it will update its firmware without asking. My current plan is to leave it on the network for home automation and Chromecast support, but to block its Internet access at the router.