DEV Community

Cover image for How to run Tailscale and Mullvad together on Manjaro Linux
Vitalii Yulieff
Vitalii Yulieff

Posted on

How to run Tailscale and Mullvad together on Manjaro Linux

You want Mullvad privacy and Tailscale remote access on one Linux machine. By default they conflict. This guide makes them run together.

The Problem πŸ€”

Both tools change how your machine routes traffic.

Mullvad sends all traffic through a VPN and adds a kill switch. Tailscale builds a private network between your devices. Run both on one machine and they conflict.

The first symptom: tailscale up hangs. No error. No login link. No output.

The kill switch causes this. Mullvad's firewall drops any packet without the Mullvad mark (0x6d6f6c65). The Tailscale daemon sends first packets without the mark, so the firewall drops them. The daemon never reaches the Tailscale control server, so login never starts.

A second problem hits IPv6. Mullvad removes the IPv6 default route. IPv6 attempts fail with network is unreachable.

The Fix: mullvad-exclude πŸ”§

You do not disable the kill switch. You add an exception.

mullvad-exclude is Mullvad's split-tunnel tool. Run a program under mullvad-exclude and Mullvad tags the traffic with the mark. The traffic leaves the machine. Everything else stays inside the VPN.

Run the Tailscale daemon under mullvad-exclude:

mullvad-exclude tailscaled
Enter fullscreen mode Exit fullscreen mode

Make the Fix Survive Reboots ♻️

A typed command dies on reboot. systemd restarts tailscaled from the unit file and drops your wrapper.

Add a systemd drop-in at /etc/systemd/system/tailscaled.service.d/override.conf:

[Unit]
After=mullvad-daemon.service
Wants=mullvad-daemon.service

[Service]
ExecStart=
ExecStart=/usr/bin/mullvad-exclude /usr/sbin/tailscaled --state=/var/lib/tailscale/tailscaled.state --socket=/run/tailscale/tailscaled.sock --port=${PORT} $FLAGS
Enter fullscreen mode Exit fullscreen mode

Reload and restart:

sudo systemctl daemon-reload
sudo systemctl restart tailscaled
Enter fullscreen mode Exit fullscreen mode

Two lines do the work.

First, the empty ExecStart= line. A service holds one ExecStart. To replace the original, clear the original with an empty line, then set your own. Skip the empty line and the service fails to start.

Second, After= and Wants=mullvad-daemon.service. These set boot order. If tailscaled starts before the Mullvad daemon, mullvad-exclude finds no daemon and Tailscale fails again. The failure shows only after a reboot. These two lines start Mullvad first.

The DNS Gotcha 🌐

After tailscale up, your internet looks dead. Pages do not load.

The firewall is not the cause here. DNS is. Tailscale MagicDNS took over the system resolver. Normal lookups break with Temporary failure in name resolution.

Refuse MagicDNS:

sudo tailscale up --accept-dns=false
Enter fullscreen mode Exit fullscreen mode

This sets CorpDNS=false in your saved preferences. The setting holds across reboots.

Remote Login with Tailscale SSH πŸ”‘

Now add remote login.

Skip OpenSSH. Tailscale ships SSH built in. No open port 22. No password file. Access uses your Tailscale identity and ACLs.

Enable Tailscale SSH:

tailscale set --ssh
Enter fullscreen mode Exit fullscreen mode

This saves RunSSH=true and holds across reboots.

Use tailscale set for changes, not tailscale up. tailscale up resets any flag you omit. tailscale set changes only the flags you name. So tailscale set keeps --ssh and --accept-dns=false safe.

A Self-SSH Limit πŸ•΅οΈ

Tailscale SSH from a host to the same host fails.

The traffic crosses the WireGuard tunnel. A node does not route to the same node. Test from a different device. A connection refused from the same machine is expected, not a fault.

Verify After Reboot βœ…

Confirm the setup survives a restart.

Six checks pass when the setup works:

  • tailscaled is active
  • tailscaled runs under mullvad-exclude
  • the tailnet is up
  • SSH is enabled
  • normal DNS resolves
  • normal traffic exits through Mullvad

One script runs all six:

#!/usr/bin/env sh
echo "== tailscale + mullvad coexistence check =="

systemctl is-active --quiet tailscaled \
  && echo "PASS  tailscaled active" \
  || echo "FAIL  tailscaled not active"

systemctl show tailscaled -p ExecStart | grep -q mullvad-exclude \
  && echo "PASS  running under mullvad-exclude" \
  || echo "FAIL  not under mullvad-exclude"

if tailscale status >/dev/null 2>&1 && ! tailscale status 2>&1 | grep -qi "logged out"; then
  echo "PASS  tailnet up (logged in)"
else
  echo "FAIL  tailnet down / logged out"
fi

tailscale debug prefs 2>/dev/null | grep -q '"RunSSH": true' \
  && echo "PASS  tailscale SSH enabled" \
  || echo "FAIL  SSH pref off"

getent hosts google.com >/dev/null 2>&1 \
  && echo "PASS  normal DNS works" \
  || echo "FAIL  DNS broken"

curl -fsS --max-time 8 https://am.i.mullvad.net/connected 2>/dev/null | grep -qi "connected to Mullvad" \
  && echo "PASS  normal traffic via Mullvad" \
  || echo "FAIL  not protected by Mullvad"
Enter fullscreen mode Exit fullscreen mode

Reboot. Run the script. Six PASS lines confirm the setup.

πŸ† Done. Mullvad protects your normal traffic. Tailscale reaches your devices and serves SSH. The setup holds across restarts.

Top comments (0)