How to install and configure your own VPN server in GCP with Wireguard
Tags: linux, wireguard, vpnserver, centos
Published: 2020-08-16 01:44:59

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, 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 between clients.
In this tutorial we focus on implementation of vpn server on Google Cloud Platform (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
In the server side we will use CentOS 8 in GCP, the steps are:
* [Create a virtual instance](#chapter-1)
* [Setup ssh keys](#chapter-2)
* [Install Wireguard](#chapter-3)
* [Configure Wireguard Server](#chapter-4)
* [Configure clients](#chapter-5)

## Create virtual host in GCP <a name="chapter-1"></a>
In this step we need to have an account in Google Cloud Platform and create a vm instance in compute engine. In this step you need to select the vm resource of you preference, in my case I choose a general purpose virtual machine with E2 series processor, I select the e2-small configuration with 2 vCPU and 2GB of ram, finally I choose centos 8 with 20 GB of ssd storage, the configuration is showed in next image.

![gcp-vm](https://dev-to-uploads.s3.amazonaws.com/i/8xg2toc9jjxkto2p288r.png)

## Setup ssh keys <a name="chapter-2"></a>
In order to access to our virtual machine, we need to create a ssh key, the ssh key are create with this command
```sh
ssh-keygen -t rsa -f ~/.ssh/[KEY_FILENAME] -C [USERNAME]
```
And, restrict the access of the key
```sh
chmod 400 ~/.ssh/[KEY_FILENAME]
```
Get public ssh key and copy
Copy directly from command line output
```sh
cat ~/.ssh/[KEY_FILENAME].pub
```
Copy with xclip from command line
```sh
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
```sh
ssh -i ~/.ssh/[KEY_FILENAME] [USER]@[PUBLIC_IP_ADDRESS]
```
## Install Wireguard <a name="chapter-3"></a>
Before install wireguard we need to update the system
```sh
sudo dnf update
```
Then, we need to install some repositories
```sh
sudo yum install elrepo-release epel-release
```
Finally, install wireguard kmod and wireguard tools
```sh
sudo yum install kmod-wireguard wireguard-tools
```
## Configure Wireguard Server <a name="chapter-4"></a>
Before creating the wireguard config file is necessary to generate public and private key
First change to root user
```sh
sudo su -
```
Go to `/etc/wireguard` directory
```sh
cd /etc/wireguard
```
Limit default file permission of root user
```sh
umask 077
```
Generate public and private key
```sh
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
Go to VPC network -> Firewall -> Create new firewall rule
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
```sh
systemctl enable --now wg-quick@wgserver
```
Check the status
```sh
systemctl status wg-quick@wgserver
```
The output will be like this

![wg-status](https://dev-to-uploads.s3.amazonaws.com/i/jcmwx2b82d8ickcctksm.png)

## Configure clients <a name="chapter-5"></a>
To create peers, we need to create a folder wgclients and one template for all clients
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
```sh
mkdir ~/wgclients/client1
```
Copy template
```sh
cp ~/wgclients/template.conf ~/wgclients/client1/client1.conf
```
Generate client keys
```sh
wg genkey | tee private-key | wg pubkey > public-key
```
Copy client private key and paste in client config file
```sh
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 in server-side
```sh
sudo su -c "wg addconf wgserver <(wg-quick strip wgserver)"
```
Check wireguard config status, will appers the new client
```sh
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
```sh
qrencode -t ansiutf8 < ~/wgclients/testclient/testclient.conf
```
Example of QR code generated from command line

![wg-qr](https://dev-to-uploads.s3.amazonaws.com/i/2e620bfoz4jlj9mtqf1n.png)

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.

Check connection in the server-side
```sh
sudo wg show wgserver
```

![wg-show](https://dev-to-uploads.s3.amazonaws.com/i/pdlqlap92rv4c34zmbn4.png)

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, in the desktop you can use `NetworkManager` to import a connection or use `systemd` based service, also you can implement client config in OpenWrt router.