BearBlogtech

Go back

Testing WireGuard Vpn

2 june 2025

Testing wireguard vpn with an aws EC2 instance and a raspberry-pi.
Required : an aws account, a pi, time


Architecture used for the test


1 server with some client(s).

The server is a EC2 instance t2 micro with 1 vcpu and 1 GIB of ram and 1 EBS volume of 8Gb on ssd.

You can deploy the instance with the web console or with terraform or OpenTofu (opentofu.org) or with python by using Aws SDK for python, Aws Boto3.
You can look at an example of python and Aws Boto3 script at the bottom of this page.

If you are using an EC2 instance on aws you can use the default security group and a create a new Key Pair or use an existing one. If you chose to use an existing one make sure to select them during the launch instances process or in your terraform/OpenTofu or python script.

For raspibian check the page https://www.raspberrypi.com/software/ or https://www.raspberrypi.com/software/operating-systems/

OS : Debian 12 for server. AWS provide an AMI with Debian 12 (HVM). The default user is admin. the last version of rapsibian for the client

Firewall UFW :

If you are using a firewall on the server, we have to open the used udp port for the client :

In this example we use the udp port 51800 and is open.
The command use to open the udp port with UFW is
ufw allow 51800/udp

make sure to reload the rule with the command ufw reload
than use ufw status to make sure the port is open

root@vm:/etc/wireguard# ufw status
Status: active

To Action From
-- ------ ----
22/tcp ALLOW Anywhere
51800/udp ALLOW Anywhere
22/tcp (v6) ALLOW Anywhere (v6)
51800/udp (v6) ALLOW Anywhere (v6)

root@vm:/etc/wireguard#

You can also check the udp port is really open with nmap :
nmap -sU -p 51800 IPSRVWIREGUARD

If the rule as not be applied run this command :
sudo ufw disable
sudo ufw enable

and check again if this step is not complete the client cannot reach the server.

If you want to remove a particular rule in ufw list use this command ufw status numbered
to list rules with number :

root@vm:/etc/wireguard# ufw status numbered
Status: active

To Action From
-- ------ ----
[ 1] 22/tcp ALLOW IN Anywhere
[ 2] 51800/udp ALLOW IN Anywhere
[ 3] 22/tcp (v6) ALLOW IN Anywhere (v6)
[ 4] 51800/udp (v6) ALLOW IN Anywhere (v6)

root@vm:/etc/wireguard# ufw delete 4
Deleting:
allow 51800/udp
Proceed with operation (y|n)? y
Rule deleted (v6)
root@vm:/etc/wireguard# ufw status numbered
Status: active

To Action From
-- ------ ----
[ 1] 22/tcp ALLOW IN Anywhere
[ 2] 51800/udp ALLOW IN Anywhere
[ 3] 22/tcp (v6) ALLOW IN Anywhere (v6)

root@vm:/etc/wireguard#


ANSIBLE :


Ansible is used to update server and raspibian and install required packages.
the playbook for the update/upgrade for the server and the raspberrypi is really basic :

Playbook for the updates :

                    ---
                    - name: update vmtmp
                      hosts: all
                      become: true
                      vars:
                     ansible_python_interpreter: /usr/bin/python3
                      tasks:
                    - debug: var=ansible_host
                        
                    - name: Install Updates for linux distro like debian Ubuntu Linux Mint or Rocky Linux
                      dnf:
                      update_only: yes
                      update_cache: yes
                      when: ansible_distribution == "Rocky"
                        
                    - name: Update apt-get repo and cache
                      package: update_cache=yes force_apt_get=yes cache_valid_time=300
                      when: ansible_distribution in ["Linux Mint", "Debian", "Ubuntu"]
                        
                    - name: Update all packages to their latest version
                      package: upgrade=dist force_apt_get=yes
                      when: ansible_distribution in ["Linux Mint", "Debian", "Ubuntu"]
                        
                    - name: Autoremove no longer required package
                      package: autoremove=yes
                      when: ansible_distribution in ["Linux Mint", "Debian", "Ubuntu"]
                        
                    - name: Check if a reboot is needed for Debian and Ubuntu boxes
                      ansible.builtin.stat:
                      path: /var/run/reboot-required
                      get_checksum: no
                      register: reboot_required_file
                      changed_when: reboot_required_file.stat.exists
                        - debug:
                        var: reboot_required_file.stat.exists
                        
                        - name: Reboot the server if required
                          ansible.builtin.reboot:
                          when: reboot_required_file.stat.exists == true
                    

