Mountain%20Landscape_edited_edited.jpg
  • Hannah Lee

Personal VPN Setup with WireGuard on CentOS

This tutorial will walk you through a WireGuard VPN server installation with ClamAV to keep your server clean. This server will have cron jobs running routinely to keep your packages updated and your server scanned for viruses. This will be very similar to my OpenVPN tutorial, but WireGuard has a much easier setup.

Before we start, here's a quick snapshot of just how much faster WireGuard is over OpenVPN:

(Test courtesy of speedtest.net)

Overall, the upload speeds were both pretty awful, but WireGuard is definitely the undisputed winner for download speed.


STARTING CONFIGURATION:



Step 1: Update and Install


a. Login to your root account.



b. Update packages:

yum -y update

c. Install packages:

yum install epel-release https://www.elrepo.org/elrepo-release-7.el7.elrepo.noarch.rpm
yum install nano kernel-headers yum-plugin-elrepo firewalld
yum install kmod-wireguard wireguard-tools 


Step 2: Configure WireGuard


a. Make WireGuard directories:

mkdir -p /etc/wireguard/client/keys /etc/wireguard/client/conf

b. Generate server keys:

wg genkey | tee /etc/wireguard/server_private.key | wg pubkey | tee /etc/wireguard/server_public.key

You'll see the server public key as output if successful. Copy the server_private.key somewhere. You'll need it for the next step.


c. Create the server configuration file:

nano /etc/wireguard/wg0.conf

Paste the following in the file:

[Interface]
Address = 10.10.10.1/24
ListenPort = 51820
PrivateKey = SERVER_PRIVATE_KEY

- Replace SERVER_PRIVATE_KEY with the contents of /etc/wireguard/server_private.key).

- "ListenPort" is the port we'll be running WireGuard on. "Address" is the subnet of your VPN network. If you change either of these variables, ensure you also update all applicable sections in the gen-wg-client script in Step 3.



Step 3: Generate Clients



a. Create script file:

nano /usr/local/bin/gen-wg-client

Paste the following in the file:

#!/bin/bash

#*****MUST CHANGE***REPLACE WITH YOUR PUBLIC IP*****
PUBLICIP="0.0.0.0"

#Optional; this is your VPN DNS server. Set to your server's VPN IP (e.g.
#10.10.10.1) if you are running DNSCrypt-Proxy (or another resolver) on
#this server.
DNS="1.1.1.1"

#Optional; update your WireGuard port here if you are using a non-standard port.
WGPORT=51820

#Optional; This is the prefix to your client .conf file names. Leave as "" if undesired.
SERVERNAME=""
LASTCLIENTIP=$(grep AllowedIPs /etc/wireguard/wg0.conf | tail -1 |sed -e 's/AllowedIPs = 10.10.10.\(.*\)\/32/\1/')

NEXTIP=$((LASTCLIENTIP+1))

# Ensuring the next assign IP is not 10.10.10.1
if [[ $NEXTIP == 1 ]]; then
        NEXTIP=$((NEXTIP+1))
else
        :
fi

CLIENTIP="10.10.10."$NEXTIP

echo "Client Name: "
read clientname

echo "The static IP for $clientname will be $CLIENTIP"

# Generating keys for new client

privatekey=$clientname"_private.key"
publickey=$clientname"_public.key"
wg genkey | sudo tee /etc/wireguard/client/keys/$privatekey | wg pubkey | sudo tee /etc/wireguard/client/keys/$publickey > /dev/null

echo "Successfully created keys."

# Adding new client keys in wg0.conf
printf "\n\n[Peer]" >> /etc/wireguard/wg0.conf
printf "\nPublicKey = $(cat /etc/wireguard/client/keys/$publickey)" >> /etc/wireguard/wg0.conf
printf "\nAllowedIPs = $CLIENTIP/32" >> /etc/wireguard/wg0.conf

echo "Successfully added client to server."

# Generating client config file
confname="$SERVERNAME$clientname.conf"
touch /etc/wireguard/client/conf/$confname
printf "[Interface]" >> /etc/wireguard/client/conf/$confname
printf "\nAddress = $CLIENTIP/24" >> /etc/wireguard/client/conf/$confname
printf "\nDNS = $DNS" >> /etc/wireguard/client/conf/$confname
printf "\nPrivateKey = $(cat /etc/wireguard/client/keys/$privatekey)" >> /etc/wireguard/client/conf/$confname
printf "\n\n[Peer]" >> /etc/wireguard/client/conf/$confname
printf "\nPublicKey = $(cat /etc/wireguard/server_public.key)" >> /etc/wireguard/client/conf/$confname
printf "\nAllowedIPs = 0.0.0.0/0" >> /etc/wireguard/client/conf/$confname
printf "\nEndpoint = $PUBLICIP:$WGPORT" >> /etc/wireguard/client/conf/$confname
printf "\nPersistentKeepalive = 25" >> /etc/wireguard/client/conf/$confname

