How do I automate Mullvad VPN split tunneling on Linux?

I have an ubuntu media server with Plex, Mullvad and qBittorrent installed.

When I start up the machine all three auto start as intended include a full system VPN with Mullvad. However I want to exclude Plex from the VPN using the split tunneling feature of Mullvad. My current conundrum is you have to manually exclude Plex from the VPN using the Mullvad interface each time it restarts. This is unlike windows which has a toggle that stay on or off even after a restart. Does anyone know of a way to automate this process?

I’ve seen this question asked a few times but no concrete answer could be found (Source 1 / Source 2). For reference I’m fairly inexperienced with Linux and am trying my best to learn.

mullvad vpn comes with a command named “mullvad-exclude” for this purpose.

here’s what you’ll need to do so Plex starts with split tunneling by default (the commands you have to do may be slightly different):

sudo systemctl edit --full plex-media-server

you’ll find a like that looks like this (again, yours may look slightly different):

ExecStart=/usr/lib/plexmediaserver/Plex\x20Media\x20Server

edit it so it looks something like this:

ExecStart= /usr/bin/mullvad-exclude /usr/lib/plexmediaserver/Plex\x20Media\x20Server

reboot and it will be excluded by default on each boot

I’m also pretty inexperienced with linux, but I’ve come up with a solution that uses the mullvad split-tunnel CLI commands that works for me.

This is all on Ubuntu 24.04.1 LTS for the record.

I have a script in my home directory that determines the main PID of the plex process and adds it as an exclusion:

~/split_tunnel_plex.sh:

#!/bin/bash

# Get the status of Plex Media Server
status=$(systemctl status plexmediaserver)

# Extract the PID
pid=$(echo "$status" | grep 'Main PID' | awk '{print $3}')

# Add the PID to the Mullvad split tunnel
mullvad split-tunnel add $pid

Then I created a service to run the script at the correct time each boot:

/etc/systemd/system/plex_mullvad.service:

[Unit]
Description=Run script after Plex and Mullvad have started
After=plexmediaserver.service mullvad-daemon.service

[Service]
ExecStart=/home/MY_USERNAME_HERE/split_tunnel_plex.sh

[Install]
WantedBy=multi-user.target

Make sure the service is enabled:

sudo systemctl enable plex_mullvad.service

After rebooting, check to see if the process is excluded with mullvad split-tunnel list. I noticed there are actually 4 processes that are excluded but they all belong to plex. My best guess is that when an excluded process spawns another process it’s automatically excluded as well, but don’t quote me on that.

