Setup Wireguard VPN Server and Client in Ubuntu 20.04

This a guide on how to setup Wireguard VPN on Ubuntu and setting up a Wireguard client.

Requirements:

1. Ubuntu Server 20.04 used in my lab. (20.04 or higher is required for Policy routing)

2. Ubuntu Client (Ubuntu 20.04)

3. Root access to the server.

4. Network Access

Note: This should also work on Linux Mint 20.04

Setting up the Wireguard Server

Login to the In my lab, I have set up a EC2 instance and below is the current IP configuration before setting up Wireguard.

[email protected]:~# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> 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 
       valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9001 qdisc fq_codel state UP group default qlen 1000
    link/ether 02:ca:92:5f:0e:80 brd ff:ff:ff:ff:ff:ff
    inet 172.31.20.229/20 brd 172.31.31.255 scope global dynamic eth0
       valid_lft 2617sec preferred_lft 2617sec
    inet6 fe80::ca:92ff:fe5f:e80/64 scope link 
       valid_lft forever preferred_lft forever

From above, I have a single interface with IP 172.31.20.229 assigned to eth0.

sudo apt update && sudo apt upgrade -y
sudo apt install wireguard -y

-Switch to root and run the following:

sudo su –

Below are the default permissions on the wireguard dir:

[email protected]:~# ls -l /etc/ | grep wireguard
drwx------ 2 root root       4096 Aug  4  2020 wireguard

-You could set permissions to the directory as follows:

chmod 0700 /etc/wireguard/
[email protected]:~# ls -l /etc/ | grep wireguard
drwx------ 2 root root       4096 Aug  4  2020 wireguard

To check the version of Wireguard installed:

[email protected]:/etc/wireguard# wg --version
wireguard-tools v1.0.20200513 - https://git.zx2c4.com/wireguard-tools/

-Generate public and private key pairs:

cd /etc/wireguard/
umask 077; wg genkey | tee privatekey | wg pubkey > publickey

This should generate the private and the public key:

[email protected]:/etc/wireguard# ls -l
total 8
-rw------- 1 root root 45 Jun 30 20:23 privatekey
-rw------- 1 root root 45 Jun 30 20:23 publickey

-Take a note of the private key “privatekeycat privatekey . You will need to add this to the WG server’s conf file.

Setting up the Wireguard Server’s configuration file

vim /etc/wireguard/wg0.conf

Add below content. (Here, I chose the IP as 192.168.6.1 which is the new VPN private address that will be assigned to the interface)

[Interface]
## My VPN server private IP address ##
Address = 192.168.6.1
 
## My VPN server port ##
ListenPort = 41194
 
## VPN server's private key i.e. string from /etc/wireguard/privatekey ##
PrivateKey = ADD_PRIVATE_KEY_HERE

-Allow the port in the Server’s Firewall:

[email protected]:~# sudo ufw allow 41194/udp
Rules updated
Rules updated (v6)

-To check the status:

sudo ufw status

– Enable wireguard service on boot on the server and start the service:

[email protected]:~$ sudo systemctl enable [email protected]
Created symlink /etc/systemd/system/multi-user.target.wants/[email protected] → /lib/systemd/system/[email protected]

[email protected]:~$ sudo systemctl start [email protected]

To check the status of the wireguard service, use the following:

[email protected]:~# sudo systemctl status [email protected]
[email protected] - WireGuard via wg-quick(8) for wg0
     Loaded: loaded (/lib/systemd/system/[email protected]; enabled; vendor preset: enabled)
     Active: active (exited) since Thu 2022-06-30 21:29:01 UTC; 8min ago
       Docs: man:wg-quick(8)
             man:wg(8)
             https://www.wireguard.com/
             https://www.wireguard.com/quickstart/
             https://git.zx2c4.com/wireguard-tools/about/src/man/wg-quick.8
             https://git.zx2c4.com/wireguard-tools/about/src/man/wg.8
    Process: 2230 ExecStart=/usr/bin/wg-quick up wg0 (code=exited, status=0/SUCCESS)
   Main PID: 2230 (code=exited, status=0/SUCCESS)