Playbook for installing the wireguard packages on debian based distro :

                    ---
                    - name: Install Wireguard 
                      hosts: all
                      become: true
                      vars:
                        ansible_python_interpreter: /usr/bin/python3
                          tasks:
                        - debug: var=ansible_host
                        # update repo cache and install packages
                        - name: Update repo cache
                          ansible.builtin.apt:
                            update_cache: yes
                            
                        - name:  install packages for wireguard
                          ansible.builtin.apt:
                            pkg:
                          - wireguard
                          - wireguard-tools
                            
                 
Please pay attention playbook use yaml format, html as possibly altered the spacing


How to Update/upgrade without Ansible :


on server and client simply run the apt command :

sudo apt update
sudo apt upgrade

Reboot if necessary
sudo reboot


How to install if you don't use Ansible :


- For Debian like distro :
on linux debian like distro use the command :

sudo apt install wireguard wireguard-tools

for the server and raspibian client

- For other distro :
Other distro can use dnf snap rpm yum or check the manual of your distro to know how to install a package.

Like this for dnf :

dnf install wireguard-tools


INSTALL SERVER :

- UPDATE THE SERVER :

- fisrt make sure the server is up to date with apt update, apt upgrade and reboot if necessary
or use ansibe and the playabook to do the update.

If you are using ansible the server must be add in the ansible inventory file with all info and sudo
required configuration, for debian AMI the default user is admin for example a EC2 instance in aws :

[aws]
srv-aws ansible_host=publicipinstance ansible_user=admin

the user can sudo without password

- run the playbook for an EC2 instance in aws (the private-key is the generated in aws console) :
ansible-playbook update_os.yml -l srv-aws --private-key ~/.ssh/xxxxxx.pem

  or without Ansible


- use apt with this command (with sudo or as root) :
sudo apt update
than
sudo apt upgrade
reboot if required
sudo reboot

- INSTALL WIREGUARD :

With ansible run the playbook : install_wireguard_debian.yml
- If EC2 instance in aws :
ansible-playbook install_wireguard_debian.yml -l srv-aws --private-key ~/.ssh/xxxxxx.pem

  or without Ansible


- use apt with this command :
sudo apt install wireguard wireguard-tools

In both case he should install wireguard and wireguard-tools

You can check if you have the directory /etc/wireguard/ if not as root you can create the directory


INSTALL ON THE CLIENT :

- UPDATE THE CLIENT :

- fisrt make sure the client is up to date with apt update, apt upgrade and reboot if necessary
or use ansible and the playabook.

If you are using ansible the client must be add in the ansible inventory file with all info and sudo
required configuration , for example a local pi client :

[myclienttest]
client-wg-client ansible_host=iphost ansible_user=theuser

the user can sudo with password

- use ansible playbook
ansible-playbook update_os.yml -l clientnameourip --ask-pass

  or


- use apt with this command (with sudo or as root) :
apt update
than
apt upgrade
reboot if required
sudo reboot

On a PI 4 this step can be really long.

- INSTALL WIREGUARD :

- use ansible playbook
ansible-playbook install_wireguard_debian.yml -l clientnameourip --ask-pass

  or


- use apt with this command :
sudo apt install wireguard wireguard-tools

In both case he should install wireguard and wireguard-tools

You can check if you have the directory /etc/wireguard/ if not as root you can create the directory

CONFIGURE WIREGUARD ON SERVER :

- CREATE THE PRIVATE AND PUBLIC KEY ON SERVER :

On server generate the private and public key by running this command as root in /etc/wireguard :
wg genkey |tee privatekey |wg pubkey > publickey

you must have this result on the server :

root@ip:/etc/wireguard#
root@ip:/etc/wireguard# wg genkey |tee privatekey |wg pubkey > publickey
root@ip:/etc/wireguard# ls -la
total 16
drwx------ 2 root root 4096 Apr 25 16:11 .
drwxr-xr-x 65 root root 4096 Apr 25 15:40 ..
-rw-r--r-- 1 root root 45 Apr 25 16:11 privatekey
-rw-r--r-- 1 root root 45 Apr 25 16:11 publickey
root@ip:/etc/wireguard#

REMEMBER NEVER EVER SHARE OR SHOW THE PRIVATE KEY and set permission to remove any permissions
on the files for users and groups other than root to ensure that only root can acces the private key.

sudo chmod go= privatekey publickey


- CREATE THE WG INTERFACE ON SERVER :

as root (sudo) create a file under /etc/wireguard/wg0.conf
add the interface info