echo "The private key is located at /etc/wireguard/client/keys/$privatekey"
echo "The public key is located at /etc/wireguard/client/keys/$publickey"
echo "The client configuration file is located at /etc/wireguard/client/conf/$confname"

- Update the PUBLICIP variable ("0.0.0.0") with your public IP.

- Update the DNS variable with your preferred DNS server. I highly recommend using a secure DNS solution such a DNSCrypt-Proxy.

- Update the WGPORT variable if you have changed the WireGuard port in wg0.conf

- Update all mentions of "10.10.10" if you are changing the subnet

- "AllowedIPs" set to 0.0.0.0/0 means that all of your internet traffic is sent through this VPN. Update the IP's here if this is undesired.


Modify this script to be a template for your client configurations. Individual client changes can be done to the individual configuration files at /etc/wireguard/client/conf.


b. Add executable permissions to the script:

chmod 755 /usr/local/bin/gen-wg-client

c. Generate a client:

gen-wg-client

This script will prompt you for the name of your client, generate the public and private keys, assign the client a static IP and add client to wg0.conf, then generate the client's configuration file in /etc/wireguard/client/conf.



Step 4: Update System Configurations



a. Start and enable firewalld:

systemctl start firewalld
systemctl enable firewalld

b. Add configurations:


firewall-cmd --add-port=51820/udp --zone=public --permanent

(or whatever port you chose for WireGuard)

firewall-cmd --add-interface=wg0 --zone=public --permanent
firewall-cmd --add-masquerade --zone=public --permanent
firewall-cmd --reload

NOTE: If you have external firewalls (e. g. on router or cloud server), ensure you add your WireGuard port there as well.


c. Enable port forwarding in sysctl.conf:

nano /etc/sysctl.conf

Add the following to the top of the file:

net.ipv4.ip_forward = 1

Restart the network service.

systemctl restart network.service


Step 5: Start and Test WireGuard



a. Start and enable WireGuard:

systemctl start wg-quick@wg0.service
systemctl enable wg-quick@wg0.service

b. Ensure the service is active and running:

systemctl status wg-quick@wg0.service

NOTE: If you get a 'Cannot find device "wg0"' error, restart your server. You installed "kernel-headers" in step 1 and you need to restart to apply the kernel headers. Restarting is unnecessary if your system came with updated kernel headers and you have successfully started the wg0 server.



c. Download the WireGuard client application to your client here:

https://www.wireguard.com/install/


d. Download your client configuration file from /etc/wireguard/client/conf and import to the application. Activate your connection!




Step 6: Install Antivirus Software and Add Cron Jobs


NOTE: ClamAV is a free, opensource antivirus software solution, but it's not perfect. If you have a preferred alternative, feel free to use that and skip this step. Antivirus software has a significant overhead, but it's important --especially if you have different users connecting to your VPN whose devices you can't control.


a. Install ClamAV:

yum install clamav

b. Update antivirus signatures:

freshclam

c. Test clamscan:

clamscan -r /home

This scans the home directory recursively and return a report on the files scanned.


d. Make log directory for clamscan:

mkdir /var/log/clamscan

e. Add cron jobs:

***This must be done on the root account so that all files can be scanned***

crontab -e

Add the following lines:


###################################################################
#THESE JOBS SCHEDULE ROUTINE UPDATES AND SCANS TO MAKE THE MOST
#EFFECTIVE USE OF LIMITED MEMORY TO AVOID MEMORY ALLOCATION ERRORS. 
#YOU MAY NEED TO SPLIT UP SCANS FURTHER DEPENDING ON THE LOAD
#ON YOUR SERVER. CLAMAV IS NOT A 100% SOLUTION, BUT SCHEDULING
#ROUTINE SCANS THAT SOMETIMES FAIL IS BETTER THAN NOT SCANNING AT ALL.
###################################################################

# Updates all packages every Monday at 1:01 AM
1 1 * * 1 yum -y update; echo "$(date) UPDATED" >> /var/log/update.log

