Solution 1:


Note: (2016-02-22) I've realised this config leaks DNS queries to the torrent trackers through the normal WAN, instead of sending it through the VPN. I'm investigating how to fix this. I'm going to keep running my config though, since the connection itself does use the VPN properly.


Update: I've noticed that when I set Transmission to download overnight on the Beaglebone, CPU usage goes to 100% after a while. It doesn't seem to happen after the same amount of time, sometimes it's fine all night, other times it struggles after 10 minutes. It can also recover by pausing all torrents and waiting for CPU load to return to normal, then starting again. I'm still investigating. A workaround might be to pause and resume torrents periodically, although it's not a very good workaround. Note this issue only applies to the Beaglebone, and probably other ARM devices. I've never had this issue on a x86 CPU.


Introduction

I've developed and tested this solution for Ubuntu 14.04, running on a BeagleBone Black. The VPN provider I am using is called ibVPN. It should work with any supported hardware though (i.e. on a "normal" x86 computer), with any OpenVPN compatible VPN provider - and should probably work for 14.10 or later. At some point I believe Ubuntu will use SystemD for boot, which will mean the Upstart scripts used here will need to be migrated. Update: Jonas Kalderstam has an answer below for using SystemD. I'm also assuming that ufw is being used as the firewall, if you are using something different then the ufw commands here will need to be changed.

I assume that all work is done over an SSH connection to the system, although it would work just as well if typed out into a physical terminal.

This is quite a long tutorial, please read all of it first and make sure you are comfortable with what you will be doing.

I've also noticed that Transmission does not properly bind to an IP address for sending UPnP/NAT-PMP data - i.e. torrent data correctly goes through the VPN, but if UPnP port forwarding is enabled Transmission will request the port forward from the local router, not through the VPN from the VPN server. Hence I've made the Upstart script disable port forwarding, since it might appear as though it has worked, but it has not. It should be possible to use iptables and iproute to force all traffic from the debian-transmission user through the VPN, but I am still looking into this. It should also work if the default route was changed to send all Internet data through the VPN, but I didn't want to do that because I use this server for other things too, and this would also cause all system updates to come through the VPN. The effect of this is that Transmission will probably download torrents slower than it could if port forwarding worked - but I've found that reasonable speeds can be achieved for most torrents without port forwarding. This question has further information if you really want to get UPnP working over the VPN. Update: falk0069 has a fantastic tip below for helping to encourage UPnP over the VPN.

Installing and configuring OpenVPN

I'd recommend that you try getting your VPN connection to work using Ubuntu before trying to get it to work here - i.e. from a desktop. This will confirm that you have the correct configuration and reduce time spent debugging.

First, install the required packages

sudo apt-get install openvpn

Next, make a directory to store the configuration files in. I'm using /opt/ibVPN, since that's the provider I'm using. Change it to whatever you like.

sudo mkdir /opt/ibVPN

The first thing to do in this new directory is to create the config file for running the VPN client. ibVPN provides a basic config file for Linux users, which I've mostly just copied and pasted.

cd /opt/ibVPN
sudo vim config.ovpn

Copy and paste your edited version into vim, using the settings for your VPN provider. (FYI, paste in the Ubuntu terminal is Ctrl+Shift+V) You should be able to get this from your VPN provider.

remote 888.888.888.888 1194 udp      #This address will be different for you
client
dev tap1
resolv-retry infinite
script-security 3 system
explicit-exit-notify 3
persist-key
mute-replay-warnings
ca ibvpn.com.crt
comp-lzo
verb 3
mute 20
ns-cert-type server
fragment 1300
route-delay 2
reneg-sec 0
max-routes 5000
link-mtu 1578

auth-user-pass pass
auth-nocache
persist-tun
route-noexec
lport 1195
lladdr 00:FF:11:AA:BB:CC
route-up "/opt/home/openvpn/route-up.sh"
down "/opt/home/openvpn/down.sh"

For those unfamiliar with vim, press Insert to type or paste text, then press Escape and type :wq to save and quit. Of course, you don't have to use vim - any text editor will work.

