Wireguard is still being tested and verified. A lot of people say to not use in production until that verification happens, but it’s a much simpler system which I use just to gain a nicer tunnel than SSH so I use it regardless. I always run my stuff as if it were publicly exposed which you should be doing as well.

That said it can be interesting to setup.


The install for wireguard varies, but is the least interesting step. Wireguard’s docs are pretty straight forward on this.

For MacOS, iOS, Android, or Windows install the special clients otherwise on Linux setup the repository for your distro and install Wireguard.

For simplicity we will assume you’re trying to connect an iPhone to a private network in something like AWS.

The VM in AWS will be our publicly available endpoint where we run Wireguard. This is the “wireguard vpn server”. Our iPhone will be our client which is connecting to that server.

Wireguard calls everything peers. We only call something a server to make it clear this is the one with the public IP address everything connects to which is the only difference.

Configure the server

I will assume Debian or Ubuntu for your VM, but follow Wireguard’s docs for other distros.

Ensure your server is up to date, add the repository, and install Wireguard. You’ll need root permissions in Linux so Wireguard can setup it’s super fast Kernel Module.

Once installed we need to create a config file for Wireguard in /etc/wireguard which we will call wg0.conf. Be sure to include .conf and the wg0 part is the name of this “wireguard interface” so it’ll be important.

The file itself is a very simple TOML file which looks similar to this:

Address =
PrivateKey = [private key goes here]
Port = 51820

AllowedIPs =
PublicKey = [public key]
PresharedKey = [pre shared key]

We will create this file and come back to it as we create and copy the keys to the right places.

Important note: Wireguard does not give you an IP. You pick it when you do this config. Your client, when it connects, uses it’s special keys to try to become whatever IP it asks to be. The IP is sort of like the username. Every time you setup a device (”peer”) you need to set up what it’s IP will be using the x.x.x.x/32 pattern in the AllowedIPs section.

We shouldn’t generate the keys for the client key, but we can generate the server’s keys.

The following will create the public and private versions of the server key.

wg genkey | tee server-privatekey | wg pubkey > server-publickey

Copy the contents of server-privatekey and paste it in to the [Interface] section of the wg0.conf file where it says PrivateKey. We’ll use the Public Key later when setting up the client.

Next lets go ahead and generate the Preshared Key and paste the output into the [Peer] section’s PresharedKey.

wg genpsk

Now we can setup the client

Configure the client

At this point we do not yet have wireguard running, but we’re very close.

We have/need:

  • The server’s Public Key
  • The Preshared Key
  • Wireguard installed on the client device
  • A public IP address for the server and what port it’ll be using

Now we go in to Wireguard on the device (iOS in this example) and create a new config from scratch.

Once we do this it’ll generate the private/public keys for this new config for you. Copy the public key for this device and get that to the server’s config and add it under the [Peer] section.

For the client’s config the UI will ask for your Address under the Interface section which is where you’ll put the IP you picked ( in this case. Don’t forget to enter that whole IP address.)

For our purposes the other options under Interface are not interesting to us.

You’ll add a peer where you’ll add:

  • The server’s public key to Public Key
  • The Preshared Key we generated on the server to Preshared Key
  • The end point to the server’s IP with the chosen port 51820 (e.g. x.x.x.x:51820. Note, it’s NOT in this example)
  • The AllowedIPs refers to which IPs should Wireguard send traffic to the other peer for. For now, simply use which lets you access any IPs in the 10.0.0.x range from this client over wireguard.
  • Since we’re on a phone we’ll use a Persistent Keepalive of 25 which should be good enough to avoid needing to restart the connection constantly.

For now do not enable any On Demand settings because they do behave weirdly and it’s best if you already know it works first before trying to figure out what’s wrong with it.

Finishing up the server

A reminder we need the Public Key from the iPhone now and to update /etc/wireguard/wg0.conf’s [Peer] section with the Public Key.

Once that’s done we should have

  • A config named wg0.conf which refers to the wg0 wireguard interface.
  • A private key for the server
  • An address for the server (
  • A port for the wireguard server to listen on (51820)
  • A peer config for the iPhone
  • A public key for the peer
  • A preshared key we generated on the server shared on the iPhone and in this config under the peer
  • An address which the peer is allowed to use when connecting (

Since Debian and Ubuntu now use SystemD we will simply run the systemd config included with Wireguard to start the server

systemctl start wg-quick.service@wg0
systemctl enable wg-quick.service@wg0

Run the status command to make sure everything is good

systemctl status wg-quick.service@wg0

A final check: ensure that your firewall (e.g. Security group in AWS) allows TCP connections on port 51820. (This is dependant on where you have the VM hosted and how so it’s hard to give a reliable step-by-step).

Finshing up on the client

Now everything should be setup! You can connect to the wireguard server and start accessing anything on the server.

You can test this by running something like Nginx or Apache and try navigating to in Safari to access the server directly over wireguard (Don’t try using the public IP since that won’t prove if it works or not).