< Back to Posts

Portable Pi-hole With WireGuard

Joe Ellis


I was a Private Internet Access customer for six years. The price hikes over the years didn’t phase me, but what really concerned me was the acquisition by Kape Technologies at the end of 2019. Long story short: the company that acquired PIA has a horrible privacy track record. Can we still trust PIA?

I decided to cancel my subscription and spin up my own VPN. There are some downsides to doing this (for example, your IP won’t be shared with others so you’ll lose the anonymity aspect), but it works fine for keeping your traffic safe on insecure networks.

One thing I knew I would miss from PIA’s VPN service is MACE, which blocks malware and ads while you’re connected. Thankfully, we can roll our own MACE-like blocker with Pi-hole.

If you want to break free from a VPN subscription and roll your own, this post is for you.

The Projects We’ll Be Using

What is WireGuard, and what is Pi-hole?

We’ll be using WireGuard to set up our actual VPN, and Pi-hole for ad-blocking.

Hosting Your VPN Server

For the purposes of this post I’ll assume you’re setting up your VPN on a VPS. I use DigitalOcean. You can use whatever. If your main concern is privacy, make sure that you trust the VPS provider!

I’m also going to assume that your server is running some flavor of Ubuntu.

Step One: Setting up the Firewall on Your Server

We want to enable the firewall, deny traffic by default, and allow all traffic coming from our VPN clients. We’re going to use the subnet for our VPN. We reserve for our VPN.

First, lets add some rules:

# ufw default deny
# ufw allow from

If you’re connected via SSH, make sure you add a rule to allow SSH traffic.

# ufw allow 22/tcp

Finally, enable the firewall.

# ufw enable

Step Two: WireGuard Server Setup

First, install the wireguard package with:

# add-apt-repository ppa:wireguard/wireguard
# apt-get update && apt-get install wireguard

Once that’s done, it’s time to generate a keypair. WireGuard avoids the code-bloat of key-exchange by delegating the task to the users, a bit like SSH. All peers in your VPN have a public-key and a private-key used for encryption.

We’ll generate a keypair for the server in /etc/wireguard/keys/server.

# mkdir -p /etc/wireguard/keys/server && cd /etc/wireguard/keys/server
# wg genkey | tee privatekey | wg pubkey > publickey

Here, wg genkey generates a private key. We write that key to the disk with tee. We also pass the private key through to wg pubkey to generate a public key, which we also write to the disk.

Now we configure WireGuard.

# vim /etc/wireguard/wg0.conf

Since our file is called wg0.conf, our WireGuard interface will be called wg0. In this file, we want to write the following:

Address =
PostUp = sysctl -w net.ipv4.ip_forward=1
PostUp = sysctl -w net.ipv6.conf.all.forwarding=1
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
PrivateKey = $private_key_from_earlier

What does this do?

Step Three: Setting up a Client

Next, we want to set up our clients. I’ll give you the steps to do this for just one client – repeat for each client you have.

First of all, make sure you have WireGuard installed on your client. I’ll assume you’re using macOS, since that’s what I used. The steps should be similar for Linux.

$ brew install wireguard

Now generate a public-private keypair for the client. Keep these somewhere safe. /etc/wireguard/keys would be a good location.

$ wg genkey | tee privatekey | wg pubkey > publickey

Now, on the server, we must edit /etc/wireguard/wg0.conf and add ourselves as a peer. Add the following to the bottom of /etc/wireguard/wg0.conf:

[Peer] # my macbook
PublicKey = $client_public_key
AllowedIPs =

What are we doing here?

Now let’s create a config file for the VPN on the client.

Address =
PrivateKey = $client_private_key

PublicKey = $server_public_key
Endpoint = $server_public_ip:51820
AllowedIPs =, ::/0

# Keep the connection alive
PersistentKeepalive = 25

That should be the VPN configured. Import the config you created into your WireGuard client and test the connection.

Step Four: Setting up Pi-hole to Block Ads

WIP! Come back soon!