BlocNotes

Notepad of a tinker, maker, hacker or whatever you call it :)

Setup Pi-Hole & WireGuard VPN on smartphone

WireGuard is a new VPN software, which is described as It aims to be faster, simpler, leaner, and more useful than IPSec, while avoiding the massive headache and using state-of-the-art cryptography.
Pi-hole is a black hole for Internet advertisements, ie a server blocking advertisements at DNS level.

I have Pi-hole on my home network, but wanted to have it also as DNS server on my phone when I am not home. As I have a bad DSL connection, I can not rely on my home server. So I put Pi-hole on a VPS server I rent: it works, flawlessly.
Nevertheless it was an open DNS resolver, which can be used to amplify DDoS attacks; there is already 2212 unsecured Pi-hole ont the Internet, so I do not want to add another one.

Pi-hole provides documentation to use OpenVPN, even to redirect only DNS requests but it is not efficient on a phone as it is not a stateless connection, so it consumes battery; moreover GSM/Wifi switch is not really handled, you have to reconnect. The solution comes from WireGuard which is stateless, and provides Android & iOS apps. I struggle to configure everything, so here is what I did:

Configuration

Pi-Hole in Docker container

Pi-holes provides a [convenient Docker]https://hub.docker.com/r/pihole/pihole/) container so it is easy to build a Docker-compose file on top.

Here is an example, as there is already other Docker services serving on ports 80 and 443 through jwilder container providing reverse proxy, so I add this container to the same network.
Pi-hole also recommends to have it as default on the machine in order to replace adds by white pages, it helps to keep pages layout, so jwilder's Docker environment variable DEFAULT_HOST should be set to Pi-hole's VIRTUAL_HOST value.
If you do not use jwilder container just delete VIRTUAL_HOST, VIRTUAL_PORT and networks related options.

version: '3.5'

services:
  pihole:
    image: pihole/pihole:latest
    dns:
      - 127.0.0.1
      - 1.1.1.1
    ports:
      - '127.0.0.1:53:53/tcp'
      - '127.0.0.1:53:53/udp'
      # Adapt to WireGuard interface
      - '192.168.2.1:53:53/tcp'
      - '192.168.2.1:53:53/udp'
    volumes:
      # Adapt to folders
      - ../../data/pi-hole/etc:/etc/pihole/
      - ../../data/pi-hole/dnsmasq.d:/etc/dnsmasq.d
    networks:
      - network-proxy
    environment:
      # Adapt to server IP address
      ServerIP: X.X.X.X
      PROXY_LOCATION: pihole
      # Adapt to domain
      VIRTUAL_HOST: pihole.YOURDOMAIN.ext
      VIRTUAL_PORT: 80
    extra_hosts:
      # Resolve to nothing domains (terminate connection)
      #  'nw2master.bioware.com nwn2.master.gamespy.com:0.0.0.0'
      # LAN hostnames for other docker containers using jwilder
      - 'pihole pihole.yourDomain.lan:5.135.166.67'
    restart: unless-stopped

networks:
  network-proxy:
    name: "https-proxy"

WireGuard

Server

WireGuard configuration was more difficult. My server is running Debian 9 where Debian systemd documentation can not be used as the version is too old, and I never found out why regular documentation was failing with wg-quick.

So I had to use the old /etc/network/interfaces file. Replace eth0 with your "main" interface.

auto wg0
iface wg0 inet static
        address 192.168.200.1
        netmask 255.255.255.0
        pre-up ip link add $IFACE type wireguard
        pre-up wg setconf $IFACE /etc/wireguard/$IFACE.conf
        pre-up iptables -A FORWARD -i wg0 -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE;
        post-down iptables -D FORWARD -i wg0 -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE; 
        post-down ip link del $IFACE

Now we have to configure WireGuard itself in /etc/wireguard/wg0.conf, where wg0 is WireGuard interface name:

[Interface]
ListenPort = 8124
PrivateKey = REPLACE_WITH_YOUR_PRIVATE_KEY

[Peer]
PublicKey = REPLACE_WITH_CLIENT_PUBLIC_KEY_GENERATED_AFTER
AllowedIPs = 0.0.0.0/0

Server keys are generated as per documentation: wg genkey | tee privatekey | wg pubkey > publickey
Then route should be added: ip route add 192.168.2.2/32 dev wg0

Android client

  1. Generate public/private key thanks to GENERATE button
  2. Interface->Addresses is client IP address. ex: 192.168.200.2
  3. Interface->Listen port is the same than wg0.conf. ex: 8124
  4. Interface->DNS servers is your server WireGuard IP. ex: 192.168.200.1
  5. Peer->Public key is the server's public key
  6. Allowed IP should be serverIp/24 but I do not know why it forwards only DNS queries to the server. Putting 0.0.0.0/0 makes it work, I have to figure out why.
  7. Endpoint is server public IP address:port. ex: X.X.X.X:8124