Wireguard VPN Endpoint with Anonymous Outgoing Traffic

I wanted a VPN endpoint that would allow me to:

  • access my network (say, my home network or my VPC)
  • browse the internet anonymously (such as through a commercial VPN like ExpressVPN, CyberGhost, PIA, or Mullvad)

That way when traveling I didn't have to choose between accessing my internal network and browsing the internet anonymously.  The solution I chose was Wireguard running on a GNU/Linux computer.

Configuring External VPN

Start by configuring the external VPN - you'll need to first download this from your commercial VPN provider. Once downloaded, add the line FwMark = 45 under [Interface] and store the file as /etc/wireguard/wg-ext.conf.  

[Interface]
PrivateKey = {Private key of External VPN WG server}
Address = 10.5.0.2/32
FwMark = 45

[Peer]
PublicKey = {Public Key of VPN Server}
AllowedIPs = ::/0, 0.0.0.0/0
Endpoint = {VPN IP}:51820
wg-ext.conf

Test that this works with wg-quick up wg-ext and run curl api.ipify.org to make sure you're routing traffic through the VPN.

You can run wg-show to see the active wireguard connections.

Configuring Private VPN

Now you'll need to set up your own internal VPN.

I won't go into the details of generating keys - but the ArchWiki has a great guide on this.

I will assume you followed that guide, generated the appropriate private/public and preshared keys and shared those with some client (e.g., an iPhone) so you can test access.

After following the ArchWiki guide you'll need to make minor modifications

set PostUp rules to:

  • launch wg-ext when wg-pvt launches
  • Forward traffic to wg-ext
  • Forward DNS traffic from the tunnel

set up route to

  • allow local network connections route add...

Link this tunnel with wg-ext by placing FwMark = 45 under Interface

[Interface]
Address = 10.100.100.1/24
ListenPort = 51820
PrivateKey = {Private key of home WG server}

# Launch wg-ext
PostUp = systemctl start wg-quick@wg-ext

# Accept sending and receiving on wg-pvt
PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -A FORWARD -o %i -j ACCEPT;

# Forward traffic to wg-ext
PostUp = iptables -t nat -A POSTROUTING -o wg-ext -j MASQUERADE;

# Forward DNS requests on :53 to wg-ext's DSN server
PostUp = iptables -t nat -A PREROUTING -p tcp --dst 10.100.100.1 --dport 53 -j DNAT --to-destination 10.5.0.1:53

# allow local network connections
PostUp = route add -net 192.168.0.0/24 dev eth0
PostUp = iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE


# Bring these rules back down
PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -D FORWARD -o %i -j ACCEPT;
PostDown = iptables -t nat -D POSTROUTING -o wg-ext -j MASQUERADE;
PostDown = iptables -t nat -A PREROUTING -p udp --dst 10.100.100.1 --dport 53 -j DNAT --to-destination 10.5.0.1:53
PostDown = route delete -net 192.168.0.0/24 dev eth0

FwMark = 45



[Peer]
# This is your client (e.g., laptop you want to
PublicKey = {Public Key for client}
PresharedKey = {PSK for client}
AllowedIPs = 10.100.100.2/32
wg-pvt.conf (your private VPN to access your home/VPC)

Where

  • 192.168.0.0/24 is your "home/vpc" network
  • 10.5.0.1 is the DNS server of the "external vpn"

FwMark = 45 is some unique number in both tunnels - this allows local traffic to be excluded

And then run sudo systemctl enable wg-quick@wg-pvt.service to launch the private VPN and have your internet traffic routed through your commercial VPN!

The three biggest snags I had run into that made a huge difference were

  • not being aware of FwMark
  • not realizing I had to route local traffic back to eth0 with route add
  • not realizing I had to add an iptable rule to forward dns requests

Troubleshooting:

No internet access from server?

  • The issue is probably with the commercial VPN

No domain resolution on the server?

  • The issue is probably in dns requests not making it to the commercial VPN (i.e., ping 8.8.4.4 works but ping google.com does not)