So even before your comment I was able to get to the systemctl file which I’m quite proud of! That being said I used the below command as the --full option told me not to edit that file and to use the below command instead (also didn’t need the dashes between the “plexmediaserver” bit in my case. The dashes caused it to not find the file.

sudo systemctl edit plexmediaserver

That being said, I’m presented with this screen which is very close to what you describe. the only issue is the commented out ExecStart line (green dot) seems totally different. It almost looks like I should be making a copy of the purple dot and then having that text (without the #) in the orange area up on top? Either that or use the below line in the orange box

ExecStart= /usr/bin/mullvad-exclude /usr/lib/plexmediaserver/Plex\x20Media\x20Server

Any final thoughts to push me across the finish line and forever archive this solution on the internet?

I also an debating if I need quotes around “Plex Media Server” since Linux doesn’t like spaces.

Edit - Also just realized \x20 is the equivalent of space. and revised the code up top

Tried to follow this but nothing seems to happen there’s nothing excluded when checking with “mullvad split-tunnel list”. I tried just running the script but it still didnt add anything to the list.

do me a favour and do

systemctl cat plexmediaserver

copy and paste it here so I can work with it and give you an idea of what to do

Was plex definitely running when you ran the script? I forgot that I had to set up a different service to ensure plex starts automatically, before logging in.

You can try running the commands one at a time to see where the problem might be. Maybe the format returned from `systemctl status plexmediaserver` is different on my system vs yours and the step to extract the PID fails.

# /etc/systemd/system/plexmediaserver.service
# DO NOT EDIT THIS FILE DIRECTLY!
#
# Plex Media Server’s variables can be customized by creating an ‘overide.conf’
# file using ‘systemctl edit plexmediaserver’ which will create the following;
# /etc/systemd/system/plexmediaserver.service.d/override.conf
#
# An example of the override.conf would be as follows if you wished to edit
# your user, group, temp directory, or app support directory (without the leading #)
#
# [Service]
# Environment=“TMPDIR=/path/to/new/tmp”
# Environment=“PLEX_MEDIA_SERVER_APPLICATION_SUPPORT_DIR=/home/myusername/Library/Application Support”
# User=myusername
# Group=mygroup
#

[Unit]
Description=Plex Media Server
After=network.target network-online.target

[Service]
Environment=“PLEX_MEDIA_SERVER_APPLICATION_SUPPORT_DIR=/var/lib/plexmediaserver/Library/Application Support”
Environment=PLEX_MEDIA_SERVER_HOME=/usr/lib/plexmediaserver
Environment=PLEX_MEDIA_SERVER_MAX_PLUGIN_PROCS=6
ExecStartPre=/bin/sh -c ‘/usr/bin/test -d “${PLEX_MEDIA_SERVER_APPLICATION_SUPPORT_DIR}” || /bin/mkdir -p “${PLEX_MEDIA_SERVER_APPLIC>
ExecStart=/bin/sh -c '\
export PLEX_MEDIA_SERVER_INFO_VENDOR=”$(grep ^NAME= /etc/os-release | awk -F= “{print \\$2}” | tr -d \\" )“; \
export PLEX_MEDIA_SERVER_INFO_MODEL=”$(uname -m)“; \
export PLEX_MEDIA_SERVER_INFO_PLATFORM_VERSION=”$(grep ^VERSION= /etc/os-release | awk -F= “{print \\$2}” | tr -d \\" )"; \
exec “/usr/lib/plexmediaserver/Plex Media Server”’
Type=simple
User=plex
Group=plex
Restart=on-failure
RestartSec=5
StartLimitInterval=60s
StartLimitBurst=3
SyslogIdentifier=Plex Media Server
StandardOutput=journal
StandardError=journal

[Install]
WantedBy=multi-user.target

# /etc/systemd/system/plexmediaserver.service.d/override.conf
ExecStart= /usr/bin/mullvad-exclude /usr/lib/plexmediaserver/Plex\x20Media\x20Server

Thanks for the help. Got it working couple differences though for anyone else trying to follow along in the future. I had to change the command for getting the status to status=$(systemctl status snap.plexmediaserver.plexmediaserver). As that was the only plex service I had. Also after rebooting and checking if the PID was excluded 6 actually showed up. Plex also says it isnt reachable from outside the network but taking my phone off wifi I was still able to connect. I dont know if any of these differences are related to the fact that this is all inside a VM on proxmox but it works for me.

in the orange box (as per the screenshot your previous comment), put exactly this and see how it works:

ExecStart=
ExecStart=/bin/sh -c '\
export PLEX_MEDIA_SERVER_INFO_VENDOR="$(grep ^NAME= /etc/os-release | awk -F= "{print \\$2}" | tr -d \\" )"; \
export PLEX_MEDIA_SERVER_INFO_MODEL="$(uname -m)"; \
export PLEX_MEDIA_SERVER_INFO_PLATFORM_VERSION="$(grep ^VERSION= /etc/os-release | awk -F= "{print \\$2}" | tr -d \\" )"; \
exec "/usr/bin/mullvad-exclude /usr/lib/plexmediaserver/Plex Media Server"'

Thanks for such a wonderful reply! TheGratitudeBot has been reading millions of comments in the past few weeks, and you’ve just made the list of some of the most grateful redditors this week! Thanks for making Reddit a wonderful place to be :slight_smile:

Still no dice with this. I added the above code to the orange area and Ctrl+X and “Y” to save it. I know it’s not working because Plex give an error saying it’s not available outside network with the VPN on and when I turn the VPN off, Plex is all green and “Fully accessible outside your network”. Hmmm the conundrum continues!

do you have lockdown mode enabled?
what port is plex running on?

lockdown mode is not enabled and plex is running on 32400

I eventually solved this by have a qbittorrent docker container and a gluetun docker container though mullvad and just running them together in isolation so everything else is excluded BUT qBittorrent instead of trying to add an exceptions. I appreciate the help though!

Having the exact issue as OP. Checked and I do think I have lockdown mode on.