29 January 2025 10 minutes minutes read cR0w

Setting Up a Wireguard VPN With Pihole on a VPS

For some reason, there has been a lot of discussions lately about personal VPNs among both tech nerds and non-tech people. I don't want to go into why a commercial VPN is almost never the ideal decision for most people right now. I do want to give a simple option for people that want to set up a VPN that can be easily shared with family, friends, community members, etc. I'm going to provide a script that installs Wireguard and Pihole on a VPS and creates 254 client config files for you to pass out. It also allows you to access both IPv4 and IPv6 destinations even if you only have IPv4 locally.

I tested this on an AWS Lightsail instance with Ubuntu 24.04 as an OS. In the past it has worked on other Debian-based VPS images but I don't guarantee it. Hell, I don't guarantee anything here, but I will take feedback on the Lightsail Ubuntu install. IDGAF about any other goofy stuff, I don't have time to troubleshoot those for you. Find a helpful furry on Mastodon and buy them a drink or something.

The reason I chose AWS is because in my testing, it gets blocked the least out of the major VPS providers. There are still sites that may block it but that's part of running a VPN out of a datacenter. I chose the Lightsail service because it's really simple to get set up for people new to the cloud stuff and it's simple to manage. It has also worked fine on an EC2 instance so feel free to play around.

There are some configuration decisions I made that may not be optimal for everyone. Hack it up to make it work. For example, I use port 123 for my tunneling because it's still so rarely filtered. And I used OpenDNS because they're simple and less shady than the other reliable ones I used before. Change those as you see fit. I am not going into hardening of the VPS here, nor am I going into configuration of the Pihole installation. That part is up to you unless I decide to write something up about it later.

To start, you need to create the Lightsail instance in the region of choice. I chose us-west-2a, which is in Oregon. You can see the OS choice in the image below.
Screenshot showing a new LIghtsail instance being created with a bare Ubuntu 24.04 operating system.

You also need to configure the options. The basic $5 plan is more than enough for multiple users. If you start running into performance issues, good news: You are your own sysadmin. Have fun determining if you need to scale or be a better admin. Also note the dual-stack option. You can save about $1 per month by using IPv6 only, but then you can't access the VPN via IPv4 and you can't access IPv4 Internet addresses. That might be okay for some use cases but I recommend most people start with this.
Screenshot showing a new instance with dual network stack and the lowest price hardware options for $5 per month.

After you create the instance, you will need to make a couple networking changes. The first is to configure the firewall. By default, the instance firewall allows HTTP and SSH inbound to the instance. We don't need HTTP so we can disable that, but we do need to allow UDP/123 inbound since that's the port we're running Wireguard on.
Screenshot showing allowed network traffic inbound to ports TCP/22 and UDP/123 .

You also need to attach a static IP to the instance. This keeps your instance IP from changing, which would screw up the client config files. Once you do that, you can log in to the instance and install the VPN. You will need to execute it as root. Don't @ me.

The install script is available at https://cascadiacrow.com/scripts/wireguardPiholeInstall.sh . You can pipe it into BASH if you want. I won't judge you. Or you can download it to the VPS and analyze it before executing it. The script is below:

#!/bin/bash

#Update the system and install Wireguard and UFW
apt update
apt -y full-upgrade
apt -y install wireguard wireguard-tools qrencode fail2ban dhcpcd5
snap refresh
apt -y autoremove
apt -y autoclean
umask 077 /etc/wireguard

#Generate some information for the configuration files
serverPrivateKey=`wg genkey`
serverPublicKey=`echo $serverPrivateKey | wg pubkey`
clientPrivateKey=`wg genkey`
clientPublicKey=`echo $clientPrivateKey | wg pubkey`
ip=`dig +short myip.opendns.com @resolver1.opendns.com -4`
port="123"
endpoint="$ip:$port"
interface=`ip -br a | grep -v lo | cut -d " " -f 1 | head -n 1`
postUp="iptables -A FORWARD -i wg0 -j ACCEPT; iptables -t nat -A POSTROUTING -o $interface -j MASQUERADE; ip6tables -A FORWARD -i wg0 -j ACCEPT; ip6tables -t nat -A POSTROUTING -o $interface -j MASQUERADE"
postDown="iptables -D FORWARD -i wg0 -j ACCEPT; iptables -t nat -D POSTROUTING -o $interface -j MASQUERADE; ip6tables -D FORWARD -i wg0 -j ACCEPT; ip6tables -t nat -D POSTROUTING -o $interface -j MASQUERADE"

#Write server configuration file
echo "[Interface]" > /etc/wireguard/wg0.conf
echo "PrivateKey = $serverPrivateKey" >> /etc/wireguard/wg0.conf
echo "Address = 169.254.66.1/24, fd00:666::1/64"  >> /etc/wireguard/wg0.conf
echo "ListenPort = 123" >> /etc/wireguard/wg0.conf
echo "PostUp = $postUp" >> /etc/wireguard/wg0.conf
echo "PostDown = $postDown" >> /etc/wireguard/wg0.conf
echo "SaveConfig = true" >>/etc/wireguard/wg0.conf
echo "" >> /etc/wireguard/wg0.conf
echo "[Peer]" >> /etc/wireguard/wg0.conf
echo "PublicKey = $clientPublicKey" >> /etc/wireguard/wg0.conf
echo "AllowedIPs = 169.254.66.2/32, fd00:666::2/128" >> /etc/wireguard/wg0.conf

