Initial setup

Update, install base packages, set up ssh key authentication, change shell to zsh and copy configs, change passwords

set -o vi
 
sudo apt update && sudo apt upgrade -y
sudo apt install git tmux zsh zsh-syntax-highlighting neovim
 
exit # back to client machine
ssh-copy-id user@pi
scp -r .config user@pi:~/
 
ssh user@pi
ln -s .config/zsh/zshrc .zshrc
chsh -s /bin/zsh
exit # logout and back in to reset shell
ssh user@pi
 
passwd user
sudo passwd root

Editing sshd config

edit config file

# /etc/ssh/sshd_config
Port 2222 # any unused port other than 22
PermitRootLogin no
PubkeyAuthentication yes
PasswordAuthentication no

sanity check and restart sshd service

sudo sshd -t
sudo systemctl restart sshd

Configuring static ip

# /etc/network/interfaces
# should contain the following
source /etc/network/interfaces.d/*
# /etc/network/interfaces.d/eth0
auto eth0
iface eth0 inet static
	address 10.0.0.5
	netmask 255.255.255.0
	gateway 10.0.0.1

reboot

Installing pihole

wget -O basic-install.sh https://install.pi-hole.net
chmod +x basic-install.sh
sudo ./basic-install.sh
  • go to 10.0.0.5/admin in web browser
  • go to Settings Teleporter and import backed up settings file

If you don’t have a settings file:

Adlists:

Regex blacklists:

I take zero credit for this wizardry. I grabbed these a long time ago and forgot to document where I got them from. I’ll have to locate them again later.

The final two rules,self.events.data.microsoft.com and dns.msftncsi.com I believe are to block absurd levels of Windows DNS requests. I created those so long ago I don’t even know if I tested them.

^(.+[_.-])?adse?rv(er?|ice)?s?[0-9]*[_.-]
^(.+[_.-])?telemetry[_.-]
^ad([sxv]?[0-9]*|system)[_.-]([^.[:space:]]+\.){1,}|[_.-]ad([sxv]?[0-9]*|system)[_.-]
^adim(age|g)s?[0-9]*[_.-]
^adtrack(er|ing)?[0-9]*[_.-]
^advert(s|is(ing|ements?))?[0-9]*[_.-]
^aff(iliat(es?|ion))?[_.-]
^analytics?[_.-]
^banners?[_.-]
^beacons?[0-9]*[_.-]
^count(ers?)?[0-9]*[_.-]
^mads\.
^pixels?[-.]
^stat(s|istics)?[0-9]*[_.-]
self.events.data.microsoft.com
dns.msftncsi.com

Settings:

  • DNS enable IPv6
  • DNS use DNSSEC
  • Rest at defaults

Edit: the previous settings assumed pi-hole as the endpoint DNS which would then forward to upstream DNS. In my finished configuration, I’m using the router as the upstream DNS which then points to further upstream public DNS servers. For complete pi-hole configuration, see Pi-hole with OpenWRT.

Setting up wireguard

Previous documentation: Setting up WireGuard P2P VPN

The above works for connection to a remote server. However, the last time I did this for remote access to my home network, or in other words for remote access to a subnet instead of just a single device, I did so with openmediavault which handles a couple things on the down low that I didn’t realize.

I could have done this with openmediavault again but I really have no reason to install it on my pi as it’s really only for wireguard, and I used that as an excuse to learn how to do all the configuration via the CLI. (I didn’t need much of an excuse, though.)

Initially I got it running with point-to-point configuration but could not access any other devices in the LAN, and I had cross-referenced with my currently functioning raspi 4B running wireguard configured via openmediavault. I was lost for quite a while here. Some helpful links that put me on the right track:

And the thread that solved it all…

Enabling forwarding in sysctl.conf

The main thing to fix remote LAN access is uncommenting this line from /etc/sysctl.conf:

# /etc/sysctl.conf
net.ipv4.ip_forward=1

Edit: to get this functional with my Android device, I also had to uncomment the following line:

# /etc/sysctl.conf
net.ipv6.conf.all.forwarding=1

This enables both access to the subnet and access to the WAN on your client while connected to the VPN. Without this line, you will only have access to your VPN server.

Note that you’ll need to reload the sysctl variables for this to take effect after editing the config file:

sudo sysctl --system

Generating client config QR codes

The other helpful thing that openmediavault handled was the automatic generation of client configs and QR codes to transfer to a different device - especially helpful to transfer to your phone, to avoid having to type in 25+ character public and preshared keys manually.

You can do this with qrencode and X11 forwarding. Note that you do need a GUI image display which installs a lot of fluff dependencies. (I purged this afterwards.)

I figured learning how to generate the QR code would take about as much time as typing in those keys manually (not to mention far more engaging)…and what do you know, I was right. Ended up being fairly easy.

Note I ran into a brief issue with X11 forwarding, you can’t do it as root. (I’m sure there’s a way, but I’m sure it’s not a good idea, so I didn’t try.) All the config files are set to -rw------ permissions (or 600) because they all contain private keys. So after generating the png file, I copied it out to my home directory and edited the permissions to be able to view it in sxiv.

You’ll also need to make sure the following line is uncommented from your /etc/ssh/sshd_config:

# /etc/ssh/sshd_config
X11Forwarding yes

I want to figure this out later, but displaying it in the terminal didn’t work for the android wireguard app. Config was invalid. (This was the command: qrencode -t ansiutf8 peer.conf). Wouldn’t have to install sxiv and mess around with X11 forwarding if you could display on the terminal.

Edit: I am so dumb. This is the correct command:

qrencode -t ansiutf8 <peer.conf

Good ol redirection. This actually takes the contents of peer.conf and generates a QR code from it. The other command encodes the literal text “peer.conf”. So ignore needing to install sxiv.

No wonder I was getting “Unknown section in Config”…

Anyway I’ve left the commands in below, just for posterity. And a couple bonus commands: sudo apt purge sxiv; sudo apt autoremove

sudo su
apt install qrencode sxiv
cd /etc/wireguard/peer
qrencode -t png -o qr_peer.conf.png -r peer.conf
cp qr_peer.conf.png /home/user
chown user:user /home/user/qr_peer.conf.png
exit
cd
sxiv qr_peer.conf.png

And for future reference, here’s what the process for my configs ended up looking like:

generate private and public key pair:

sudo su
cd /etc/wireguard
touch private.key
chmod 600 private.key
wg genkey > private.key
wg pubkey < private.key > public.key

create server config file:

touch wg0.conf
chmod 600 wg0.conf
vim wg0.conf
 
# /etc/wireguard/wg0.conf
[Interface]
PrivateKey = <vim: :r private.key>
Address = 10.0.10.1/28 # subnet with 14 usable hosts
ListenPort = 51820
PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -A FORWARD -o %i -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -D FORWARD -o %i -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE

I’ll be honest I couldn’t tell you 100% what those iptables rules do, but openmediavault had them there and I’ll be damned if I’ll leave them out. I have at least a vague idea. If everything else had worked without a hitch I would probably have investigated them, but I’m tired of troubleshooting and want to get this documented before it leaks out my ears. They were actually a red herring for a while, I was convinced the problem was there, but nothing worked even with my firewall disabled.

create peer keypair and psk:

touch peer.private.key
chmod 600 peer.private.key
wg genkey > peer.private.key
wg pubkey < peer.private.key > peer.public.key
touch peer.preshared.key
chmod 600 peer.preshared.key
wg genkey > peer.preshared.key

create peer config file:

touch peer.conf
chmod 600 peer.conf
vim peer.conf
 
# /etc/wireguard/peer/peer.conf
[Interface]
PrivateKey = <vim: :r peer.private.key>
Address = 10.0.10.2/28
DNS = 10.0.0.2 #pi-hole address on LAN
 
[Peer]
PublicKey = <vim: :r ../public.key>
PresharedKey = <vim: :r peer.preshared.key>
# AllowedIPs will differ depending on OS and can be freely edited on the end device (as I discovered by trial and error)
AllowedIPs = 0.0.0.0/0, 128.0.0.0/0 
Endpoint = <public-ip>:51820

add peer config to server config:

This is the one that actually matters. Generating the keys for peer.conf on your server is way easier than writing it by hand, but the peer.conf does nothing on its own, it’s meant to be transferred (via QR or copy paste) to your end device. You must add the following to wg0.conf for the peer to be able to connect.

# /etc/wireguard/wg0.conf
[Interface]
...
 
[Peer]
PublicKey = <vim: :r peer/peer.public.key>
PresharedKey = <vim: :r peer/peer.preshared.key>
AllowedIPs = 10.0.10.2/32

Do this for every peer you configure.

UFW rules

I enabled the firewall without first adding a rule for port 53 to allow DNS requests. Duh.

This includes explicit allows for wireguard (51820/udp), my ssh port, access from the subnet 10.0.10.0/28 (the wireguard subnet, which I’m not 100% sure is necessary?), and 53 (note BOTH tcp and udp)

Edit 2024-11-11: also need to run sudo ufw allow 80/tcp in order to access the web interface.

To                         Action      From
--                         ------      ----
51820/udp                  ALLOW       Anywhere
22/tcp                     LIMIT       Anywhere
Anywhere                   ALLOW       10.0.10.0/28
53                         ALLOW       Anywhere
80/tcp                     ALLOW       Anywhere
51820/udp (v6)             ALLOW       Anywhere (v6)
22/tcp (v6)                LIMIT       Anywhere (v6)
53 (v6)                    ALLOW       Anywhere (v6)
80/tcp (v6)                ALLOW       Anywhere (v6)

EOF