I'll quickly explain this config file: The first 18 lines specify the specific settings to use with the server, these came from ibVPN - yours will probably be slightly different if you have a different provider. The next lines are modified options I've specified.

  • If your settings file had any lines with auth-user*, comment these out. For this setup to work automatically, we need to have a file with the username and password in it - so make sure the password you chose for the VPN provider is strong, random, and unique.

  • The auth-user-pass pass tells OpenVPN to look for a file called pass to read the user and password from.

  • auth-nocache removes the password from memory, which might slightly increase security if you are worried about it.

  • persist-tun will try to keep the same IP address from the server if your connection drops out, which should hopefully mean less starting and stopping of Transmission-daemon.

  • route-noexec tells the OpenVPN client not to automatically use the routes provided by the server - which would pull all network traffic over the VPN. We just want to send torrent traffic, so we will need to use different routing settings.

  • lport 1195 tells the OpenVPN client to use port 1195 instead of 1194 - in my case I also want to run an OpenVPN server on the same device, and the server will need to use port 1194. Even if you aren't running an OpenVPN server, it doesn't hurt to make this change.

  • I changed the line dev tap to dev tap1, to force the virtual device to be tap1 instead of being assigned by OpenVPN, again because of running a separate OpenVPN server. Even if you're not running a VPN server, this change shouldn't matter. The firewall scripts have been written to use tap1, so if you would rather use another device then remember to change those scripts where appropriate.

  • lladdr 00:FF:11:AA:BB:CC tells OpenVPN to assign the tap interface to have this MAC address, which can be useful for iptables firewall rules.

  • route-up and down run scripts to start and stop Transmission-daemon as required - these are needed here because they run with environment variables containing information about the connection, which is needed to correctly bind Transmission to the right IP address and port.

In my case, I had a server certificate from the VPN provider - which also has to be in the same directory as the config file.

sudo vim /opt/ibVPN/ibvpn.com.crt

Copy and paste this, or move it via SCP or SSHFS.

-----BEGIN CERTIFICATE-----
MIIDeDCCAuGgAwIBAgIJAMVKgpjMPUfxMA0GCSqGSIb3DQEBBQUAMIGFMQswCQYD
VQQGEwJVUzELMAkGA1UECBMCQ0ExFTATBgNVBAcTDFNhbkZyYW5jaXNjbzEVMBMG
A1UEChMMRm9ydC1GdW5zdG9uMRgwFgYDVQQDEw9Gb3J0LUZ1bnN0b24gQ0ExITAf
BgkqhkiG9w0BCQEWEm1lQG15aG9zdC5teWRvbWFpbjAeFw0xMDA3MjExOTU5MzVa
Fw0yMDA3MTgxOTU5MzVaMIGFMQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0ExFTAT
BgNVBAcTDFNhbkZyYW5jaXNjbzEVMBMGA1UEChMMRm9ydC1GdW5zdG9uMRgwFgYD
VQQDEw9Gb3J0LUZ1bnN0b24gQ0ExITAfBgkqhkiG9w0BCQEWEm1lQG15aG9zdC5t
eWRvbWFpbjCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAz23m3BXY5Asiw8Dx
T4F6feqsp+pIx6ivftTniyUCbSAxI1J1s1x75DzxmUpIwPu5xavzgPXgZr8FT81X
JGqF9km4AE95iddJawKx0wNgdTo7GximQq9rw0dsQIB5hZZQ9TJwHC3VOnmEic5A
OawKOCybMcRs8saLakZOgh7Xc+UCAwEAAaOB7TCB6jAdBgNVHQ4EFgQUeRhE2N4l
XwL4H1dbjkZ4ou6fj3AwgboGA1UdIwSBsjCBr4AUeRhE2N4lXwL4H1dbjkZ4ou6f
j3ChgYukgYgwgYUxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJDQTEVMBMGA1UEBxMM
U2FuRnJhbmNpc2NvMRUwEwYDVQQKEwxGb3J0LUZ1bnN0b24xGDAWBgNVBAMTD0Zv
cnQtRnVuc3RvbiBDQTEhMB8GCSqGSIb3DQEJARYSbWVAbXlob3N0Lm15ZG9tYWlu
ggkAxUqCmMw9R/EwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOBgQASt0pl
WzVseQLTNM8Mlgw4ZnGAv/x2xnijmMqrkE+F7pnaOicGpxgCfMKzjZuJu0TNJqF2
fibE7GhMdomD4dLFgIu8Wb5E7iQ1CSBEOGumRhK8qCsDzjr7WXUdhqA6Xvo+ylU6
DMzy0Wn3NNvfGC+qxOgybYCJwDnVPi0CEDSbzQ==
-----END CERTIFICATE-----

Obviously if you aren't using an ibVPN account, your certificate will be different.

Let's now make the password file:

sudo vim /opt/ibVPN/pass

The first line must be the full username, then the second line must be the password. This must be the only contents of this file.

