Skip to content

Instantly share code, notes, and snippets.

@x1le
Created April 13, 2020 00:41
Show Gist options
  • Save x1le/65fd6edb6ec12178c880029c4faa42d4 to your computer and use it in GitHub Desktop.
Save x1le/65fd6edb6ec12178c880029c4faa42d4 to your computer and use it in GitHub Desktop.
VPN on Seedbox

Setup VPN back home

We want to be able to securely sync between the cloudbox and back on-prem (for a local plex server). As a result we'll configure a wireguard VPN link between the two and then setup a rsync daemon on the cloudbox.

See Wireguard vs OpenVPN on a local Gigabit Network for a performance comparison. I've gone with Wireguard over OpenVPN based on it being incorporated into the Linux Kernel and increased performance versus OpenVPN. In addition, there's a useful walkthrough on How to setup your own VPN server using WireGuard on Ubuntu that I leaned on during this process. It's not quite right though and had some errors in.

Install wireguard pre-reqs on both boxes

sudo apt-get -y install software-properties-common; \
sudo add-apt-repository -y ppa:wireguard/wireguard; \
sudo apt-get install -y wireguard; \
sudo modprobe wireguard  # activate kernel module

Generate public/private keypair (on both boxes)

sudo -s  # do this as root
cd /etc/wireguard; \
umask 077; \
wg genkey | sudo tee privatekey | wg pubkey | sudo tee publickey
exit  # drop back to your user

We need to create a network interface now for the wireguard VPN. I'm going to set the cloudbox as the server as it will always have a fixed IP address and will not need to store any reference to my home IP (it'll be a pull).

Common convention is to use wg0 as a name for this. In addition we also need to choose a subnet for the VPN addresses. As I've got a 192.168.0.1/24 configuration at home I'll use 10.10.0.1/24 for the VPN.

Note the highlighted IP address we assign to each node here. It will need to be incremented for each to provide a unique address. In addition I'm dropping in the primary network interface based on the default routing but if this isn't what you want replace the inline code with your preferred network interface.

NB: mypublickeycontents should be the contents of the public key you generated on your home server so that the seedbox can authenticate it.

sudo -s  # run the below commands as root
export HOME_PUBLIC_KEY=mypublickeycontents
sudo tee /etc/wireguard/wg0.conf <<EOF
# file: /etc/wireguard/wg0.conf
# Server configuration (we allow peers to connect into us)
[Interface]
Address = 10.10.0.1/24
ListenPort = 51820
PostUp = iptables -A FORWARD -i wg0 -j ACCEPT; iptables -t nat -A POSTROUTING -o $(ip -4 route | grep default | awk '{print $5}') -j MASQUERADE
PostDown = iptables -D FORWARD -i wg0 -j ACCEPT; iptables -t nat -D POSTROUTING -o $(ip -4 route | grep default | awk '{print $5}') -j MASQUERADE
PrivateKey = $(cat /etc/wireguard/privatekey)

[Peer]
PublicKey = $HOME_PUBLIC_KEY
AllowedIPs = 10.10.0.2/32
EOF
exit  # drop back to your user

Enable forwarding of packets in the host kernel for cloudbox.

sudo tee /etc/sysctl.conf << EOF
net.ipv4.ip_forward=1
net.ipv6.conf.all.forwarding=1
EOF
sudo sysctl -p

Finally we can start the wg0 interface.

wg-quick up wg0

Hopefully you'll see something like the below output.

feederbox# wg-quick up wg0

