Running a Self-Hosted Mullvad Exit Node on TrueNAS

For roughly a year, my phone, laptop and desktop relied on the Tailscale-Mullvad integration to route traffic through Mullvad’s VPN. The add-on cost 5 dollars a month.
That configuration ended when my credit card got rejected and cancelled twice. So I moved to paying Mullvad directly by SEPA for 12 months.

I replaced the add-on with a self-hosted equivalent on my TrueNAS server. The stack consists of two containers managed through Portainer:

  • mullvad-exit-gw runs gluetun configured with a Mullvad WireGuard endpoint in a city and country of my choice.
  • mullvad-exit-ts runs tailscale and advertises itself to the tailnet as an exit
    node under the hostname mullvad-de. The Tailscale container shares a network namespace with the gluetun container via network_mode: “service:mullvad-exit-gw”. All traffic from the Tailscale sidecar,
    including its connection to the Tailscale coordination server, therefore leaves the host through the Mullvad tunnel. On any tailnet client, the command tailscale set –exit-node=mullvad-de –exit-node-allow-lan-access routes outbound traffic while preserving access to the local network. Persistent state for Tailscale lives on a host bind mount at
    /mnt/zfs_tank/Applications/tailscale-mullvad rather than a TrueNAS-managed ix_volume. This allows the stack to survive a Portainer reinstallation without forcing a fresh device authorization.

Fixing a DNS leak

The initial deployment passed Mullvad’s IP check but failed its DNS check, with the result reporting Cloudflare resolvers in the city I chose. The cause lies in gluetun’s default behavior: it operates its own DNS-over-TLS resolver, and that resolver uses Cloudflare upstream unless directed otherwise. The VPN tunnel was correctly configured, but the resolver running above it bypassed Mullvad entirely. Two environment variables on the gluetun container correct this:

DOT: “off”
DNS_ADDRESS: “194.242.2.4”

The address 194.242.2.4 is Mullvad’s anycast resolver with content filtering for ads, trackers, and malware domains. I also configured the same resolver as the tailnet’s global nameserver in the Tailscale admin console, ensuring that any device routed through mullvad-de performs DNS lookups through Mullvad rather than its local resolver.

,

Leave a comment

Discover more from /root

Subscribe now to keep reading and get access to the full archive.

Continue reading