[email protected]
myBIGstrongpassword1234567890

We also have to secure the permissions on this file, or OpenVPN won't start.

sudo chmod 400 pass

This will make the file read-only, and only for the owner (i.e. no other user can read it at all)

These commands will create the files to run at startup, and set them to be executable only by root.

sudo touch route-up.sh
sudo touch down.sh
sudo chmod 700 route-up.sh
sudo chmod 700 down.sh

At this point, it is probably a good idea to test if the VPN connection actually works. Start the connection with:

sudo openvpn --cd /opt/ibVPN --config config.ovpn

You will see warnings that the up and down external commands could not be run, but don't worry about that. If it works, you will see Initialization Sequence Completed on the terminal. Press Control+C to end the connection. If it doesn't work, you will have to investigate why not and fix it before continuing. I found that it sometimes it took a few goes to start working. Make sure your password file is correct. There are lots of great resources on the Internet about OpenVPN, so have a look around.

At this point, it's probably easiest to move on to getting Transmission up and running. Once you are sure that both the VPN and Transmission can run separately, they can be combined.

Installing and configuring Transmission

Install the required packages:

sudo apt-get install transmission-daemon

By default, Transmission will run automatically on boot. Since we will eventually be using OpenVPN to start Transmission, we want to disable this. To do so, edit the config file for Transmission-daemon

sudo vim /etc/default/transmission-daemon

And change the following line to read:

ENABLE_DAEMON=0

Now Transmission will not start on boot.

Let's now create a directory for the Transmission settings to reside in, and for the downloaded torrents to go into. This assumes you've already set up a disk of some sort, and it's mounted at /media/arm-disk/. For security purposes, the daemon will be run by its own user rather than as root or as "ubuntu". A new user is created by the installer for transmission-daemon, "debian-transmission". This user needs to own the folder that we create, and have read and write access to the storage location for the torrents being downloaded.

sudo mkdir /opt/transmission
sudo chown debian-transmission:debian-transmission /opt/transmission
sudo mkdir /media/arm-disk/torrents-complete
sudo chown debian-transmission:debian-transmission /media/arm-disk/torrents-complete
sudo mkdir /media/arm-disk/torrents-incomplete
sudo chown debian-transmission:debian-transmission /media/arm-disk/torrents-incomplete

Now we need to start transmission, just briefly, so that it creates the settings file we need:

sudo -u debian-transmission -g debian-transmission /usr/bin/transmission-daemon --config-dir /opt/transmission --foreground

This command starts transmission-daemon as the debian-transmission user, tells it to use the /opt/transmission directory for the settings files, and tells it to keep running in the foreground. Once it has run for a few seconds, press Control+C to end it. We can now edit the settings file.

sudo -u debian-transmission vim /opt/transmission/settings.json

We now need to change to following lines from their defaults to read:

"download-dir": "/media/arm-disk/torrents-complete",

"incomplete-dir": "/media/arm-disk/torrents-incomplete",

"incomplete-dir-enabled": true,

"rpc-whitelist": "127.0.0.1,192.168.1.*",

Save and exit (Escape, type :wq and press Enter)

The middle two edits will enable the use of the "incomplete" directory, separating your finished torrents from the unfinished ones. This isn't completely necessary, but I personally find it extremely useful. The last edit enables the web GUI to be accessed by any computer on the LAN (assuming your LAN subnet is 192.168.1.0, modify this if it is different).

It's now a good idea to run Transmission again, to see if it works and can actually download a torrent. We will use a web browser window to access the GUI and to add a torrent. First, let's allow access to the web GUI through the firewall from the LAN, then run transmission-daemon again.

sudo ufw allow in from 192.168.0.0/16 to any port 9091
sudo -u debian-transmission -g debian-transmission /usr/bin/transmission-daemon --config-dir /opt/transmission --foreground

Visit this URL in Firefox (or whichever browser you prefer): http://XXX.XXX.XXX.XXX:9091 , where XXX is replaced by the address of your server on the LAN (i.e. 192.168.1.10). Find a torrent to download, for example Big Buck Bunny in 1080p60hz. This is a free short film, legally available for free download. In the Transmission GUI, click the "Open Torrent" button, and paste this link (or any other torrent you like) into the first box. Then press "Upload". If Transmission is working correctly, the torrent will begin to download. If it does not, then you will need to work out why before continuing. There are lots of resources available on the Internet for using transmission-daemon. It could also be the torrent you chose isn't working, try a few others first.

