Motivation
I have some datasets on a VPS that I want to back up regularly to my homelab.
- Both servers run ZFS
- I don’t want to expose extra ports
Approach
Use zrepl1 to transport backups through a Wireguard2 tunnel. While I still have to open up the Wireguard port, having an encrypted tunnel between my VPS and my home server is a useful thing to have in general.
Details
Setting up Wireguard
Most of this guide is taken from here.
Install packages.
pkg install wireguard-tools zrepl
Generate public and private keys for both the backup server and the VPS. Keep track of this.
wg genkey | \
tee /usr/local/etc/wireguard/privatekey | \
wg pubkey > /usr/local/etc/wireguard/publickey
Create a new configuration for the interface in /usr/local/etc/wireguard/wg0.conf.
- The backup server acts as the server, listening for requests
- Address is some private address. Subnet mask represents the address space that your peers live in.
[Interface]
PrivateKey = <backup server private key>
Address = 10.1.0.1/24 # As an example
ListenPort = 51820
[Peer]
PublicKey = <vps public key>
AllowedIPs = <the ips that your vps uses>
And on the client:
[Interface]
PrivateKey= <vps private key>
Address = <same as AllowedIPs in previous file>
[Peer]
AllowedIPs=10.1.0.1/32 # backup server IP
Endpoint=<public ip address>:51820
PersistentKeepalive=25
PublicKey= <backup server public key>
Enable and start Wireguard.
service wireguard enable
service wireguard start
You can also bring it up with
wg-quick wg0 up
Enable forwarding packets between interfaces.
sysctl net.inet.ip.forwarding=1
echo 'net.inet.ip.forwarding=1' >> /etc/sysctl.conf
And set up /etc/pf.conf. This enables packets to be received on the wg0 interface.
ext_if = "vtnet0"
wg_net = "10.1.0.0/24"
nat on $ext_if from $wg_net to any -> ($ext_if)
Enable and start pf.
service pf enable
service pf start
service pflog enable
service pflog start
Setting up zrepl
VPS config:
jobs:
- name: minecraft_server
type: push
connect:
type: tcp
address: "10.1.0.2:8888"
filesystems:
zroot/minecraft: true
snapshotting:
type: periodic
prefix: zrepl_
interval: 10m
pruning:
keep_sender:
- type: grid
grid: "12x10m(keep=all) | 24x1h | 14x1d"
regex: "^zrepl_"
keep_receiver:
- type: grid
grid: "1x1m(keep=all) | 24x1h | 30x1d | 12x30d"
regex: "^zrepl_"
This sets up snapshotting every 10 minutes. On the VPS, all snapshots are stored in the past two hours, a snapshot every hour is stored in the past day, and a snapshot every day is stored in the past two weeks. On the backup server, hourly snapshots are kept in the last day, daily snapshots in the last month, and monthly snapshots in the past year.
The 1x1m(keep=all) rule is to avoid this issue.
Server config:
jobs:
- type: sink
name: "backup-name"
root_fs: "zroot/backups" # This is the fs where you want all your backups to live in
serve:
type: tcp
listen: ":8888"
clients: {
"10.1.0.3": "vps_server"
}
recv:
placeholder:
encryption: off # Must be added
The name of the filesystem will be zroot/backups/vps_server/zroot/minecraft in this case.
Monitoring
You can monitor if data has been sent through the tunnel via sudo wg show, and the status of the backup jobs with sudo zrepl status.
Improvements
- Containerize zrepl and WireGuard
- Set up mounting ZFS in a container3
- Set up Wireguard in a container
- Figure out DNS to find the server name
- Figure out restore
References
https://emar10.dev/posts/rootless-podman-wireguard
https://www.server-world.info/en/note?os=FreeBSD_14&p=wireguard&f=1