This is a full guide to making your own Wireguard VPN server to safely access devices on your home network over the internet. Wireguard VPN an amazing secure and simple to use VPN. Feel free to familiarize yourself with Wireguard before continuing.
For this guide, I will be using a Raspberry Pi 4 Model B (RPI) as the VPN server, but you can use any computer for this. I would recommend getting a low power PC, as this will (in most cases) always be running, so take care to check the maximum TDP of the CPU in your machine to avoid using too much power, espcially when the server is idle. The TDP of the RPI is ~7W underload, but it will only use ~2W when idle. Depending on what you plan to do with the VPN (if you are the only one who will use it, size of files you plan to transfer, etc), a Raspberry Pi might be all you need as well, but if you need more processing power, looking for a PC with an Intel N100, Intel Celeron N5105, or AMD Ryzen 3 3200U are all good choices as well as they have low TDPs. A Wireguard VPN server does not require many resources (depending on expected network load), needing little memory and storage, unless you want to keep large log files.
The first step will be to install linux on your machine. You technically can set this up with Windows or MacOS, but linux is the better choice here, being that it is extremely reliable in a server setup and requires very little resources to run effectively. If you are using an RPI, you will need to download and install the Raspberry Pi Imager. If not, you will need to install linux on your PC. You can watch a video here if you do not know how to do so already. As for the distribution, you can go with any, but I would recommend Raspberry Pi OS Lite for the RPI and Ubuntu Server for other PCs, as they are both lightweight and headless, meaning that they don't have a GUI, which we do not need since we will be accessing the server primarily through SSH.
Now that we have our OS set up, you can connect your VPN server to your home network. I would recommend a connection via ethernet if possible for a faster and more reliable internet connection. Connect to your VPN server via SSH. I would also now recommend that you make sure the system is up to date before continuing with
sudo apt update -y && sudo apt upgrade -y
Now we can install WireGuard with
sudo apt install wireguard
After installing Wireguard, the first thing we will need to do is generate a public/private key pair for our server. WireGuard exclusively uses certificate authentication for connecting to the VPN, meaning that instead of entering a username and password to log into the VPN, you must instead create a key pair for each machine you plan to have connected to the network, and register the client's public key onto the VPN server to be able to connect. This increases security as an attacker can't just brute force you password and you are able to remove certificates from machines that you believe may be compromised. This does, however, come with the downside of not being able to connect to the VPN without a machine with registered keys, but the security benefits are more than worth this incovenience. To generate your keys for the server, you will run
wg genkey | tee privatekey | wg pubkey > publickey
Now, you should see two files in your home directory: privatekey and publickey, aptly named. Make sure you keep the private key private, as the name implies. If anyone were to get your VPN private key, not only would they be able to calculate your server's public key, but also be able to pose as your VPN server. The public key, as the name implies, is fine for others to know due to their client needing to be registered on the server as detailed earlier. Taking your private key, we can create the configuration file for your VPN server. Using your favorite text editor (nano is very beginner friendly if you are looking for an in-terminal text editor), create and open a file named '/etc/wireguard/wg0.conf'. You can name the '.conf' file whatever you want, wg0.conf is just a standard name most people give it. We will start writing the 'Interface' section of the configuration. This is what tells WireGuard how to setup your VPN endpoint. Here is a tempalte 'Interface' section:
Let's go over what each of these configurations are:
Now that we have our interface setup, we can start the server. In terminal, run
wg-quick up wg0 (or the name you gave your .conf file)
To check that our VPN interface has started successfully, we can enter the command
sudo wg
If the interface is running correctly, you should see an output from this command with your interface's public key, private key (likely hidden), and listening port. You can also run
ip addr show
To list the network interface devices on your machine and their IP addresses. Under an entry named 'wg0' (or your conf name), you should see 'inet 10.0.0.1/8' that we set before. If all looks correct, then great! We have just set up our VPN server! Next is to set up and add a client to our server. On the machine you wish to add, install WireGuard. Since most of you are probably using Windows for your personal computers, you can simply go here to download the installer. For MacOS users, WireGuard will be available for download on the Play Store. For mobile devices it will again be available in the Play Store and the Google Store. We will again start by creating a key pair using the same command in terminal/powershell
wg genkey | tee privatekey | wg pubkey > publickey
On GNU/Linux, we will create a .conf file in /etc/wireguard/, same as with the set up for the server. On Windows, MacOS, and mobile, we will still be creating the same file, but the location of it is non-specific, as we will be adding the file as a tunnel in the GUI of the WireGuard application. Still be sure to keep this file in a secure location on your computer so that your private key is kept safe. Here is another template for the .conf file.
Lets go through what each of these settings specify for the client
Now that we have our client configuration set up, we can start the connection. On Linux, start it same as before with
wg-quick up wg0 (or your conf file name)
On Windows, MacOS, or mobile, open the WireGuard application, hit 'Add Tunnel', and select the configuration file we just made. You should see that the VPN interface is indeed running, but we are not receiving any packets on it. This is because we have yet to add this client to our server configuration, so it is ignoring the attempts to connect to it. To register our new client, we must go back to our server, close the VPN interface with
wg-quick down wg0 (or your conf file name)
and edit its configuration file and add a new Peer entry like so
AllowedIPs should be the IP you set in the client with /32 after to specify that it can only connect as this one IP address. After saving these changes, you can start the interface again. Now, back on the client, you should see that we are receiving packets from the server. To verify this, try
ping 10.0.0.1
If you are able to receive responses from this IP address, then congratulations! You have successfully connected to your VPN! You can repeat the process to add more clients to your VPN, but again, make sure to give each a unique IP address on your IP address space.
Now that we have connected to the VPN, you will probably want to try it out by connecting to another device through it. With our PostUp and PostDown options in our server configuration file, we have already set the IP filtering to allow network traffic forwarding and NAT for outgoing traffic, but there is one more setting we need to change to allow connecting different devices through the VPN server. Let's say we have two clients on the VPN with IP addresses 10.0.0.2 and 10.0.0.3. You will find that you are able to ping 10.0.0.3 from 10.0.0.2 and receive packets back, but any other connection you try to establish will fail, such as SSH, with a connection timeout error. If this is the case for you, we need to check if you server has IPv4 packet forwarding is enabled. You can do this by entering the command
cat /proc/sys/net/ipv4/ip_forward
If this outputs a 0, this means IPv4 packet forwarding is disabled on your machine. You can change this setting permanently by opening /etc/sysctl.conf with your favorite text editor and uncommenting (or adding if not there) the line
net.ipv4.ip_forward=1
Now, after either rebooting the system or running
sudo sysctl -p
You should see that SSHing into 10.0.0.3 from 10.0.0.2 will now complete successfully. By editing /etc/sysctl.conf, this change is now permanent and IPv4 packet forwarding will be enable at startup from now on.
When creating the client configuration, we specified the Endpoint of the VPN server, the IP address and port that our client will attempt to reach the server on. For machines on the same LAN as the server, this would be the private IP address of the server (most likely 192.168.0.0/16). Having a VPN server to isolate certain devices on your network and lock access to them behind the VPN is great for security, but more likely than not, you wanted to set up a VPN to access your devices when you are not home securely, such as a home file server, for example. For the client configuration for the file server, using the VPN server's private IP address is no issue, as both servers will not be leaving the LAN. However, for devices you wish to use to access this file server through the VPN, they will obviously not be able to access the VPN server over the same IP address, thus, we need to forward a port on your router to the VPN server to establish a connection.
But wait, isn't the whole point of making this VPN that forwarding a port directly to your server is insecure, you might be asking, and you would be correct. However, there is a reason this system is much more secure than forwarding a port directly to your file server. Firstly, with the VPN, you are only fowarding a single port to the VPN machine rather than the multiple ports you may need for your file server, such as port 22 for SSH, port 80 for a webserver, etc. Additionally, WireGuard requires authentication and registration of a client's public key to connect, so an attacker will not be able to perform any brute force attacks to log in. WireGuard will also ignore any unknown connection attempts, so the exposed port may not even be detected during penetration testing. Since you are running a dedicated VPN server, there are also less services that can be taken advantage of in an attack. Overall, these factors make forwarding a port to a VPN server much more secure than directly to another one of your machines. I have also left other security considerations to make your VPN server even more secure and avoid as many vulnerabilities as possible.
So, getting back to forwarding the port on your router, each router is different, but generally, you will want to visit 192.168.1.1 in your browser. This will take you to a page for accessing and changing settings on your router. Look for a 'Port Forwarding' or 'Single Port Forwarding' section, usually under a section labelled 'Security'. If you are having trouble finding it, a quick Google search with your router model should be able to help. Once you locate this section, you will want to forward port 51820 on your router to port 51820 to your VPN server's IP address, or the port that you chose for your server configuration. For the protocol, you will only want to allow UDP, as this is the only protocol WireGuard uses. After applying those settings, you will want to change the Endpoint option in your client's configuration to your home network's public IP address. You can get this by visiting ipv4.icanhazip.com or entering this command into the terminal
curl -L ipv4.icanhazip.com
After replacing this in your client's configuration file, try connecting to the VPN tunnel and ensuring that everything is working as expected. This will work even if you are on the same LAN as the VPN server, as the traffic will still route out to the Internet before coming back into your network to the VPN server.
It is always a good idea to have a firewall active to block any unwanted connections to your device. To get started, we will install the 'Uncomplicated Firewall' package with
sudo apt install ufw
To check what rules, if any, are set after installation, we can run
sudo ufw status verbose
To start, we will add a rule specifying which IP addresses will be able to SSH into the VPN server. You can restrict access for SSHing into the VPN to just devices on your LAN with
sudo ufw allow from 192.168.1.0/24 to any port 22 proto tcp
This assumes that your LAN has that IP address space, and you should change it if not. This only allows connections from your LAN to the server on port 22 over TCP, since ssh defaults to port 22 and uses TCP. If you want to allow SSH access to the server on the VPN as well, we can add another rule like this
sudo ufw allow from 10.0.0.0/8 to any port 22 proto tcp
which does the same as the above command except allowing connections over the VPN to SSH in as well. Again, change the IP address space to the one you chose for your VPN if different.
Now, we will obviously also need to allow incoming connections over the port we are listening on for incoming VPN connections. Since I have chosen 51820, I will add the rule
sudo ufw allow from any to any port 51820 proto udp
This allows all incoming connection to port 51820 over UDP, which WireGuard uses. To put these rules into action, enter
sudo ufw enable
The firewall is now enabled. Test that all services you need are able to be connected to and add or delete firewall rules as needed. After changing the rules, you can load them with
sudo ufw reload
To learn more about using ufw to manage your firewall, run
man ufw
A general but very good rule to keeping any device secure is to keep it up-to-date with the latest updates. As we said earlier, you can update your VPN server using
sudo apt update -y && sudo apt upgrade -y
However, you probably don't want to have to log into and update the VPN server often as you probably want this server to be autonomous. So, to automate these updates, we can look to crontab.
Crontab, short for cron table, is used to modify each user's cron file, which is used by the cron daemon to run scheduled commands. We can use this to schedule automatic updates for your server. We can open the cron file for the root user using
sudo crontab -e
In this file, you can add the line
0 6 * * * apt update -y && apt upgrade -y
This line will have your server run these commands to check for and install updates everyday at 6 a.m. Now, you will no longer need to manually keep your server up to date. While we are using crontab, another command I recommend to schedule is a daily reboot command. You can add the line
0 5 * * * /usr/sbin/shutdown -r +5
to your root's cron file, which will turn off your system everyday at 5 a.m. with a 5 minute delay before turning back on. 5 a.m. may work for you, but I would recommend choosing a time where it is very unlikely that anyone will be accessing the VPN and that you check that the path to the 'shutdown' command is the same on your system. You can check by running
which shutdown
Now that we are rebooting the server every morning, we will need to ensure that the WireGuard interface will be brough up on start up as well. We can create a system service that will start the interface on boot up every time. To do this, we can enter the command
sudo systemctl enable [email protected]
From now on, on start up, the server will automatically start the VPN interface, and you can check this by restarting your server and running
sudo systemctl status [email protected]
sudo wg
to ensure that it is up and running.
Another simple yet effective security strategy is to rotate out your keys regularly and often. By rotating them regularly, you dramatically decrease the chance that the network could be compromised as, even if the keys of even one of your devices is compromised, that key will become invalid after your rotation period. Once every 30 days is typically a good amount of time to do this, but you can do this more or less often based on your needs. Whenever the time does come to rotate out your keys, you just need to regenerate a key pair using
wg genkey | tee privatekey | wg pubkey > publickey
In the server configuration, you will need to update the server's private key and each of the client's public keys. For each client, you will need to update them with their new private keys and the server's new public key. Now, your whole network is up and running again with completely different keys.
Another great way to keep your VPN and the devices on it secure as well as keeping your home network secure is to isolate the VPN from the rest of the network. By doing this, you ensure that any infected or compromised device on the LAN will not be able to affect the devices on the VPN server and vice versa. This does include some incovenience, however, such as not being able to access any of the devices on the VPN from your home network, including the VPN server itself, without being connected to the VPN. Depending on your needs and use case, this extra security measure may or may not be worth it. Unfortunately, I do not have much information to pass along in this section in terms of particulars for achieving this isolated network as I have not set up my VPN this way, as I like having easy access to all my devices when home, but I still felt that this concept was worth sharing for those who are new to networking and are interested in maximizing the security of their systems.
Coming Soon!