Deploy a WireGuard Docker container with wg-easy

Deploy a WireGuard Docker container with wg-easy
Photo by Privecstasy / Unsplash

When I started using Pi-hole in 2018, I wanted to use Pi-hole filtering on my mobile internet connection, so I added PiVPN to one of my failover Pi-hole devices. Using the WireGuard iOS app and the on-demand setting, every time I left home and my phone disconnected from Wi-Fi, the VPN connected, and I continued using Pi-hole protections on my mobile device.

Since I started fiddling with Docker in mid-2023, I have migrated some of my homelab services, including my UniFi controller and LibreNMS, into Docker containers.

In April 2024, the PiVPN project announced on Reddit that maintenance was ending. Later that same day, I started poking around for an alternative that I could run in Docker. I found that solution in wg-easy.

An example Docker compose file based on my real-world use:

services:
  wg-easy:
    dns:
      - 192.168.21.2
      - 192.168.21.3
    environment:
      - PASSWORD=a_g00d_p@assword # web UI password
      - PORT=5150 # web port
      - UI_TRAFFIC_STATS=true
      - WG_DEFAULT_DNS=192.168.21.3,192.168.21.2
      - WG_DEVICE=eth0
      - WG_HOST=ddnshost.example.net # DDNS hostname
      - WG_MTU=1420
      - WG_PERSISTENT_KEEPALIVE=25
      - WG_PORT=51820 # wireguard port
    image: ghcr.io/wg-easy/wg-easy:latest
    hostname: wg-easy
    container_name: wg-easy
    volumes:
      - wg-easy_data:/etc/wireguard
    restart: unless-stopped
    mem_limit: 125m
    cap_add:
      - NET_ADMIN
      - SYS_MODULE
    network_mode: host

volumes:
  wg-easy_data:
    external: true

Additional iptables rules are needed on the Docker host to forward the traffic to the container:

iptables -t nat -A POSTROUTING -o ens192 -j MASQUERADE
iptables -A FORWARD -i ens192 -o wg0 -m state --state RELATED,ESTABLISHED -j ACCEPT
iptables -A FORWARD -i wg0 -o ens192 -j ACCEPT
# This is useful if you are trying to connect from your LAN
# to a device on your LAN via the VPN address (OPTIONAL)
iptables -t nat -A POSTROUTING -o wg0 -j MASQUERADE

The container interface is wg0 and the Docker host interface is ens192.

I used host networking mode because if I used the ipvlan driver or bridge driver, I couldn't connect to my Docker host after starting the VPN tunnel from my mobile device.

Next, I added a rule to my firewall to send 51820/udp on the WAN IP to the LAN IP of the Docker host.