Once the download is finished, press Control+C in the terminal window to stop transmission-daemon.

Configure binding Transmission to the VPN interface

Now let's make an Upstart script, which will be used to start Transmission when the VPN is ready.

sudo mv /etc/init/transmission-daemon.conf /etc/init/transmission-daemon.conf.bak

Don't worry if this complains, it's just to make a backup of the Upstart file, if one existed - it might not have. Let's open vim to edit the new one:

sudo vim /etc/init/transmission-daemon.conf

Paste this into the editor:

description "transmission-daemon, attached to OpenVPN tunnel tap1"

start on transmission-daemon-start
stop on runlevel [!2345] or transmission-vpn-down

# This includes the information from OpenVPN into this environment

export LOCAL_IP
env PORT=51413

# give time to send info to trackers
kill timeout 30

# Run as unprivileged user
setuid debian-transmission
setgid debian-transmission

# Start transmission again if it stops for some reason
respawn
# If transmission stops 5 times in a minute, give up trying to respawn it
respawn limit 5 60

exec /usr/bin/nice -15 /usr/bin/transmission-daemon --config-dir /opt/transmission --bind-address-ipv4 $LOCAL_IP --peerport $PORT --no-portmap --foreground

Save and close vim. (Escape, then type :wq). Again, open vim:

sudo vim /etc/init/transmission-up.conf

And paste this:

description "Script to create firewall and routing rules for transmission-daemon"

start on transmission-vpn-up

# This includes the information from OpenVPN into this environment
export VPN_GATEWAY
export LOCAL_IP
env PORT=51413

task

script
    # Set up IP route, firewall rules
    # It doesn't matter if they already exist, they will be skipped
    /sbin/ip route add default via $VPN_GATEWAY dev tap1 table 200
    /sbin/ip rule add from $LOCAL_IP table 200
    /sbin/ip route flush cache
    /usr/sbin/ufw insert 1 reject out on eth0 from any port $PORT
    /usr/sbin/ufw insert 1 reject in on eth0 to any port $PORT
    /usr/sbin/ufw insert 1 deny in on tap1 to any
    /usr/sbin/ufw insert 1 allow in on tap1 to any port $PORT proto udp

    # Start the actual transmission-daemon process, in a separate task so that unprivileged user/group can be set
    /sbin/initctl emit transmission-daemon-start LOCAL_IP=$LOCAL_IP

end script

Again, save and close vim. (Escape, then type :wq). Finally:

sudo vim /etc/init/transmission-down.conf

Paste this:

description "Script to remove firewall rules for transmission-daemon"

start on runlevel [!2345] or stopping openvpn-transmission
env PORT=51413

task

script
    # Take down IP route, firewall rules
    # It doesn't really matter if they don't get taken down, but this will be cleaner
    /usr/sbin/ufw delete reject out on eth0 from any port $PORT
    /usr/sbin/ufw delete reject in on eth0 to any port $PORT
    /usr/sbin/ufw delete deny in on tap1 to any
    /usr/sbin/ufw delete allow in on tap1 to any port $PORT proto udp

    /sbin/ip route flush cache

end script

These scripts tell Upstart to listen for the "transmission-vpn-up" signal. The "transmission-up.conf" script then sets up the required routing rules to send traffic from the local VPN address via the VPN interface, and sets the firewall to allow in traffic from the VPN to the listening port for Transmission. Traffic directed to Transmission's listening port from the normal LAN interface is blocked. The "transmission-daemon.conf" script then starts transmission-daemon with the required settings to bind it to the VPN IP address. Note that this command will also ensure UPnP/NAT-PMP is disabled - see my note at the top about port forwarding. The "nice -15" sets Transmission to have a lower priority, which I found useful when using the lower spec'd BeagleBone - sometimes Transmission can hog resources, which slows the system down. At least with a low priority, more important system tasks can still run. The "transmission-down.conf" script will remove the firewall rules when the VPN is stopped. Three different scripts are used so that transmission-daemon can be run as an unprivileged user, but the firewall rules can be run as root.

Now let's go back to the OpenVPN settings, and edit the "route-up" and "down" scripts to trigger starting and stopping our Transmission script.

sudo vim /opt/ibVPN/route-up.sh

Paste this into vim:

#! /bin/bash

/sbin/initctl emit transmission-vpn-up VPN_GATEWAY=$route_vpn_gateway LOCAL_IP=$ifconfig_local

All this script does is say to Upstart that transmission-daemon should start, and gives it the information it needs to attach to the VPN connection.

