I've been dying to try out WireGuard for a while now, and I finally got around to it. I was scouring tutorials and also checked the docs and figure it all out. It's a new VPN protocol, that works similarly to ssh. I've put my desktop, iPhone, and MacBook Air on it. Here's a few neat things it's allowed me to try:

  • Running iOS builds from xcode without being on the same physical network. Useful on an unknown network and you don't feel like connecting your phone after connecting your laptop.
  • Accessing development servers from any device, without remembering the IP address. Ex: macbookair:3000 from any of my devices, across any network.
  • Throwing up code-server on my desktop, and coding from my iPad from anywhere.
  • Using VS Code's Remote SSH plugin, and running all projects on a desktop, increasing Macbook air battery life. Plus things run way faster and cooler on the laptop now!
  • Steam link / game streaming away from home.
  • Adding a windows file share (raid setup) to the iOS Files app, using it from anywhere. It's like having your own personal iCloud.

There's so much more you can do, hopefully that gives you some ideas.

Here's the fastest way to get it running on Ubuntu and iOS, while also persisting your configuration.

Server Setup

Get an Ubuntu server running 20.04, I like to use Digital Ocean. After setup, I tend to change the default SSH port in /etc/ssh/sshd_config and also disable root logins.

First, we need to enable ipv4 forwarding, so that traffic flows through our VPN:

sysctl net.ipv4.ip_forward=1
sudo vim /etc/sysctl.d/99-sysctl.conf
# Add 'net.ipv4.ip_forward = 1' to the end of the file

Now let's install WireGuard

sudo apt install wireguard

Let's generate keys for our server

umask 077; wg genkey | tee privatekey | wg pubkey > publickey
sudo mv publickey /etc/wireguard/publickey
sudo mv privatekey /etc/wireguard/privatekey

the first command ensures that our outputted file can only be used by the current user, as a security precaution. The remaining piped commands come from the key generation docs from WireGuard. After that, I am copying the files into the wireguard directory for safe keeping.

Create our first peer's keys

wg genkey | tee mobile-privatekey | wg pubkey > mobile-publickey
sudo mv mobile-publickey /etc/wireguard/mobile-publickey
sudo mv mobile-privatekey /etc/wireguard/mobile-privatekey

Let's create our WireGuard interface configuration.

sudo vim /etc/wireguard/wg0.conf

[Interface]
## Internal IP for the interface  ##
Address = 10.10.10.1/24

## Whatever DNS provider you want to use, in this case CloudFlare ##
DNS = 1.1.1.1

## My VPN server port ##
ListenPort = 41194

## cat /etc/wireguard/privatekey and paste the contents below ##
PrivateKey = privatekeytext

# Change eth0 to your network interface if it differs
PostUp = iptables -A FORWARD -i wg0 -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE; ip6tables -A FORWARD -i wg0 -j ACCEPT; ip6tables -t nat -A POSTROUTING -o eth0 -j MASQUERADE; iptables -A INPUT -s 10.200.200.0/24 -p tcp -m tcp --dport 53 -m conntrack --ctstate NEW -j ACCEPT; iptables -A INPUT -s 10.200.200.0/24 -p udp -m udp --dport 53 -m conntrack --ctstate NEW -j ACCEPT
PostDown = iptables -D FORWARD -i wg0 -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE; ip6tables -D FORWARD -i wg0 -j ACCEPT; ip6tables -t nat -D POSTROUTING -o eth0 -j MASQUERADE



## Add the below section for every client you created above ##
## Increment the allowedIPs by one each time ##
[Peer]

PublicKey = publickeyfromclient
AllowedIPs = 10.10.10.2/32

Internal IP for the interface

Be sure to paste your PrivateKey contents, first one is /etc/wireguard/privatekey and the other would be your mobile-publickey. Open up access to the ListenPort of your choosing, if you have a firewall like csf or ufw enabled.

Next, we enable the service, so that it runs on boot, and start it:

sudo systemctl enable wg-quick@wg0
sudo systemctl start wg-quick@wg0

Run sudo wg and make sure you see your interface and peers listed with the correct addresses. You can create multiple interfaces, just make wg1.conf and enable that, instead of wg0 above. This can be useful if you have a lot of devices and networks you want to setup.

iOS config

Our server is good to go! Let's make a config file for iOS now. There's nothing special about this config, and it could be used on any type of device. But at the end we will encode it in a QR code for usage in the mobile WireGuard app.

vim mobile.conf

[Interface]
PrivateKey = <contents of mobile-privatekey>

## Must match peer address in our server config above ##
Address = 10.10.10.2/32

## Setup your own DNS server, or use CloudFlare / Google / etc ###
DNS = 1.1.1.1


[Peer]
PublicKey = <contents of server-publickey>
Endpoint = <public-server-ip>:41194
AllowedIPs = 0.0.0.0/0, ::/0

Replace the Interface PrivateKey with the contents of mobile-privatekey. Replace Peer PublicKey with the server's /etc/wireguard/publickey. Finally, put your server's public IP address in the Endpoint field.

Add to device

sudo apt-get install qrencode
qrencode -t ansiutf8 < mobile.conf

You'll now see a QR code. Scan it using the WireGuard iOS app, and you should be connected!

Adding more peers

Here's a quick reference for when you want to add a new client device to your VPN network.

# Generate new private / public keys
wg genkey | tee DESKTOP-privatekey | wg pubkey > DESKTOP-publickey

# Copy existing config, since it has most of what we need
cp mobile.conf DESKTOP.conf

cat DESKTOP-privatekey # copy contents

vim DESKTOP.conf

Inside DESKTOP.conf (or whatever you named it) you need to paste the private key contents at the top, and then increment the Address by one. Ex: 10.10.10.2/32 becomes 10.10.10.3/32.

Now we need to update our /etc/wireguard/wg0.conf file:

cat DESKTOP-publickey
# copy the contents

vim /etc/wireguard/wg0.conf

# Add the following lines to the bottom

[Peer]

PublicKey = contents-from-above

# Matching IP from our DESKTOP.conf file
AllowedIPs = 10.10.10.4/32

PersistentKeepalive = 25

If your device is behind a firewall, and it is going to be routinely used as a server, you will want to use PersistentKeepalive, otherwise you can omit it.

My desktop doesn't access anything from my iPhone, so my iPhone doesn't use it. However, I do use PersistentKeepalive on my desktop, because my iPhone regularly connects to its development server, file share, etc and it is behind a router.

Now we run sudo systemctl restart wg-quick@wg0 and then sudo wg should show the peer we just added.

Copy the DESKTOP.conf file to your device, or use the QR method from above for mobile. Repeat these steps and replace DESKTOP with your real device name!

If you are serious about using this, it can be nice to setup a DNS server as well. This way you can alias all your device IP's and just use macbook or iphone when connecting between devices. Follow this guide for more on that. I wanted to keep this tutorial to the bare minimum. Because of my interest in WireGuard, I've been following a tuturial on making a DNS server in Rust. So I may write about setting that up if I end up finishing it.

I hope this was helpful, as I had found a mix of the above steps, and some extra unnecessary things on other tutorials.