Jun 30 21:29:01 ip-172-31-20-229 systemd[1]: [email protected]: Succeeded.
Jun 30 21:29:01 ip-172-31-20-229 systemd[1]: Stopped WireGuard via wg-quick(8) for wg0.
Jun 30 21:29:01 ip-172-31-20-229 systemd[1]: Starting WireGuard via wg-quick(8) for wg0...
Jun 30 21:29:01 ip-172-31-20-229 wg-quick[2230]: [#] ip link add wg0 type wireguard
Jun 30 21:29:01 ip-172-31-20-229 wg-quick[2230]: [#] wg setconf wg0 /dev/fd/63
Jun 30 21:29:01 ip-172-31-20-229 wg-quick[2230]: [#] ip -4 address add 192.168.6.1/24 dev wg0
Jun 30 21:29:01 ip-172-31-20-229 wg-quick[2230]: [#] ip link set mtu 8921 up dev wg0
Jun 30 21:29:01 ip-172-31-20-229 systemd[1]: Finished WireGuard via wg-quick(8) for wg0.

Checking the ifconfig output, you would see a new interface wg0 is created automatically which is expected.

[email protected]:~# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> 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 
       valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9001 qdisc fq_codel state UP group default qlen 1000
    link/ether 02:ca:92:5f:0e:80 brd ff:ff:ff:ff:ff:ff
    inet 172.31.20.229/20 brd 172.31.31.255 scope global dynamic eth0
       valid_lft 2235sec preferred_lft 2235sec
    inet6 fe80::ca:92ff:fe5f:e80/64 scope link 
       valid_lft forever preferred_lft forever
5: wg0: <POINTOPOINT,NOARP,UP,LOWER_UP> mtu 8921 qdisc noqueue state UNKNOWN group default qlen 1000
    link/none 
    inet 192.168.6.1/24 scope global wg0
       valid_lft forever preferred_lft forever

– You can check wireguard information/stats using the below command:

[email protected]:~$ sudo wg
interface: wg0
  public key: pHrkGojLiNZy2GwshmdEXMaaOmowXXXXXXXXXXXXXXX=
  private key: (hidden)
  listening port: 41194

Configuring the VPN Client

  • Login to the client and install Wireguard.
sudo apt install wireguard -y

– Create the configuration file

[email protected]:~# sudo sh -c 'umask 077; touch /etc/wireguard/wg0.conf'

[email protected]:~# ls -l /etc/wireguard/wg0.conf 
-rw------- 1 root root 0 Jun 30 20:58 /etc/wireguard/wg0.conf
  • Create a key pair in the client

– In the client machine, create a key pair:

[email protected]:~# cd /etc/wireguard/

[email protected]:/etc/wireguard# umask 077; wg genkey | tee privatekey | wg pubkey > publickey

[email protected]:/etc/wireguard# ls -l 
total 8
-rw------- 1 root root 45 Jun 30 21:01 privatekey
-rw------- 1 root root 45 Jun 30 21:01 publickey
-rw------- 1 root root  0 Jun 30 20:58 wg0.conf
[email protected]:/etc/wireguard# 

– Take a note of the client’s public key. (This will be added in the server’s config later)

-Take a note of the private key from the client. This will be added in its own config file.

cat privatekey

– On the client, create the wireguard config file as below:

[Interface]
## Add the client's private key which is from /etc/wireguard/publickey ##
PrivateKey = CLIENT_PRIVATE_KEY_HERE
 
## Client ip address that will be set by this Client ##
Address = 192.168.6.2/24
  
[Peer]
## Ubuntu 20.04 server public key ##
PublicKey = SERVER_PUBLIC_KEY_HERE
 
## set ACL ##
AllowedIPs = 192.168.2.0/24
  
## Your Ubuntu 20.04 LTS server's public IPv4/IPv6 address and port ##
Endpoint = PUBLIC_IP_OF_YOUR_WIREGUARD_SERVER:41194
   
##  Key connection alive ##
PersistentKeepalive = 15

-On the client, enable and start the Wireguard service:

[email protected]:/etc/wireguard# sudo systemctl enable [email protected]
Created symlink /etc/systemd/system/multi-user.target.wants/[email protected] -> /lib/systemd/system/[email protected]

[email protected]:/etc/wireguard# sudo systemctl start [email protected]

– Check the status of the service in the client:

[email protected]:~# sudo systemctl status [email protected]
* [email protected] - WireGuard via wg-quick(8) for wg0
     Loaded: loaded (/lib/systemd/system/[email protected]; enabled; vendor preset: enabled)
     Active: active (exited) since Thu 2022-06-30 21:35:17 UTC; 5min ago
       Docs: man:wg-quick(8)
             man:wg(8)
             https://www.wireguard.com/
             https://www.wireguard.com/quickstart/
             https://git.zx2c4.com/wireguard-tools/about/src/man/wg-quick.8
             https://git.zx2c4.com/wireguard-tools/about/src/man/wg.8
    Process: 123 ExecStart=/usr/bin/wg-quick up wg0 (code=exited, status=0/SUCCESS)
   Main PID: 123 (code=exited, status=0/SUCCESS)
        CPU: 28ms

Jun 30 21:35:17 wg-client systemd[1]: Starting WireGuard via wg-quick(8) for wg0...
Jun 30 21:35:17 wg-client wg-quick[123]: [#] ip link add wg0 type wireguard
Jun 30 21:35:17 wg-client wg-quick[123]: [#] wg setconf wg0 /dev/fd/63
Jun 30 21:35:17 wg-client wg-quick[123]: [#] ip -4 address add 192.168.6.2/24 dev wg0
Jun 30 21:35:17 wg-client wg-quick[123]: [#] ip link set mtu 1420 up dev wg0
Jun 30 21:35:17 wg-client systemd[1]: Finished WireGuard via wg-quick(8) for wg0.

-From the above output, we can see that the wireguard service has created the interface wg0 and assigned the IP 192.168.6.2/24 to it. You could also verify this by checking by checking the device ip conf as below:

[email protected]:~# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> 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 
       valid_lft forever preferred_lft forever
2: [email protected]: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether aa:3c:37:57:21:8a brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 192.168.1.143/24 brd 192.168.1.255 scope global dynamic eth0
       valid_lft 86010sec preferred_lft 86010sec
    inet6 fe80::a83c:37ff:fe57:218a/64 scope link 
       valid_lft forever preferred_lft forever
3: wg0: <POINTOPOINT,NOARP,UP,LOWER_UP> mtu 1420 qdisc noqueue state UNKNOWN group default qlen 1000
    link/none 
    inet 192.168.6.2/24 scope global wg0
       valid_lft forever preferred_lft forever

So far, we can configured the client to talk to the server. But the Server does not know about the client. So, next we need to update the Server’s Wireguard configuration file with the details of the wireguard client.

-Login to the Wireguard Server and add the below block to the server’s wireguard conf:

[Peer]
## Desktop/client VPN public key ##
PublicKey = CLIENT_PUB_KEY_HERE

## client VPN IP address (note  the /32 subnet) ##
AllowedIPs = 192.168.6.2/32

-So, your Wireguard server’s configuration file will be as follows:

[Interface]
## My VPN server private IP address ##
Address = 192.168.6.1
 
## My VPN server port ##
ListenPort = 41194
 
## VPN server's private key i.e. /etc/wireguard/privatekey ##
PrivateKey = ADD_PRIVATE_KEY_HERE

[Peer]
## Desktop/client VPN public key ##
PublicKey = CLIENT_PUB_KEY_HERE

## client VPN IP address (note  the /32 subnet) ##
AllowedIPs = 192.168.6.2/32

– Start the service again on the server:

sudo systemctl start [email protected]

Verify connectivity from the client => server:

– If the server is in the cloud, then update the security groups tallow the port.

– From the client, ping the server 192.168.6.1

[email protected]:~# ping 192.168.6.1
PING 192.168.6.1 (192.168.6.1) 56(84) bytes of data.
64 bytes from 192.168.6.1: icmp_seq=1 ttl=64 time=81.9 ms
64 bytes from 192.168.6.1: icmp_seq=2 ttl=64 time=82.5 ms
^C
--- 192.168.6.1 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1001ms
rtt min/avg/max/mdev = 81.886/82.172/82.458/0.286 ms

Checking active connections from Wireguard server:

– To see which clients are connected to the server and the statistics, you can run the below:

[email protected]:~# sudo wg
interface: wg0
  public key: pHrkGojLiNZy2GwshmdEXMaaOmowXXXXXXXXXXXXXXX=
  private key: (hidden)
  listening port: 41194

peer: 8Zp7Cji5Aseew3L0P3c35sUzJNIPYYYYYYYYYYYYYYY=
  endpoint: 1.2.3.4:33395
  allowed ips: 192.168.6.2/32
  latest handshake: 1 minute, 12 seconds ago
  transfer: 3.94 KiB received, 1.47 KiB sent

 

Additional Information:

For debugging issue with wireguard, you could check the logs:

sudo journalctl -eu [email protected]

Here is a little cronjob to monitor the tunnel via ping and restart tunnel: (Credits to linuxbabe)

sudo crontab -e

-Add the below:

SHELL=/bin/bash
* * * * * for ((i=1; i<=6; i++)) do (ping -c9 192.168.6.1 > /dev/null || systemctl restart [email protected]) done

Hope this helps! Cheers!

Sources/References:

https://www.cyberciti.biz/faq/ubuntu-20-04-set-up-wireguard-vpn-server/

Set Up Your Own WireGuard VPN Server on Ubuntu 22.04/20.04/18.04

Hexadecimal basics using basic Linux utilities

This is short guide on how to convert strings and decimal values to hexadecimal and vice-versa using simple Linux utilities such as xxd and printf.

  1. To convert a string to hexadecimal, you can use xxd in Linux.

For example: To convert a string “kali” to hexadecimal, you can use the below format.

[email protected]:~$ echo -n kali | xxd
00000000: 6b61 6c69 kali

To group and display the output a single character at a time, use -c  flag with argument 1.

[email protected]:~$ echo -n kali | xxd -c1
00000000: 6b k
00000001: 61 a
00000002: 6c l
00000003: 69 i

This means the following:

00000000: 6b k <- k is a single character and its hexadecimal value is 6b
00000001: 61 a <- a is a single character and its hexadecimal value is 61
00000002: 6c l <- l is a single character and its hexadecimal value is 6c
00000003: 69 i <- i is a single character and its hexadecimal value is 69

2. Convert Hexadecimal value back to string:

[email protected]:~$ echo -n "6b61 6c69" | xxd -r -p
kali

Dont worry about the spaces, it should still work.

[email protected]:~$ echo -n "6b616c69" | xxd -r -p
kali[email protected]:~$

3. Convert decimal (number) to hexadecimal

-Lets say you want to convert number 12 to decimal value. To do so, you could use printf as shown below.

[email protected]:~$ printf "%x\n" 12
c

From above output, the hexadecimal value for number 12 (aka decimal 12) is character c.

To find hexadecimal values for values from 1 to 255, you could run through it in a loop

for num in {1..255}; do printf "%x\n" $num ; done | less

Hope these help.

PS: Knowing hexadecimal does come in handy while learning/debugging different protocols.

How to fix “Error opening terminal: xterm-termite” when trying to SSH to a remote host

I am using “termite” on my ArchLinux machine but when I try to SSH to a remote linux machine(Ubuntu) to run some commands, it throws me an error “Error opening terminal: xterm-termite“. This a post on how to fix it.

Quick Fix:

If you are already SSH’ed into the remote machine and you see this issue, you could update the TERM variable on the remote system: (Run on remote system)

export TERM=xterm-256color

Permanent Fix:

The permanent fix is to edit your local ~/.bashrc file to include the following:

if [ "$TERM" = xterm ]; then
TERM=xterm-256color;
fi
export TERM=xterm-256color

In my case, I had to add it to my Arch Linux’s ~/.bashrc file. (i.e not on the remote Ubuntu machine that I am connecting to)

Here is a screenshot from my box: (Right click image and open in new team to view in full screen)

arch linux termite i3-gaps

To verify its fixed, open a new terminal (or source ~/.bashrc again) and SSH into the remote machine. Ideally this should be fixed.

Hope this helps!

Note: If you terminal does not support 256-color, then you may need to change the TERM variable to “xterm-color” instead of “xterm-256color”.

Credits/References:

Github

Mount TrueNAS Core Samba share on Linux

This is a guide that describes on how to mount a remote Samba share configured on TrueNAS on to a Linux machine.

 

Login in your Linux machine. (I am using a Linux Mint 19.3 in this demo. This should technically work on other Debian/Ubuntu based systems as well).

Use the following commands to get your current user’s user ID (UID) and group ID (GID) respectively.

id -u $USER
id -G $USER

Create a file /etc/.truenas_creds. This is where you would store the samba credentials.

Replace text in red with the username and password of the remote SMB share which was configured in TrueNas.

cat /etc/.truenas_creds
username=enter_username_here
password=enter_password_here

Modify the file permissions so that root is the owner and set the file permission to 600.

sudo chown root: /etc/.truenas_creds
sudo chmod 600 /etc/.truenas_creds

In your linux machine, create a folder to where you want the contents of the remote samba share to be mounts. For example: create a directory named /mnt/truenas/.

sudo mkdir /mnt/truenas/

-Below is a sample syntax that can be used for populating /etc/fstab.

//ip-of-nas-server/enter-remote-samba-share/location /enter-local-mount/location/here/ cifs credentials=/etc/.truenas_creds,iocharset=utf8,uid=enter_your_uid_here,gid=enter_your_gid_here,noperm 0 0

-Here is what that I added in /etc/fstab.

//192.168.1.12/mnt/truenas /mnt/truenas/ cifs credentials=/etc/.truenas_creds,iocharset=utf8,uid=1000,gid=1000,noperm 0 0

My TrueNAS server’s IP => 192.168.1.12

Remote samba share => /mnt/truenas

Local mount location => /mnt/truenas/

Credentials for samba share => /etc/.truenas_creds

-Once complete, run the following to mount all entries looking at /etc/fstab.

mount -a

-If there are no errors in the above command, check your local mount path to verify that the mount was successful.

ls -l /mnt/truenas/

References:

linuxize

Askubuntu

Bash script to loop through values in a file with space as a separator

Lets say we have a file with list of IPs that are space separated and you want to read each of the values to pass to a loop to perform an operation. Here is an example file with IP Addresses separated  by a space:

cat ips.txt
192.168.1.1 192.168.1.10

Now, lets say you want to loop through these IPs and run a ping command against each of them.

cat ping.sh
#!/bin/bash

# IFS is an internal bash variable. Here, we set its value as space.
IFS=$" "
# Read the file "ips.txt" and store the list of values to a variable "ips"
ips="$(cat ips.txt)"

# Run the following loop which will loop through each of the ips and run a ping test
for ip in $ips; do ping -c 1 $ip; done
# Unset the IFS variable so that it wont mess with the reset of the script
unset IFS

-Running this loop, will loop through the list of IP addresses and perform a ping.

./ping.sh
PING 192.168.1.1 (192.168.1.1) 56(84) bytes of data.
64 bytes from 192.168.1.1: icmp_seq=1 ttl=64 time=0.660 ms

--- 192.168.1.1 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.660/0.660/0.660/0.000 ms
PING 192.168.1.10 (192.168.1.10) 56(84) bytes of data.
64 bytes from 192.168.1.10: icmp_seq=1 ttl=64 time=0.108 ms

--- 192.168.1.10 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.108/0.108/0.108/0.000 ms

Hope this helps!

Happy scripting folks! 🙂

Source/References: Link

Run bash script from a Perl script

To run a bash script (Example: bash-script.sh) from inside a perl script, you could use the following syntax:

system("sh", "bash-script.sh")

Note: Here, once the bash script completes execution it will continue with the execution of the perl script.

Example:

Perl Script: perl-script.pl
Bash Script: bash-script.sh

Below is a perl script  “perl-script.pl” which calls an external bash script “bash-script.sh”.

#!/usr/bin/perl
use strict;
use warnings;

print "Running parent perl script. \n";
print "Starting to call external bash script\n";

# Sample Argument to be passed to the bash script
my $my_arg = "ARG1";

# With arguments - pass them inside quotes seperated by commas 
system("sh", "bash-script.sh","$my_arg");

print "Back to parent perl script\n";

Below is the sample “bash-script.sh” which prints the variable.

#!/bin/bash
echo "---Start of Bash script---"

a=$1
echo "Argument from Perl script is" $a

To test, execute the perl script:

./perl-script.pl

 

Credits/References
https://stackoverflow.com/questions/3200801/how-can-i-call-a-shell-command-in-my-perl-script

How to fix print_req_error: I/O error, dev fd0, sector 0 error

After a fresh install of Ubuntu, my terminal was being flooded with “print_req_error: I/O error, dev fd0, sector 0” error.

dev fd0

This is because, your kernel thinks you have a floppy disk fd0, but cant find one. To fix this issue, you can run the following in your terminal:

sudo rmmod floppy
echo "blacklist floppy" | sudo tee /etc/modprobe.d/blacklist-floppy.conf
sudo dpkg-reconfigure initramfs-tools

EDIT: Thanks @Joanmi for your comment (For the noticing the issue with sudo command.) 

Misc: If you are deploying a new virtual machine, you can avoid this issue by deleting the Floppy Disk drive.

Source: StackOverflow

View progress when using dd command

While using “dd”, by default it does not show the progress nor status of the transfer. However, you could use the flag “status=progress” to show the status/progress of the transfer. Here is a screenshot:

This flag is available in the newer version of dd. Here are the CLI outputs for the text ninjas:

$ sudo dd if=archlinux-2019.06.01-x86_64.iso bs=4M of=/dev/sdd status=progress oflag=sync
641728512 bytes (642 MB, 612 MiB) copied, 16 s, 39.1 MB/s
153+1 records in
153+1 records out
643825664 bytes (644 MB, 614 MiB) copied, 16.4601 s, 39.1 MB/s

PS: Use dd (data duplicator) with caution. ‘ddis also known as disk destroyer  in an alternate universe.

Regards,
ΞXΤЯ3МΞ

Check partition information in Linux

To show currently mounted partition in human readable format, use:

df -h

df -h sample output screenshot

Another way to check partition information using parted.

sudo parted /dev/sda print

parted sample output screenshot

Here, we can see that the disk size is 120GB along with the partition information.

To view the list of partitions using fdisk, use:

fdisk -l

To view the list of block devices:

lsblk

Hope this helps! Cheers 🙂