sudo vim /opt/ibVPN/down.sh

Again, more pasting:

#! /bin/bash

/sbin/initctl emit transmission-vpn-down

This script is even more simple - it signals for transmission-daemon to stop.

At this point, it is probably a good idea to make sure that the owner of the entire VPN config folder is the root user - since these scripts run as root, anyone who could change them could run anything they wanted to as the root user.

sudo chown root:root -R /opt/ibVPN
sudo chmod 700 -R /opt/ibVPN
sudo chmod 400 /opt/ibVPN/pass

This now means that only the root user can modify or view the VPN connection settings.

OK, we're nearly done! Let's test if our setup is working so far:

sudo openvpn --cd /opt/ibVPN --config config.ovpn

Connect again to the Transmission web GUI, and resume the existing torrent or add a new one. It should be able to download, maybe after a few minutes of waiting for peers. A nifty way I found of testing whether or not it is working is to look at iftop. Install iftop, and run:

sudo apt-get install iftop
sudo iftop -i tap1

This screen will be showing all connections running through the VPN. If your torrent is downloading and is correctly using the VPN, there will be lots of IP addresses and host names here. Also look at iftop for the LAN connection:

sudo iftop -i eth0

Here you should see a large amount of traffic to a single IP address, being the VPN server, and then only minimal traffic to other LAN devices - assuming that you aren't running other services on your BeagleBone.

You can confirm that the VPN is working by following these instructions.
This site lets you download a torrent to see the IP address other peers use to connect to you - if everything is working this will be the VPN IP address and not your own WAN IP address.

If you are experiencing issues, you can see the Upstart error log by doing:

sudo tail -f /var/log/upstart/transmission-daemon.log

In a separate terminal/SSH window, try running the tail command while starting the VPN connection as above and look for any error messages. Hopefully you can resolve the issue from seeing the error messages, if not have a dig around on the Internet, or post a comment.

Configure it all to start automatically

If you are happy with manually issuing the command to start the OpenVPN tunnel, or you want to do it with your own script, then you are done. But I wanted it to start on boot, so I made another Upstart script to launch OpenVPN.

sudo vim /etc/init/openvpn-transmission.conf

This is the last thing we have to paste!

description "OpenVPN client, with attached transmission-daemon"

start on started networking
stop on runlevel [!2345] or stopped networking

# Give time for Transmission to send info to trackers, wait for graceful close
kill timeout 45

# Start the OpenVPN tunnel again if it stops for some reason
respawn
# If it stops 5 times in a minute, give up trying to respawn it
respawn limit 5 60


exec openvpn --cd /opt/ibVPN --config config.ovpn

post-stop script
    # Pause for a few seconds, before exiting
    /bin/sleep 3s
end script

All this does is wait for the system to signal that the network is ready, and then it will start the OpenVPN tunnel - which will in turn start Transmission. When the system is turned off, or if networking is shut down for some reason, Upstart will remove the firewall rules and close transmission-daemon. Simple! This will continue to work after a reboot too, so now you're all set.

To interact with Transmission, use the web GUI as we did during the setup phase. It is also possible to make the GUI accessible over the Internet, by setting up port forwarding. There are lots of tutorials on how to do this, so I won't repeat it here.

As for getting the completed downloads off the BeagleBone, I'm using NFS. I can get speeds of about 8 MB/s copying over the LAN from the BeagleBone to my desktop computer - which is pretty good for such a low-powered device. Ubuntu provides some handy information for setting this up.

Solution 2:

Just got this working using SystemD so I thought I'd share. I have placed all of my scripts, configs, and certificates in the same directory which I will refer to as /etc/openvpn/myprovider

OpenVPN config

This depends on your specific VPN, but one difference from @seanlano's config is that I only use a route-up script. So the things you need in addition to your working provided config, are these lines:

route-noexec
route-up "/etc/openvpn/myprovider/transmission-route-up.sh"

Where you place the transmission-route-up.sh script wherever you like. Note the absence of a down script. (My VPN was already using a custom down script so it would have conflicted anyway).

/etc/openvpn/myprovider/transmission-route-up.sh:

#!/bin/sh

# Print environment variables for transmission's benefit
printenv > /etc/openvpn/myprovider/vpn.env


# Set up VPN routes
ip route add default via $route_vpn_gateway dev $dev table 10

ip rule add from $ifconfig_local/32 table 10
ip rule add to $route_vpn_gateway/32 table 10

ip route flush cache