# Runs antivirus scans every day at 2 AM. The / directory is split up into 
# seven days, so the entire / directory is scanned once a week.

# Delete "--remove" if you want to review the files to ensure they are infected before removal

1 2 * * 1 clamscan --remove / | tee -a /var/log/clamscan/$(date +"\%b-\%d-\%y-\%H-\%M").log 
08 2 * * 1 clamscan -r --remove /bin | tee -a /var/log/clamscan/$(date +"\%b-\%d-\%y-\%H-\%M").log 
15 2 * * 1 clamscan -r --remove /boot /dev | tee -a /var/log/clamscan/$(date +"\%b-\%d-\%y-\%H-\%M").log 
22 2 * * 1 clamscan -r --remove /tmp | tee -a /var/log/clamscan/$(date +"\%b-\%d-\%y-\%H-\%M").log

1 2 * * 2 clamscan -r --remove /etc | tee -a /var/log/clamscan/$(date +"\%b-\%d-\%y-\%H-\%M").log 
08 2 * * 2 clamscan -r --remove /home /lib | tee -a /var/log/clamscan/$(date +"\%b-\%d-\%y-\%H-\%M").log 

1 2 * * 3 clamscan -r --remove /lib64| tee -a /var/log/clamscan/$(date +"\%b-\%d-\%y-\%H-\%M").log 
8 2 * * 3 clamscan -r --remove /lost+found /media /mnt | tee -a /var/log/clamscan/$(date +"\%b-\%d-\%y-\%H-\%M").log 

1 2 * * 4 clamscan -r --remove /opt | tee -a /var/log/clamscan/$(date +"\%b-\%d-\%y-\%H-\%M").log 
08 2 * * 4 clamscan -r --remove /proc /root | tee -a /var/log/clamscan/$(date +"\%b-\%d-\%y-\%H-\%M").log 

1 2 * * 5 clamscan -r --remove /run | tee -a /var/log/clamscan/$(date +"\%b-\%d-\%y-\%H-\%M").log 
8 2 * * 5 clamscan -r --remove /sbin | tee -a /var/log/clamscan/$(date +"\%b-\%d-\%y-\%H-\%M").log 
15 2 * * 5 clamscan -r --remove /srv | tee -a /var/log/clamscan/$(date +"\%b-\%d-\%y-\%H-\%M").log 

1 2 * * 6 clamscan -r --remove /sys | tee -a /var/log/clamscan/$(date +"\%b-\%d-\%y-\%H-\%M").log 
8 2 * * 6 clamscan -r --remove /var| tee -a /var/log/clamscan/$(date +"\%b-\%d-\%y-\%H-\%M").log

1 2 * * 7 clamscan -r --remove /usr/sbin | tee -a /var/log/clamscan/$(date +"\%b-\%d-\%y-\%H-\%M").log
8 2 * * 7 clamscan -r --remove /usr/bin | tee -a /var/log/clamscan/$(date +"\%b-\%d-\%y-\%H-\%M").log
15 2 * * 7 clamscan -r --remove /usr/include /usr/lib /usr/etc /usr/games| tee -a /var/log/clamscan/$(date +"\%b-\%d-\%y-\%H-\%M").log
22 2 * * 7 clamscan -r --remove /usr/lib64 | tee -a /var/log/clamscan/$(date +"\%b-\%d-\%y-\%H-\%M").log
29 2 * * 7 clamscan -r --remove /usr/libexec /usr/local /usr/share /usr/src | tee -a /var/log/clamscan/$(date +"\%b-\%d-\%y-\%H-\%M").log


# Deletes all clamscan logs older than 30 days
30 3 * * * find /var/log/clamscan/ -type f -mtime +30 -delete

IMPORTANT: The "--remove" option of clamscan is unpredictable. It may detect a false

positive and delete an important, uninfected file. If you remove this option, you must

ensure you are routinely checking the logs for infected files (although this means it's no

longer self-maintaining....)


Step 7: DONE!


So, as you can see, the installation of WireGuard itself is really quite simple. It's so lightweight, you can even run OpenVPN on the same server simultaneously. But don't forget to secure your DNS traffic! Head over to my DNSCrypt-Proxy tutorial next.


If you want recommendations on VPS hosting services, I personally use LunaNode and Vultr. I mainly selected these providers based on available server locations, low price, security features, and overall quality of service.


Special thanks to LinuxBabe for her very informative tutorial. If you want to explore other WireGuard options or need some more troubleshooting tips, head over to her tutorial here.