Skip to content

Mullvad VPN

Mullvad VPN configuration for routing traffic through a VPN tunnel.

Available Options

This page documents 9 configuration options.

nixflix.mullvad.enable

Whether to enable Mullvad VPN.

Using Tailscale with Mullvad

If you want to use Tailscale alongside Mullvad VPN, you'll need to configure nftables rules to route Tailscale traffic around the VPN. Add this to your NixOS configuration:

{
  networking.nftables = {
    enable = true;
    tables."mullvad-tailscale" = {
      family = "inet";
      content = ''
        chain prerouting {
          type filter hook prerouting priority -100; policy accept;
          ip saddr 100.64.0.0/10 ct mark set 0x00000f41 meta mark set 0x6d6f6c65;
          udp dport 41641 ct mark set 0x00000f41 meta mark set 0x6d6f6c65;
          # Allow incoming UDP on Tailscale port to bypass Mullvad
          udp dport 41641 ct mark set 0x00000f41 meta mark set 0x6d6f6c65;
        }

        chain outgoing {
          type route hook output priority -100; policy accept;
          meta mark 0x80000 ct mark set 0x00000f41 meta mark set 0x6d6f6c65;
          ip daddr 100.64.0.0/10 ct mark set 0x00000f41 meta mark set 0x6d6f6c65;
          # Allow outgoing UDP from Tailscale port to bypass Mullvad
          udp sport 41641 ct mark set 0x00000f41 meta mark set 0x6d6f6c65;
        }
      '';
    };
  };
}

This ensures Tailscale traffic (100.64.0.0/10) bypasses the Mullvad VPN tunnel.

If you want tailscale exit node traffic to be routed through mullvad instead of the server's own established internet connection, then you need the following:

networking.nftables = {
  enable = true;
  tables."mullvad-tailscale" = {
    family = "inet";
    content = ''
      chain prerouting {
        type filter hook prerouting priority -50; policy accept;

        # Allow Tailscale protocol traffic to bypass Mullvad
        udp dport 41641 ct mark set 0x00000f41 meta mark set 0x6d6f6c65;

        # Allow direct mesh traffic (Tailscale device to Tailscale device) to bypass Mullvad
        ip saddr 100.64.0.0/10 ip daddr 100.64.0.0/10 ct mark set 0x00000f41 meta mark set 0x6d6f6c65;

        # Exit node traffic: DON'T mark it - let it route through VPN without bypass mark
        # Clear meta mark so it routes through Mullvad (no ct mark means Mullvad won't drop in NAT)
        iifname "tailscale0" ip daddr != 100.64.0.0/10 meta mark set 0;

        # Return traffic from VPN: Mark it so it routes via Tailscale table
        # Use bypass mark so it doesn't get routed back through Mullvad
        iifname "wg0-mullvad" ip daddr 100.64.0.0/10 ct mark set 0x00000f41 meta mark set 0x6d6f6c65;
      }

      chain outgoing {
        type route hook output priority -100; policy accept;
        meta mark 0x80000 ct mark set 0x00000f41 meta mark set 0x6d6f6c65;
        ip daddr 100.64.0.0/10 ct mark set 0x00000f41 meta mark set 0x6d6f6c65;
        # Allow outgoing UDP from Tailscale port to bypass Mullvad
        udp sport 41641 ct mark set 0x00000f41 meta mark set 0x6d6f6c65;
      }

      chain postrouting {
        type nat hook postrouting priority 100; policy accept;

        # Masquerade exit node traffic going through Mullvad
        iifname "tailscale0" oifname "wg0-mullvad" masquerade;
      }
    '';
  };
};
Typeboolean
Default
false
Example
true
Declared inmodules/mullvad.nix

nixflix.mullvad.accountNumber

Mullvad account number.

Warning

Can be a plain string (visible in Nix store) or { _secret = /path/to/file; } for file-based secrets.

Plain-text secrets will be visible in the Nix store. Use { _secret = path; } for sensitive data.

Typestring or (submodule)
Default
null
Example
{ _secret = "/run/secrets/secret-file"; }
Declared inmodules/mullvad.nix

nixflix.mullvad.autoConnect

Automatically connect to VPN on startup

Typeboolean
Default
true
Declared inmodules/mullvad.nix

nixflix.mullvad.dns

DNS servers to use with the VPN. Defaults to Cloudflare (1.1.1.1, 1.0.0.1) and Google (8.8.8.8, 8.8.4.4) DNS servers.

Typelist of string
Default
["1.1.1.1" "1.0.0.1" "8.8.8.8" "8.8.4.4"]
Example
[
  "194.242.2.4"
  "194.242.2.3"
]
Declared inmodules/mullvad.nix

nixflix.mullvad.enableIPv6

Wether to enable IPv6 for Mullvad

Typeboolean
Default
false
Declared inmodules/mullvad.nix

nixflix.mullvad.killSwitch.allowLan

Allow LAN traffic when VPN is down (only effective with kill switch enabled)

Typeboolean
Default
true
Declared inmodules/mullvad.nix

nixflix.mullvad.location

Mullvad server location as a list of strings.

Format: ["country"] | ["country" "city"] | ["country" "city" "full-server-name"] | ["full-server-name"]

Examples: ["us"], ["us" "nyc"], ["se" "got" "se-got-wg-001"], ["se-got-wg-001"]

Use "mullvad relay list" to see available locations. Leave empty to use automatic location selection.

Typelist of string
Default
[ ]
Example
[
  "us"
  "nyc"
]
Declared inmodules/mullvad.nix

nixflix.mullvad.gui.enable

Whether to enable Mullvad GUI application.

Typeboolean
Default
false
Example
true
Declared inmodules/mullvad.nix

nixflix.mullvad.killSwitch.enable

Whether to enable VPN kill switch (lockdown mode) - blocks all traffic when VPN is down.

Typeboolean
Default
false
Example
true
Declared inmodules/mullvad.nix