# Add firewall rules
iptables -A INPUT -i $dev -p udp --dport 24328 -j ACCEPT
iptables -A INPUT -i $dev -p tcp --dport 24328 -j ACCEPT

iptables -A OUTPUT -o $dev -p udp --sport 24328 -j ACCEPT
iptables -A OUTPUT -o $dev -p tcp --sport 24328 -j ACCEPT

The first line, the printenv, is important. Place it wherever you like, it is used in the SystemD service later. I place it in the same directory as my vpn config.

Replace 24328 with whatever port your transmission-daemon should listen on. I use iptables (using Debian), so you can probably replace those lines with the ufw lines from @seanlano's config.

SystemD VPN service

This is the service which auto starts the VPN for us. Verify that the path to openvpn is correct on your machine, and that the path to the config file is correct as well. You must specify full paths in SystemD services.

/etc/systemd/system/my-vpn.service:

[Unit]
Description=VPN connection
After=network.target

[Service]
Type=forking
PIDFile=/var/run/openvpn/vpn.pid
ExecStart=/usr/sbin/openvpn --cd /etc/openvpn/myprovider --config /etc/openvpn/myprovider/myconfig.ovpn --daemon --writepid /var/run/openvpn/vpn.pid

[Install]
WantedBy=multi-user.target

Enable the VPN service with:

systemctl enable my-vpn.service

And test it with:

systemctl start my-vpn.service
systemctl status my-vpn.service

If it's started/running, you're good.

SystemD transmission-daemon.service

This script requires the vpn-service, so if the vpn goes down, transmission-daemon also goes down. This is handy if the vpn is restarted, and you get a new IP-address, because transmission will need to restart and re-bind then, which should be handled automatically. Note that we make use of the environment variables we printed in the route-up script earlier.

/etc/systemd/system/transmission-daemon.service:

[Unit]
Description=Transmission BitTorrent Daemon Under VPN
After=network.target my-vpn.service
Requires=my-vpn.service

[Service]
User=debian-transmission
Type=notify
EnvironmentFile=/etc/openvpn/vpn.env
ExecStart=/usr/bin/transmission-daemon -f --log-error --bind-address-ipv4 $ifconfig_local --rpc-bind-address 0.0.0.0 --no-portmap
ExecReload=/bin/kill -s HUP $MAINPID

[Install]
WantedBy=multi-user.target

Enable it

systemctl enable transmission-daemon.service

And start it

systemctl start transmission-daemon.service

When you reboot, it should all start automatically (in order!). Note that using Type=simple in the vpn service causes some problems for the timing of script ordering, hence I recommend using forking instead.

You can specify an actual ip-address for the rpc-bind-address if you want to be more restrictive (this is the web GUI listening address, which should not be your VPN-ip). And if you want to run transmission with nice, just change the ExecStart line and add /usr/bin/nice -n15 to the beginning.

Handling address changes

One thing I've noted over time is that if the vpn-connection for some reason gets a new ip-address, transmission will still be bound to the old address and stop working. And simply doing systemctl restart transmission-daemon.servicedoesn't cut it. It needs to stop fully, and then start fresh.

No idea why, but for that reason I have added the following lines to my root crontab (sudo crontab -e):

# m h  dom mon dow   command
0 6 * * * /bin/systemctl stop my-vpn.service; /bin/systemctl start my-vpn.service
1 6 * * * /bin/systemctl stop transmission-daemon.service; /bin/systemctl start transmission-daemon.service

Solution 3:

I noticed you mentioned that Transmission does not goes through the VPN for UPnP/NAT-PMP. I noticed this as well and created a patch for Transmission so it honors the bind-address-ipv4 setting for UPnP. NAT-PMP is a bit harder to implement since you need to determine the default gateway. UPnP is the main one that is being used these days, though, so it is probably good enough. I logged this as a bug on the trac.transmissionbt site and provided the patch. Hopefully it will be incorporated in a future release. https://trac.transmissionbt.com/ticket/5990

Another option for right now if you don't want to recompile is to manually run upnpc from the miniupnpc package. E.g.

sudo apt-get install miniupnpc
upnpc -m 10.10.10.51 -a 10.10.10.51 51515 51515 TCP
upnpc -m 10.10.10.51 -a 10.10.10.51 51515 51515 UDP

Where 10.10.10.51 is your VPN IP and 51515 is your requested TCP/UDP port.

I'm not sure how long the forwarding is good for. Also you might want to use the '-d' option to remove your port when disconnecting. I found that if I don't, I can't get I same port again if I relogin into the VPN.

Cheers