I sometimes surf the web from public WiFi when I’m not at home and unable to use my home network. These networks present some threats and using a VPN can mitigate some of those them, although I need to research the threat they present better.

VPNs can protect my traffic from observation. I realize that using them doesn’t solve this problem but moves it from needing to trust WiFi provider to trusting the VPN provider.

Malicious advertising is another potential threat that I would like to mitigate.

To solve both of these problems, I decided to implement a VPN running pi-hole to a VM in a cloud that I control.

These techniques do not mitigate all threats. For example, NSO-style zero-click text messages are unaddressed and probably need OS-level safeguards in place.

Installing Wireguard on an AWS Instance

I followed this blog post to set up my AWS VPN. The directions were clear, and I set it up without a problem on my first try. To keep things simple, my VM has same OS as in the example (Ubuntu 18.04.6 LTS) even though new versions are available.

Adding a New Client

To add a new client and generate a QR code for easy entry on mobile,

$ sudo add-client.sh  # prompts for user name, e.g. "client0"
$ qrencode -t ansiutf8 < client0.conf

The client files are stored in /etc/wireguard/clients. Whenever a client is added or modified, wireguard must be restarted,

$ sudo systemctl restart wg-quick@wg0

Once pi-hole was set up (directions below), I reconfigured the client to use it for DNS, see DNS parameter below,

[Interface]
PrivateKey = <KEY>
Address = 10.50.0.7/32
DNS = 172.21.0.2

[Peer]
PublicKey = <PublicKey>
PresharedKey = <PresharedKey>
AllowedIPs = 0.0.0.0/0, ::/0
Endpoint = <IP address of AWS instance>:54321
PersistentKeepalive=25

Example SSH config file

While this step isn’t necessary to have less to remember, I configured SSH to access my AWS instance by a short name, ssh wireguard, by creating a SSH configuration file and copying to ~/.ssh/config:

Host wireguard
HostName <IP address>
User <username>
IdentityFile <path to PEM>

Pi-Hole Installation

TODO intro

I investigated setting up pi-hole running natively but found running it in docker to be easier because it eliminates resource conflicts with already running processes.

docker-compose File Modifications

The default docker-compose file presents the pi-hole’s ports on localhost, but these were already in use by systemd-resolved. I modified the file to define a docker network instead, 172.21.0.2 below.

version: "3"

# More info at https://github.com/pi-hole/docker-pi-hole/ and https://docs.pi-hole.net/
services:
  pihole:
    container_name: pihole
    image: pihole/pihole:latest
    environment:
      TZ: 'America/New_York'
      WEBPASSWORD: 'raspiraspi'
    # Volumes store your data between container upgrades
    volumes:
      - './etc-pihole:/etc/pihole'
      - './etc-dnsmasq.d:/etc/dnsmasq.d'
    # Recommended but not required (DHCP needs NET_ADMIN)
    #   https://github.com/pi-hole/docker-pi-hole#note-on-capabilities
    cap_add:
      - NET_ADMIN
    restart: unless-stopped
    networks:
      pihole:
        ipv4_address: 172.21.0.2

networks:
  pihole:
    driver: bridge
    ipam:
       config:
         - subnet: 172.21.0.0/16

Accessing Pi-Hole’s Web Interface

Pi-hole presents an informative web interface on port 80. Since it is running inside a docker container on a private docker network, we need to SSH with remote port forwarding to access it. After running the ssh command below, the web interface can be accessed on your local machine from port 8181 (https://localhost:8181)

$ ssh -f -4 -i <PEM> -N -L 8181:172.21.0.2:80 wireguard

Options:

  • -f puts SSH into background after connection
  • -4 uses IPv4, otherwise there is a bind error
  • -N does not execute a remote command, recommended for forwarding ports
  • -L local port forwarding

Changing Pi-Hole’s Password

The docker-compose file has an option (WEBPASSWORD) to specify the pi-hole’s password, which is needed to see more extensive data on the web interface. Defining this parameter didn’t work for me. I needed to shell into the container and set it manually.

$ sudo docker exec -it <container hash> /bin/bash
$ pihole -a -p <PASSWORD>

Next Steps

Now that I think more about it, the fact that most phones are sitting out on the Internet unprotected seems unbelievable, given the protections provided to desktops in enterprises. People’s phones carry very sensitive personal and financial details which makes them juicy targets to hackers. I should understand the threat model and potential tools better.