Skip to content

How-to

Self-hosted VPN with WireGuard

Run WireGuard on an instance to reach your private network from your computer, as if you were on it. You run and maintain the VPN instance yourself: Breqwatr Cloud doesn't offer a VPN service.

Once the tunnel is up, you connect to your instances' private addresses directly, over SSH, RDP or anything else, and none of them needs a floating IP.

Before you start

  • A network with a router to the internet: see Networks and routers. Note its address range, such as 10.0.0.0/24.
  • A key pair: see Key pairs.
  • WireGuard on your computer: the WireGuard app from wireguard.com on Windows and macOS, or the wireguard-tools package on Linux.
  • The files from learn-projects at v1.1.0.

The tunnel uses 10.8.0.0/24. If your network already uses that range, pick another private range and change it in both files.

Create the security groups

Two groups: vpn lets WireGuard in, and from-vpn lets the VPN instance reach your other instances.

  1. In the Breqwatr Cloud Portal (Strata), open Security Groups and choose New security group. Name it vpn and create it.
  2. Open vpn and add two rules: Protocol UDP, Port 51820, Source CIDR left blank for any address; and Protocol TCP, Port 22, Source CIDR your public IP address followed by /32, so you can set the instance up.
  3. Create a second group named from-vpn. Its rules wait until the VPN instance has an address.
openstack --os-cloud <cloud-name> security group create vpn
openstack --os-cloud <cloud-name> security group rule create vpn --protocol udp --dst-port 51820
openstack --os-cloud <cloud-name> security group rule create vpn --protocol tcp --dst-port 22 --remote-ip <your-ip>/32

openstack --os-cloud <cloud-name> security group create from-vpn
openstack --os-cloud <cloud-name> security group rule create from-vpn --protocol tcp --dst-port 22 --remote-group vpn
openstack --os-cloud <cloud-name> security group rule create from-vpn --protocol tcp --dst-port 3389 --remote-group vpn

Add rules to from-vpn for any other port you want to reach through the tunnel.

resource "openstack_networking_secgroup_v2" "vpn" {
  name = "vpn"
}

resource "openstack_networking_secgroup_rule_v2" "vpn_wireguard" {
  security_group_id = openstack_networking_secgroup_v2.vpn.id
  direction         = "ingress"
  ethertype         = "IPv4"
  protocol          = "udp"
  port_range_min    = 51820
  port_range_max    = 51820
  remote_ip_prefix  = "0.0.0.0/0"
}

resource "openstack_networking_secgroup_rule_v2" "vpn_ssh" {
  security_group_id = openstack_networking_secgroup_v2.vpn.id
  direction         = "ingress"
  ethertype         = "IPv4"
  protocol          = "tcp"
  port_range_min    = 22
  port_range_max    = 22
  remote_ip_prefix  = "${var.my_ip}/32"
}

resource "openstack_networking_secgroup_v2" "from_vpn" {
  name = "from-vpn"
}

resource "openstack_networking_secgroup_rule_v2" "from_vpn" {
  for_each          = toset(["22", "3389"])
  security_group_id = openstack_networking_secgroup_v2.from_vpn.id
  direction         = "ingress"
  ethertype         = "IPv4"
  protocol          = "tcp"
  port_range_min    = tonumber(each.key)
  port_range_max    = tonumber(each.key)
  remote_group_id   = openstack_networking_secgroup_v2.vpn.id
}

WireGuard doesn't answer anything without a valid key, so UDP 51820 can be open to any address. Limit it to your own IP address if yours doesn't change.

Launch the VPN instance

Launch an Ubuntu instance with flavour v1.c1r2 on your network, with your key pair and the vpn security group, and give it a floating IP, the same way as any Linux instance: see Launch your first instances. Name it vpn-01.

In the portal, then open from-vpn and add rules for Port 22 and Port 3389, with Source CIDR vpn-01's private address followed by /32.

Set up WireGuard on the VPN instance

Sign in with ssh ubuntu@<vpn-floating-ip>, then install WireGuard, make the instance's keys, and turn on forwarding so it passes traffic on to your network:

sudo apt-get update && sudo apt-get install -y wireguard
wg genkey | sudo tee /etc/wireguard/server.key | wg pubkey | sudo tee /etc/wireguard/server.pub
echo net.ipv4.ip_forward=1 | sudo tee /etc/sysctl.d/99-wireguard.conf
sudo sysctl --system

The second command prints the instance's public key. Your computer's configuration needs it.

Make your computer's keys

In the WireGuard app, add an empty tunnel. The app makes a key pair and shows the public key. Name the tunnel breqwatr-vpn, and leave the window open for the next step.

wg genkey | tee client.key | wg pubkey > client.pub
cat client.pub

Write the two configurations

On the VPN instance, save wg0.conf as /etc/wireguard/wg0.conf, with the instance's private key (sudo cat /etc/wireguard/server.key) and your computer's public key:

# WireGuard on the VPN instance, saved as /etc/wireguard/wg0.conf

[Interface]
Address = 10.8.0.1/32
ListenPort = 51820
PrivateKey = <server-private-key>
# Sends traffic from the tunnel on to your network with the VPN instance's own address
PostUp = iptables -t nat -A POSTROUTING -s 10.8.0.0/24 -j MASQUERADE
PostDown = iptables -t nat -D POSTROUTING -s 10.8.0.0/24 -j MASQUERADE

# One [Peer] section for each device that connects, each with its own tunnel address
[Peer]
PublicKey = <client-public-key>
AllowedIPs = 10.8.0.2/32

Start it, and have it start at every boot:

sudo chmod 600 /etc/wireguard/wg0.conf
sudo systemctl enable --now wg-quick@wg0

On your computer, fill in client.conf with your private key, the instance's public key, its floating IP and your network's address range:

# WireGuard on your computer

[Interface]
Address = 10.8.0.2/32
PrivateKey = <client-private-key>

[Peer]
PublicKey = <server-public-key>
Endpoint = <vpn-floating-ip>:51820
# The tunnel, and your network's address range
AllowedIPs = 10.8.0.0/24, <network-range>
PersistentKeepalive = 25

In the tunnel window, keep the PrivateKey line the app wrote, paste the rest of client.conf below it, and choose Save. Then choose Activate.

sudo cp client.conf /etc/wireguard/breqwatr-vpn.conf
sudo chmod 600 /etc/wireguard/breqwatr-vpn.conf
sudo wg-quick up breqwatr-vpn

sudo wg-quick down breqwatr-vpn closes the tunnel.

Only traffic for the tunnel and your network goes through the VPN. The rest of your traffic goes out as usual.

Check it worked

  • On the VPN instance, sudo wg show lists your computer's public key with a latest handshake a few seconds old.
  • From your computer, ping 10.8.0.1 answers.
  • You can reach an instance in the from-vpn group at its private address: ssh ubuntu@<private-address> for Linux, or RDP to the private address for Windows.

Once it works, remove the vpn group's SSH rule if you don't need it, and sign in to the VPN instance through the tunnel at its private address instead.

Add more devices

Give each device its own key pair and its own tunnel address, such as 10.8.0.3/32. Add a [Peer] section for it to wg0.conf on the VPN instance, then sudo systemctl restart wg-quick@wg0. To remove a device, delete its [Peer] section and restart.

Keep the VPN instance small

  • Run nothing else on it, and keep it updated with sudo apt-get upgrade.
  • Keep every private key on the machine it was made on.
  • If the instance is replaced, its keys go with it: make new ones and update every device's configuration.