[#] ip link add wg0 type wireguard
[#] wg setconf wg0 /dev/fd/63
[#] ip -4 address add 10.10.0.1/24 dev wg0
[#] ip link set mtu 1420 up dev wg0
[#] iptables -A FORWARD -i wg0 -j ACCEPT; iptables -t nat -A POSTROUTING -o enp3s0 -j MASQUERADE

Configure a ufw profile for it to allow through the firewall.

sudo tee /etc/ufw/applications.d/wireguard <<EOF
# file: /etc/ufw/applications.d/wireguard
# Used to configure the ufw definition for wireguard vpn server

[wireguard]
title=Wireguard VPN Server
description=WireGuard is an extremely simple yet fast and modern VPN that utilizes state-of-the-art cryptography
ports=51820
EOF

sudo ufw app update wireguard
sudo ufw allow wireguard

Now setup the client connection on our homeserver.

NB: theseedboxpublickeycontents should be the contents of the public key you generated on your seedbox so that the peer can authenticate it.

sudo -s  # run the below commands as root
export SEEDBOX_PUBLIC_KEY=theseedboxpublickeycontents
sudo tee /etc/wireguard/wg0.conf <<EOF
# file: /etc/wireguard/wg0.conf
# Client configuration (we connect to the seedbox)
[Interface]
Address = 10.10.0.2/24
PrivateKey = $(cat /etc/wireguard/privatekey)

[Peer]
PublicKey = $SEEDBOX_PUBLIC_KEY
AllowedIPs = 10.10.0.0/24
Endpoint = feederbox.yarr.wtf:51820
PersistentKeepalive = 25
EOF
exit  # drop back to your user

Assuming we can ping from one to another via the 10.0.0.1/24 subnet then enable the service on both boxes.

sudo systemctl daemon-reload
sudo systemctl enable wg-quick@wg0.service

Enable rsync

To avoid the overhead of rsync over ssh we'll use a rsync daemon that listens on the wireguard interface only (and so traffic is encyrpted over that tunnel).

On the seedbox (as your user, not root) run:

sudo tee /etc/rsyncd.conf <<EOF
# /etc/rsyncd.conf
# rsync daemon file listening on our VPN interface
# address (10.10.0.1) only. Designed to allow quick
# sync of data back from cloud to on-prem storage-server
# (dealt with by our `media-sync` systemd timer).
# 
# Use `read only` to prevent mistaken deletion of content.
pid file = /var/run/rsyncd.pid
lock file = /var/run/rsync.lock
log file = /var/log/rsync.log
address = 10.10.0.1

[media]
# hosts allow = 10.0.0.0/24
# hosts deny = *
gid = $(id -g)
uid = $(id -u)
path = /mnt/local/Media
comment = Completed Media Downloads
read only = true
timeout = 300
EOF

sudo systemctl enable --now rsync

And add this to the firewall

sudo ufw allow in on wg0 to any port 873

To check this works run a query from the on-prem box.

$ rsync -rdt rsync://10.10.0.1:873

media          	Completed Media Downloads

We can now enable our media-sync systemd scripts on the on-prem box to automate the pull down of completed media back home.

Add your own user (optional)

It might be useful to have additional clients capable of tunnelling via the seedbox. E.g. some private trackers want you to have consistent IP addresses and you might want that security as well when browsing.

To setup a peer for your mobile/laptop etc. you need to:

  • Create a public/private keypair
  • Decide on the routing you want to have for your client
    • Forward all traffic through the VPN (AllowedIPs = 0.0.0.0/0, ::0/0)
    • Route just traffic which is for my private subnets such as Home LAN and other VPN peers (AllowedIPs = 10.10.0.0/24,192.168.0.1/24)

Whilst the iOS client will take care of the first part for you if wanted (creation of a keypair) you'll still need to fill out the following details.

  • Server file

    • Add your client as a [Peer] block with a
      • PublicKey = generated by the client as per before
      • AllowedIPs = which source IPs can I expect from that peer? Note that this setting is different on the server (essentially acting as an ACL) versus client (where it controls routing).
  • Peer file / mobile client

    • Create an [Interface] block (this is shown differently in the mobile client). I needed to add:
      • Addresses: 10.10.0.3/24
      • DNS servers: whatever you want (mine is 1.1.1.1 but could use an internal PiHole etc.)
    • Add your seedbox as a [Peer] block with a
      • PublicKey = generated already
      • AllowedIPs = decide on the routing approach
      • Endpoint = seedbox fqdn/ip and port
      • (Opt) PersistentKeepAlive = how often to poll in order to keep the connection up if we're behind NAT

NFS

If you're mounting shares from home then install apt-get install -y nfs-common and then add the necessary fstab entries / modify the mergerfs service.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment