Home Server Setup with Wireguard VPN

Having a server at home or even at an office is so old school. All the cool kids host their servers in the clouds somewhere. Even this blog is hosted in the cloud, or rather an ocean, Digital Ocean. Of course, quite a lot of the ‘cloud, cloud, cloud!’ hosting chants come from people with a financial benefit from you using the cloud, at least in the form of affiliate links like one I’ve just added for fun. All the ‘cloud’ means is that the hardware is located not in your own facility (corporate or personal) but in a large professionally-managed data center.

The cloud works wonderfully as ‘professional-managed’ means better than hobbyists like me and even IT system admins, usually. The cloud does have a few faults. It is expensive, my 1 CPU/1GB RAM VM is only $6 month ($70/year), but my new server and electric costs will be cheaper in less than two years, and has eight times the power. The cloud is less controllable and configurable to a certain extent. Having a VPN into a home network is a convenient to access said network and anything on it. The main advantage to the cloud of course, is that it has a simple interface (no need to play with computer parts) and if something breaks or is breached, it breaks comfortably far away in a data center somewhere. Actually that last one might be a disadvantage, as I put a lot more effort into security for my home server, where it feels more personal, than I do for the cloud ones.

So how do we set one up? I am mostly leaving this as a guide to get things going again, say, if my server dies, but also perhaps you may find it helpful as well. I have this hosted in my Raspberry Projects Github repo as this started years ago on a Raspberry Pi, and for the most part probably could still run quite satisfactorily on one.

Installation begins with an initial test of the hardware, configuring the hardware (adding some more RAM and an SSD), checking out the BIOS (in this case enabling booting from a USB drive and AC power recovery, options not present in all computers), and then booting and installing Ubuntu 20.04 from a USB drive. I’ve got this all plugged into a backup battery that can run for about an hour, which keeps things running through most power outages.

My primary tasks are:

  • Running a dynamic dns client (very minimal process) which points a domain name to my home’s ip address.
  • Running some batch Python scripts (moderate consumption, occasionally)
  • Running a Wireguard VPN server (minimal process when only one or two clients at once)
  • Running Nextcloud (definitely the highest performance demanding service) or WordPress

I decided after trying it out, that Nextcloud wasn’t for me. It is nice but I really don’t have any reason not to just use Google Drive and various chat apps for the handful of times I need such services personally. I might be tempted to run this WordPress site from it, but the possibility of power outages and changes to the IP address would mean occasional downtimes that I personally don’t currently desire. I also trust Digital Ocean’s backups more than my own backups.

The dynamic dns client requires some quick setup in Google Domains which I won’t bother to discuss here, as well.

A firewall (ufw) and fail2ban are both services for security purposes, which are setup here. SSH is for remote access over the network.

# install Ubuntu, make sure you have a new user that isn't root
# update
sudo apt update
sudo apt upgrade

# setup system firewall
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw enable
sudo ufw allow ssh
sudo ufw status verbose

# setup fail2ban
sudo apt install fail2ban

# setup ssh
# I won't be exposing SSH to the public internet (only behind the vpn)
sudo apt install openssh-server
sudo systemctl status ssh

# dynamic dns with ddclient
sudo apt install ddclient
# might be under /etc/ddclient/ddclient.conf
sudo nano /etc/ddclient.conf
# details of that file for my use:
	use=web, web=dyndns
# test
sudo ddclient -daemon=0 -debug -verbose -noquiet

# samba share drives (using ubuntu GUI)

# python for my python scripts, installing necessary packages
# download miniconda and install
conda install pandas  # 1.0.5
pip install gspread  # 3.6.0
pip install PyPDF4   # 1.27.0
sudo apt install default-jre
pip install tabula-py  # 2.1.1

crontab -e
# Add these:
	*/15 * * * * /home/colin/miniconda3/bin/python /home/colin/FarmLog/fiveteenMinuteLog.py
	35 09 * * * /home/colin/miniconda3/bin/python /home/colin/UCI_pdf_reader/UCI_pdf_reader.py

# if you have "system problem detected" popups
sudo rm /var/crash/*
# set to enabled=0 to stop all the popups
sudo gedit /etc/default/apport &

First introduce the Wireguard configuration file. The eth0 should be replaced with the name of your network adapter. wg0 should be replaced if you use a different interface name.

Address =, fd86:ea04:1110::1/64
PostUp = iptables -A FORWARD -i wg0 -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE; ip6tables -A FORWARD -i wg0 -j ACCEPT; ip6tables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
PostDown = iptables -D FORWARD -i wg0 -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE; ip6tables -D FORWARD -i wg0 -j ACCEPT; ip6tables -t nat -D POSTROUTING -o eth0 -j MASQUERADE
ListenPort = 51820

AllowedIPs =, fd86:ea04:1115::26/128

AllowedIPs =, fd86:ea04:1115::27/128

The client side configuration looks like this:

Address =, fd86:ea04:1115::26/128

AllowedIPs =
Endpoint = example.com:51820

Those XXXXXX and YYYYYY that I left in there can be replaced by keys generated with: wg genkey | tee privatekey | wg pubkey > publickey

Setting up Wireguard on the server now:

# Install Wireguard, add-repository is necessary with <18.04
sudo apt install wireguard

# deploy configuration file wg0.conf (find examples online)
sudo nano /etc/wireguard/wg0.conf
# make sure eth0 in PostUp/PostDown is set to the network adapter in use
ip -o -4 route show to default | awk '{print $5}'
# new key if needed for a new client
wg genkey | tee privatekey | wg pubkey > publickey

# for wireguard this was required on the current server but not on a previous:
sudo nano /etc/sysctl.conf
# uncomment or add the following:
sudo sysctl -p     # restarts

# start the service
sudo ufw allow 51820/udp
wg-quick up wg0
sudo systemctl enable wg-quick@wg0
sudo wg show

Nextcloud if used:

# Nextcloud if used
sudo snap install nextcloud
snap info nextcloud
sudo nextcloud.manual-install username verysecurepassword
sudo ufw allow 80,443/tcp
sudo nextcloud.occ config:system:set trusted_domains 1 --value=example.com
sudo nextcloud.occ config:system:set trusted_domains 2 --value=your.local.ip
# configure email service and install apps
# run the following once/if ports 80 and 443 are publically exposed
sudo nextcloud.enable-https lets-encrypt

Final steps:

# make sure 'automatic security updates' is on in Gnome, or else:
# sudo apt install unattended-upgrades
# sudo unattended-upgrades --dry-run --debug

# make sure router password is not a generic default
# router give device fixed IP address by mac address
# port forward to this device on 51820  (80 and 443 for Nextcloud public)
# confirm ddns, vpn, python, ssh, shared network drive
# test vpn off network, all clients make sure IP address changes
# schedule backup to HDD if desired

That last step is mostly working inside the router, make sure it is secure and having it forward the necessary ports past its firewall to the server.

Leave a Comment

Your email address will not be published. Required fields are marked *