Make sure to use the correct network interface not just eth0
you can check the interfce name with ip route list table main default

[interface]
PrivateKey=theprivatekeypreviuoslycreatedwithwggenkey
Address=10.0.0.2/24
SaveConfig=true
# iptables must be available
# add iptables required rules to allow traffic on wg0 and the network interface could be other than eth0
PostUp=iptables -A FORWARD -i wg0 -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE;
# remove iptables rules when vpn is stopped
PostDown=iptables -D FORWARD -i wg0 -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE;
ListenPort=443 #or any other port like default wireguard port 51820

When done start the wg inerface
wg-quick up wg0

return something like this on aws ec2

[root@ip]# wg-quick up wg0
[#] ip link add wg0 type wireguard
[#] wg setconf wg0 /dev/fd/63
[#] ip -4 address add 10.0.0.1/24 dev wg0
[#] ip link set mtu 8921 up dev wg0
[root@ip]#

check result with wg command and ifconfig or ip a or ip -brief a command

[root@ip wireguard]# ip a
1: lo: mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host noprefixroute
valid_lft forever preferred_lft forever
2: enX0: mtu 9001 qdisc fq_codel state UP group default qlen 1000
link/ether 06:bd:05:55:0a:69 brd ff:ff:ff:ff:ff:ff
altname eni-079431efaba15e462
altname device-number-0.0
inet 172.31.9.232/20 metric 512 brd 172.31.15.255 scope global dynamic enX0
valid_lft 2461sec preferred_lft 2461sec
inet6 fe80::4bd:5ff:fe55:a69/64 scope link
valid_lft forever preferred_lft forever
5: wg0: mtu 8921 qdisc noqueue state UNKNOWN group default qlen 1000
link/none
inet 10.0.0.1/24 scope global wg0
valid_lft forever preferred_lft forever
[root@ip wireguard]#

- CREATE THE PRIVATE AND PUBLIC KEY ON CLIENT :

On client generate the private and public key by running this command as root in /etc/wireguard :

wg genkey |tee privatekey |wg pubkey > publickey

you must have this result on the client :

root@testpidev:/etc/wireguard#
root@testpidev:/etc/wireguard# wg genkey |tee privatekey |wg pubkey > publickey
root@testpidev:/etc/wireguard# ls -la
total 24
drwx------ 2 root root 4096 Apr 25 12:27 .
drwxr-xr-x 137 root root 12288 Apr 25 12:07 ..
-rw-r--r-- 1 root root 45 Apr 25 12:27 privatekey
-rw-r--r-- 1 root root 45 Apr 25 12:27 publickey
root@testpidev:/etc/wireguard#

REMEMBER NEVER EVER SHARE OR SHOW THE PRIVATE KEY and set permission to remove any permissions
on the files for users and groups other than root to ensure that only root can acces the private key.

sudo chmod go= privatekey publickey


- CREATE THE WG INTERFACE ON CLIENT :

as root (sudo) create a file uder /etc/wireguard/wg0.conf

[interface]
PrivateKey=sdsdfasdfasdfadsfasdfasdfadsf
Address=10.0.0.3/24
SaveConfig=true

[Peer]
# publickey of the public interface of the server
PublicKey=kljsalfdkjga;gj;alksfgl;akfsg
# endpoint is wireguard vpn server public ip check on the server
# and the port number set in the server like 443 or 51820
Endpoint=xxx.xxx.xxx.xxx:port
# specify the ip or all traffic, in this case we send all traffic to the server even web traffic
# because we need to control this client even update. Web traffic can be routed via the server with ip-forwarding
# set to 1 if it's really necessary
AllowedIPs=0.0.0.0/0
PersistentKeepalive=20

start the interface as root with the command wg-quick up wg0

we should see something like this on the client :

root@raspberrypi:/etc/wireguard# wg-quick up wg0
[#] ip link add wg0 type wireguard
[#] wg setconf wg0 /dev/fd/63
[#] ip -4 address add 10.0.0.2/24 dev wg0
[#] ip link set mtu 1420 up dev wg0
[#] wg set wg0 fwmark 51820
[#] ip -4 route add 0.0.0.0/0 dev wg0 table 51820
[#] ip -4 rule add not fwmark 51820 table 51820
[#] ip -4 rule add table main suppress_prefixlength 0
[#] sysctl -q net.ipv4.conf.all.src_valid_mark=1
[#] nft -f /dev/fd/63
root@raspberrypi:/etc/wireguard#

check the status of the interface with sudo wg

root@raspberrypi:/etc/wireguard# wg
interface: wg0
public key: SlPQ1Bn1kZl9L/yZPLgx6yRcGTM6CYedQw1fNzycyAc=
private key: (hidden)
listening port: 50047
fwmark: 0xca6c

peer: OfCL3SxQkrFxvz8OXflTWGFBM6iyaIvK525XqS4mUm8=
endpoint: 3.99.221.82:443
allowed ips: 0.0.0.0/0
transfer: 0 B received, 296 B sent
persistent keepalive: every 20 seconds
root@raspberrypi:/etc/wireguard#

As root or with sudo, now we must copy the publickey of this client into the server with this command :

wg set wg0 peer keykeykeyekeykeykeykeykeykeykey allowed-ips 10.0.0.2/24

on the client check if the connection is available

root@raspberrypi:/etc/wireguard# wg
interface: wg0
public key: SlPQ1Bn1kZl9L/yZPLgx6yRcGTM6CYedQw1fNzycyAc=
private key: (hidden)
listening port: 50047
fwmark: 0xca6c

peer: OfCL3SxQkrFxvz8OXflTWGFBM6iyaIvK525XqS4mUm8=
endpoint: 3.99.221.82:443
allowed ips: 0.0.0.0/0
latest handshake: 5 seconds ago
transfer: 4.34 KiB received, 9.51 KiB sent
persistent keepalive: every 20 seconds
root@raspberrypi:/etc/wireguard#

root@raspberrypi:/etc/wireguard# ping 10.0.0.1
PING 10.0.0.1 (10.0.0.1) 56(84) bytes of data.
64 bytes from 10.0.0.1: icmp_seq=1 ttl=127 time=17.8 ms
64 bytes from 10.0.0.1: icmp_seq=2 ttl=127 time=15.9 ms
64 bytes from 10.0.0.1: icmp_seq=3 ttl=127 time=25.3 ms

--- 10.0.0.1 ping statistics ---
4 packets transmitted, 3 received, 25% packet loss, time 3005ms
rtt min/avg/max/mdev = 15.850/19.638/25.281/4.067 ms
root@raspberrypi:/etc/wireguard#


Stop - start the wg0 interface on the client and server manually :

as root (sudo)
wg-quick down wg0
wg-quick up wg0

or with systemctl to get your connection to the server at reboot

root@dev:/etc/wireguard# systemctl enable wg-quick@wg0.service
Created symlink /etc/systemd/system/multi-user.target.wants/wg-quick@wg0.service → /lib/systemd/system/wg-quick@.service.
root@dev:/etc/wireguard#


Test if port is open with nmap :


nmap -sU -p 51820 WGIPSRV

AWS SDK Boto3 simple script example to create an EC2 instance :

import boto3
import boto3.session
import sys
import datetime
from datetime import datetime


# if you have different env in your aws config file. ARG to get env DEV or PROD
print('DEBUG number of arg :', len(sys.argv), 'args')
print('Arg list is :', str(sys.argv))
print('Arg0 list is :', str(sys.argv[0]))



# THE REGION
AWS_REGION = "ca-central-1"

# Specify the parameters for the instance
image_id = 'ami-xxxxxxxxxxxxx'  # AMI ID for Debian 12 (HVM), SSD Volume Type
instance_type = 't2.micro'
key_name = 'key-pair'  # key pair name used for the test
security_group_ids = ['sg-asecuritygroup'] # my sg with only ssh https from my ip
monitoring_status = {'Enabled': False}
instance_name = 'srv_name'
iops = 3000 # int
vol_Size = 8 # int
vol_Type = 'gp3'
Thput  = 125 # int


ec2 = boto3.resource('ec2', region_name=AWS_REGION)

instances = ec2.create_instances(
	BlockDeviceMappings=[
		{
		'Ebs': {
			'DeleteOnTermination': True,
			'Iops': iops,
			'VolumeSize': vol_Size,
			'VolumeType': vol_Type,
			'Throughput': Thput,
			'Encrypted': False,
			},
		'DeviceName': '/dev/xvda',
		}
	],
	ImageId=image_id,
	MinCount=1,
	MaxCount=1,
	InstanceType=instance_type,
	KeyName=key_name,
	SecurityGroupIds=security_group_ids,
	Monitoring=monitoring_status,
	TagSpecifications=[
        {
            'ResourceType': 'instance',
            'Tags': [
                {
                    'Key': 'Name',
                    'Value': instance_name
                }
            ]
        }
    ]
)

# Get the instance ID
print(instances)