How to install and configure you own vpn server in GCP with Wireguard

Security is one of the most important things now days specifically in enterprise environments, a vpn helps to encrypt traffic from client to internet. Wireguard is a vpn protocol than works on the kernel side and acts like a network interface, is one of the most modern vpn protocols it’s based in public and private key exchange just like ssh does. A vpn can connect different host with encrypted connection throught internet, this topology can connect a simple client in an android app or even connect different hosts across datacenters inside in a cluster, for example to connect workers in Kubernetes/swarm cluster in different datacenters regions with encrypted connection without open any public API on internet, wireguard also can be used to connect different home based host across internet only opening one udp port and use the vpn server as encrypted bridge.

In this article we focus on implementation of vpn server on GCP with wireguard, this setup will use a centos 8 on the server-side, and the configuration of one client in android device.

Server-side setup

  1. Create a virtual instance
  2. Setup ssh keys
  3. Install Wireguard
  4. Configure Wireguard Server
  5. Create Peers

1. Create virtual host in GCP

Setup ssh keys

ssh-keygen -t rsa -f ~/.ssh/[KEY_FILENAME] -C [USERNAME]

And, restrict the access of the key

chmod 400 ~/.ssh/[KEY_FILENAME]

Get public ssh key and copy

# copy directly from command line output
cat ~/.ssh/[KEY_FILENAME].pub
# copy with xclip
cat ~/.ssh/[KEY_FILENAME].pub | xclip -selection c

Paste the public key in GCP. Go to Compute Engine -> Metadata -> SSH keys -> Edit -> Add item, then paste generated public ssh key

Then paste in GCP and test ssh connection

ssh -i ~/.ssh/[KEY_FILENAME] [USER]@[PUBLIC_IP_ADDRESS]

Install Wireguard

sudo dnf update

Then, we need to install some repositories

sudo yum install elrepo-release epel-release

Finally, install wireguard kmod and wireguard tools

sudo yum install kmod-wireguard wireguard-tools

Configure Wireguard Server

# change to root user
sudo su -
# go to /etc/wireguard directory
cd /etc/wireguard
# limit default file permission of root user
umask 077
# generate public and private key
wg genkey | tee private-key | wg pubkey > public-key

Create a wireguard config file in /etc/wireguard/wgserver.conf and add the following lines

[Interface]
Address = 10.50.0.1/24
SaveConfig = true
PostUp = firewall-cmd --zone=public --add-port 50555/udp && firewall-cmd --zone=public --add-masquerade && firewall-cmd --zone=trusted --add-interface=wgserver && firewall-cmd --zone=trusted --add-masquerade
PostDown = firewall-cmd --zone=public --remove-port 50555/udp && firewall-cmd --zone=public --remove-masquerade && firewall-cmd --zone=trusted --remove-interface=wgserver && firewall-cmd --zone=trusted --remove-masquerade
ListenPort = 50555
PrivateKey = <private key>

Config explained

Address: the address of subnet in wireguard interface, it must be a private ip address class a, b or c

SaveConfig: Update the config file when it added more users

PostUp: This setting is executed when the interface initializes, in this case configure the firewall

PostDown: This setting is executed when the interfaces shutdown, in this case remove firewall configuration

ListenPort: The port where wireguard is listen (wireguard only listen udp ports)

PrivateKey: Wireguard private key, this key was generated one step above in /etc/wireguard/private-key copy and paste in /etc/wireguard/wgserver.conf

Add firewall rules in GCP

To grant access to wireguard server add in source IP ranges 0.0.0.0/0, in protocols and ports add udp port on 50555 (ListenPort) then create the rule

Enable wireguard server at boot with systemd

systemctl enable --now wg-quick@wgserver

Check the status

systemctl status wg-quick@wgserver

The output will be like this

Configure Peers

The ~/wgclients/template.conf file will be like this

[Interface]
PrivateKey = <client_private_key>
Address = 10.50.0.xxx/32
[Peer]
PublicKey = <server_public_key>
Endpoint = <server_public_ip_address>:<server_listen_port>
# to route all traffic through wireguard server
# AllowedIPs = 0.0.0.0/0, ::/0
# to route only wireguard server subnet
AllowedIPs = 10.50.0.0/24

Then create a directory for each client, generate private and public key, copy template and replace client private key and address

# create client directory
mkdir ~/wgclients/client1
# copy template
cp ~/wgclients/template.conf ~/wgclients/client1/client1.conf
# generate keys
wg genkey | tee private-key | wg pubkey > public-key
# copy client private key and paste in client config file
cat private-key | xclip -selection c

Edit ~/wgclients/client1/client1.conf and copy and paste client private key, the file will be like this

[Interface]
PrivateKey = QWERTfvCAJ5WgIqpCxOz9e7yYIzxOmB/PE1GBGNGJ29=
Address = 10.50.0.100/32
[Peer]
PublicKey = QWERTYvCAJ5WgIqpCxOz9e7yYIzxOmB/QWERTYNGJ20=
Endpoint = 32.54.69.87:50555
AllowedIPs = 10.50.0.0/24

Then add client public key to /etc/wireguard/wgserver.conf after Interface config add the following lines

[Peer]
PublicKey = QWERTYvCAJ5WgIqpCxOz9e7yYIzxOmB/QWERTYNGJ20=
# if client have static ip address put here, else omit the field
# Endpoint = 32.54.69.87:50555
AllowedIPs = 0.0.0.0/0, ::/0

Then reload config file

# reload wgserver config file
sudo su -c "wg addconf wgserver <(wg-quick strip wgserver)"
# check wireguard config status, will appers the new client
sudo wg show wgserver

Then test connection, in this case with an android app. First download wireguard android app on google play store, generate QR from client config file and load from app

# generate QR code from terminal
qrencode -t ansiutf8 < ~/wgclients/testclient/testclient.conf
# check connection with
sudo wg show wgserver

Exaple of QR code generated from command line

If everything works fine, type ifconfig.me in android browser, it will appear the wireguard server address, from command line will appear the latest handshake and transfer data summary.

Now you can add more android clients with the same method, for desktop clients I highly recommend to add PersistentKeepalive option in server and client side, then you can user Network Manager to import a connection or use systemd based service, also you can implement client config in OpenWrt router.

Engineer || MSc student || DevOps in progress