#Write out server public key to file
echo "$serverPublicKey" > /etc/wireguard/serverPublicKey

#Enable routing
cat << EOF >> /etc/sysctl.conf
net.ipv4.ip_forward=1
net.ipv6.conf.all.forwarding=1
EOF
sysctl -p

#Enable and start the service
systemctl enable wg-quick@wg0
systemctl start wg-quick@wg0

#Create PiHole Unattended Installation Config File
mkdir /etc/pihole
echo "WEBPASSWORD=a3c7f03895d6dc02f126c6a3767aeed7d300847ca91e4ea1ee6057d9cd5aa58c
PIHOLE_INTERFACE=$interface
IPV4_ADDRESS=169.254.66.1/24
IPV6_ADDRESS=fd00:666::1/64
QUERY_LOGGING=true
INSTALL_WEB=true
DNSMASQ_LISTENING=all
PIHOLE_DNS_1=208.67.222.222
PIHOLE_DNS_2=208.67.220.220
PIHOLE_DNS_3=2620:0:ccc::2
PIHOLE_DNS_4=2620:0:ccd::2
DNS_FQDN_REQUIRED=true
DNS_BOGUS_PRIV=true
DNSSEC=false
TEMPERATUREUNIT=C
WEBUIBOXEDLAYOUT=traditional
API_EXCLUDE_DOMAINS=
API_EXCLUDE_CLIENTS=
API_QUERY_LOG_SHOW=all
API_PRIVACY_MODE=false" > /etc/pihole/setupVars.conf

#Make the PiHole installer think we don't want DHCP
echo '# 169.254.66.1' >> /etc/dhcpcd.conf

#Install PiHole
curl -L https://install.pi-hole.net | bash /dev/stdin --unattended

#Uninstall dhcpcd
apt purge -y dhcpcd5

##Create client configuration files

#Generate some information for the configuration files
serverPublicKeyFile=`cat /etc/wireguard/serverPublicKey`

#Shut down Wireguard to add new clients
wg-quick down wg0

#Write client configuration files
for i in {1..254}
do \
clientPrivateKey=`wg genkey`
clientPublicKey=`echo $clientPrivateKey | wg pubkey`
echo "[Interface]" > /etc/wireguard/clientconfig_$i
echo "PrivateKey = $clientPrivateKey" >> /etc/wireguard/clientconfig_$i
echo "Address = 169.254.66.$i/32, fd00:666::$i/64" >> /etc/wireguard/clientconfig_$i
echo "DNS = 169.254.66.1, fd00:666::1" >> /etc/wireguard/clientconfig_$i
echo "" >> /etc/wireguard/clientconfig_$i
echo "[Peer]" >> /etc/wireguard/clientconfig_$i
echo "PublicKey = $serverPublicKeyFile" >> /etc/wireguard/clientconfig_$i
echo "Endpoint = $endpoint" >> /etc/wireguard/clientconfig_$i
echo "AllowedIPs = 0.0.0.0/0, ::/0" >> /etc/wireguard/clientconfig_$i
echo "PersistentKeepalive = 15" >> /etc/wireguard/clientconfig_$i

#Add new clients to Wireguard server as peers
echo "" >> /etc/wireguard/wg0.conf
echo "[Peer]" >> /etc/wireguard/wg0.conf
echo "PublicKey = $clientPublicKey" >> /etc/wireguard/wg0.conf
echo "AllowedIPs = 169.254.66.$i/32, fd00:666::$i/128" >> /etc/wireguard/wg0.conf
done

#Bring Wireguard back up. Probably not necessary because of the reboot but doesn't hurt.
wg-quick up wg0

init 6

After the script finishes installing, it will reboot the instance so don't worry when you get disconnected. You were ( probably ) not hacked. The client config files are stored in /etc/wireguard and are each numbered so you can pass them out to different devices. They are also already in the server's wireguard config file as peers so you don't need to do anything with the wg0.conf on the server. If you are using a mobile Wireguard client and want a QR code to scan, you can run the following command and it will give you a totally safe and secure QR code that totally isn't quishing:

qrencode -t ansiutf8 < /etc/wireguard/clientconfig_1

That will print out the config for client configuration file 1. Change the name to print out the others. Again, they go from 1 to 254.

Once you are connected to the VPN, you can access the Pihole admin interface at http://169.254.66.1/admin . The default password in this install is 'cR0w' . From there you can admin the Pihole and change DNS servers, add block lists, etc.

And that's it. If you try it the way I described here and it doesn't work, ping me on Mastodon at https://infosec.exchange/@cR0w . It should work though since I verified it a few minutes before publishing this post.