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?

  • WireGuard is a simple and fast VPN solution. It's a lot leaner than OpenVPN and is easier to set up. A lot of attention is directed towards WireGuard at the minute, especially because it was recently merged into Linus Torvalds's tree. This means it'll be included in the next release of the Linux kernel.
  • Pi-hole is a project which describes itself as a 'black hole for internet advertisements'. It's a DNS server intended to run on a Raspberry Pi on your local network which you then point your router at such that every device in your home resolves DNS through it. Pi-hole blacklists a tonne of shady domains so that when any client on your network requests them, the name just simply doesn't resolve. The upshot? Traffic to dodgy domains is blocked network-wide.

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?

  • Address = specifies the subnet for the interface. This just means that the range of IP addresses through to will be used for our VPN.
  • PostUp specifies the commands to run when the WireGuard interface is brought up. In this case, when we bring up wg0, we will enable IPv4 and IPv6 forwarding as well as configure iptables to perform NAT for traffic passing through our internet-facing interface.
  • PostDown specifies the commands to run when the WireGuard interface is brought down. In this case we just remove the NAT rules we created in PostUp.
  • ListenPort defines the port the VPN will listen on.
  • PrivateKey specifies the VPN server's private key (which we made earlier). This is required to decrypt traffic from our clients.

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?

  • PublicKey specifies the peer's public key, naturally. We need to include this so that the server knows how to encrypt traffic destined for this peer.
  • AllowedIPs specifies a range of IP addresses that this client may use within the VPN. It is not a list of IPs that you are allowed to connect from, as the name might suggest. In our case, we're saying 'this client can only use the IP inside our VPN' -- we refuse to route any traffic from this peer that does not use this IP inside the VPN.

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

    Address =
    PrivateKey = $client_private_key
    DNS =

    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!