Transmission daemon over OpenVPN

42,492

Solution 1

New approach in 2022: Network Namespaces

In the years since I first attempted this, there's been some developments that make setting up Transmission to run over a VPN easier and more reliable – using a "Network Namespace". This doesn't just apply to Transmission, it could be for any systemd service. It no longer relies on the application correctly binding to the appropriate network interface, instead systemd will force all network traffic to use the configured namespace – which in our case will mean sending it though the VPN.


1. Configure networking

There's many ways that networking might be configured, in my case I was already using Netplan to create a bridge. It's probably not necessary to create one if you aren't also using it for other reasons (instead use the NAT option), but for reference here is my Netplan config which I'm using in this example. You'll need to adjust as appropriate, or configure the network interfaces with another tool of your choosing.

Example Netplan config:

network:
  version: 2
  renderer: networkd
  ethernets:
    enp1s0:
      dhcp4: no
      dhcp6: no
  bridges:
    br0:
      interfaces: [enp1s0]
      dhcp4: no
      dhcp6: yes
      dhcp6-overrides:
       use-dns: yes
       use-ntp: yes
       send-hostname: yes
       use-hostname: no
      addresses:
        - 192.168.64.200/24
        - "aaaa:bbbb:cccc::200:1/64"
      ipv6-privacy: yes
      gateway4: 192.168.64.1

2. Install and configure systemd-named-netns scripts

Although systemd supports network namespaces, it doesn't have much in the way of configuration for them. Fortunately, a helpful fella called James Swineson has made a set of scripts which create systemd services for various network namespace configurations.

Download the repository:

git clone https://github.com/Jamesits/systemd-named-netns.git

Install the scripts:

cd systemd-named-netns/
sudo make install

3. Configure systemd-named-netns

The exact configuration you need will depend on your network setup. I'm using a bridge, but a NAT option is also available. See the wiki page for more information.

The rest of this guide assumes that you're using a bridge. I'm using the name torrentvpn for the namespace, it will come up in a few places. If you decide to use a different name, make sure it only contains alphanumeric characters and is not longer than 12 characters.

Create a resolv.conf file for the DNS settings to use inside the network namespace:

sudo mkdir -p /etc/netns/torrentvpn/
sudo touch /etc/netns/torrentvpn/resolv.conf

Then edit the file /etc/netns/torrentvpn/resolv.conf to this:

nameserver 8.8.8.8

This will use Google's DNS service for anything that runs inside the network namespace, feel free to use another if you prefer – NextDNS is a good alternative.

Now let's configure the namespace bridge, edit the file /etc/default/netns-torrentvpn to this:

# Bridge name
BRIDGE=br0

# If you need DHCP
DHCPV4=1

# Set a static MAC, helpful with DHCP
MACADDR=02:00:00:aa:bb:01

# Device name outside netns
DEVNAME_OUTSIDE=veth0
# Device name inside netns
DEVNAME_INSIDE=veth1

At this point we can test our network namespace setup, start the namespace with this command:

sudo systemctl start [email protected]
sudo systemctl enable [email protected]

Then try to ping something from inside the namespace, and make sure it works:

sudo chnetns torrentvpn ping google.com

4. Set up OpenVPN

There's a crazy number of VPN service providers out there, so the steps might be slightly different for you. Ideally you should confirm you can get an OpenVPN tunnel set up using the config files from your provider, possibly using a graphical interface first if that's easier. In theory it doesn't even have to be OpenVPN, it can be any VPN that you can get running through systemd.

I have an account with ProtonVPN, who provide OpenVPN configuration files which have the necessary certificates and keys embedded inline. The config file is saved at /etc/openvpn/client/protonvpn.conf and I've modified it to have the username and password read from the file at /etc/openvpn/client/protonvpn.pass (with the auth-user-pass config option). You'll need to adapt this to suit your provider.

The OpenVPN package provides systemd scripts for managing a client connection, although we want to add an extra couple of lines so that our connection uses the network namespace. Run this command:

sudo systemctl edit [email protected]

and add the following lines:

[Unit]
[email protected] [email protected]
[email protected] [email protected]
[email protected]

[Service]
PrivateNetwork=yes
ExecStartPre=/sbin/sysctl net.ipv6.conf.all.disable_ipv6=1

This creates a "drop-in" override file at /etc/systemd/system/[email protected]/override.conf, which lets us add our extra settings without needing to edit the config from the package maintainer. It also disables IPv6 inside the namespace, since my VPN provider doesn't support it and I don't want to accidentally end up using my non-VPN Internet connection.

Restart the systemctl daemon, then try to start the VPN:

sudo systemctl daemon-reload
sudo systemctl start [email protected]
sudo systemctl enable [email protected]

Test again with a ping through the namespace, this time the response time should be slower than before because of the extra distance the packets now have to travel to reach the VPN endpoint:

sudo chnetns torrentvpn ping google.com

5. Set up Transmission Daemon

There's lots of information about configuring Transmission, and you might have different desires, so read the documentation. I'll quickly show the main steps here.

Install Transmission:

sudo apt install transmission-daemon

Stop the daemon (systemd seems to start it after being installed)

sudo systemctl stop transmission-daemon.service

Edit the configuration file at /var/lib/transmission-daemon/.config/transmission-daemon/settings.json. In particular, you'll probably want to change download-dir to somewhere with sufficient storage, and also allow access from your LAN in rpc-whitelist (for me this meant adding 192.168.64.*). You will also need to set a password through rpc-password to log into the web UI.

Don't forget to set the correct permissions for your downloads directory:

sudo chown debian-transmission:debian-transmission /home/torrents/

6. Set Transmission to use the VPN

Similarly to how we edited the systemd config for OpenVPN with an override, we will do the same with Transmission:

sudo systemctl edit transmission-daemon.service

Add the following lines, and save:

[Unit]
[email protected] [email protected]
[email protected] [email protected] [email protected]
[email protected]
[email protected]

[Service]
PrivateNetwork=yes

Reload systemd, then start the service:

sudo systemctl daemon-reload
sudo systemctl start transmission-daemon.service
sudo systemctl reenable transmission-daemon.service

Because of the namespace, Transmission's web UI won't be accessible from the IP of the host machine, but rather from the IP of the virtual device inside the namespace which is attached to the bridge we set up. To find that IP address, run:

sudo chnetns torrentvpn ip ad

and find the address of the veth device – for me it was 192.168.64.46. The Transmission UI is then accessible at http://192.168.64.46:9091 , using the username and password you set in the configuration file.

7. Testing it out

Everything should all be up and running now. The best way I've found to confirm that the torrents really do use the VPN to download is to use the handy checker that Torguard provide (thanks to @lemonek for introducing me to this!) – it gives you a special torrent to download, and shows which IP addresses attempted to share it. Compare the IP that shows up with your Internet IP, and make sure it is not the same. You can also check the IP seen by servers for anything using the VPN by running:

sudo chnetns torrentvpn curl http://ip.42.pl/raw

This will show the IP address seen by the server at ip.42.pl, which should be the same IP shown by the Torguard tool.

Weird behaviour in Ubuntu 18.04

Frustratingly, I found that on reboot the network namespace setup seemed to play up slightly on Ubuntu 18.04 (but not on 20.04), leaving me unable to test out shell commands inside the namespace with the chnetns command. Strangely though the namespace worked fine for services within systemd jobs, Transmission was still running just fine.

I tried a bunch of things but couldn't figure it out, but I did at least realise that by stopping and restarting everything it could all be made to work:

sudo systemctl stop [email protected]
sudo systemctl start transmission-daemon.service

Solution 2

Update: (2022-04-13) It's been quite a while, and I've got a new method for doing this, using Linux network namespaces. See my new answer for the steps. I'm also definitely not using that old Beaglebone board any more! The steps apply equally to any CPU type.


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 3

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 4

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

Share:
42,492

Related videos on Youtube

seanlano
Author by

seanlano

Keen software hacker, developer, and photographer - I love to make new things, and figure out how things work

Updated on September 18, 2022

Comments

  • seanlano
    seanlano almost 2 years

    I have recently acquired a BeagleBone Black, onto which I've installed Ubuntu using this method. It has all worked so far. I want to use my BeagleBone as a torrent box, but I don't want to do it directly over my Internet connection (I don't think my ISP will like it) - so I've purchased a VPN subscription from a European server. I've manually connected my laptop to this VPN before and the run Transmission. I know that the VPN connection works in Ubuntu, and the host provides setup information for OpenVPN. Annoyingly, the dynamic nature of the assigned IP address means it would change frequently, so when I used my laptop with the VPN I would manually set the listening address in Transmission to the required value.

    Ideally I'd like the following setup:

    • Transmission runs only over the VPN, and is prohibited from running torrents over the normal WAN connection
    • Only traffic directed to Transmission will be accepted or sent through the VPN, all other unsolicited traffic will be dropped
    • Transmission uses the appropriate port to listen on, based on the assigned IP address
    • OpenVPN starts automatically on boot, which then subsequently starts Transmission
    • Transmission's web GUI can be accessed over the LAN, and possibly over the Internet from my WAN connection (i.e. not back through the VPN)
    • RobotHumans
      RobotHumans over 9 years
      Self answers aren't bad. Don't apologize for them. You also don't have to explain that's what you're doing though... It is an encouraged behavior
    • Giacomo1968
      Giacomo1968 over 9 years
      Agreed with @hbdgaf. No need to apologize. Great work on all fronts.
  • Ismael Miguel
    Ismael Miguel over 9 years
    Wow! How long did you spend looking for all this stuff?
  • seanlano
    seanlano over 9 years
    Haha, quite a while. I'd done it once before on a DD-WRT router, then when I was doing i again for the BeagleBone I thought I'd write this up so I don't forget how to do it. :D
  • Ismael Miguel
    Ismael Miguel over 9 years
    This is valuable information. Not only for you but for someone else. I've made this account here just to say that!
  • seanlano
    seanlano over 9 years
    I've noticed recently that when I set Transmission to download overnight, CPU usage goes to 100% after a few hours, and then the usage of other processes stays high for quite a while after pausing. I've also got Syncthing running on the same system, and I think they fight for resources or something like that. I'm not sure how Transmission could cause Syncthing to have high CPU usage, but it appears that it does. I'm still investigating.
  • Ismael Miguel
    Ismael Miguel over 9 years
    4 years ago I had similar problems, but it was an old version 'fighting' against Opera 12. I've downloaded Transmission from the Debian repositories and installed on puppy linux 4.3.1. I've always assumed it was my CPU crapping out, since the computer was incredibly weak.
  • seanlano
    seanlano over 9 years
    I once had Transmission running on a DD-WRT router, with a 400 MHz MIPS processor - and I don't remember it being too bad. I think there might be a bug in the ARM build.
  • Ismael Miguel
    Ismael Miguel over 9 years
    Sadly, it wasn't on an ARM CPU. It was an Intel Centrino. Which one exactly, I don't remember. But it was single-core. Transmission crashed A OT, using almost 100% of the CPU. Are you using the most recent build? I was, but it was 4 years ago. And it was a Debian-compatible distribution (to which I had to install the dependencies manually). If you really believe it has a bug, try an older version (don't use it for anything else other than testing!).
  • seanlano
    seanlano over 9 years
    @IsmaelMiguel, I'm using the most recent ARMHF build in the official Ubuntu repos for 14.04. I might try an older version and see if it makes a difference. Also my earlier mention of Syncthing having issues seems to just be related to the overload of the processor - after I kill Transmission the system returns to normal after about 10 minutes. Hmmm...... :/
  • Ismael Miguel
    Ismael Miguel over 9 years
    ARM CPUs are quite weak. You probably need to tweak the number of acceptable connections. And limiting some other stuff. Also, check the RAM usage. It might be trying to swap and (since the CPU is slower than a x86) that may be causing a disaster everywhere. Also, you may try to limit the process' CPU usage with the nice command (if I'm not mistaken).
  • seanlano
    seanlano over 9 years
    Yeah I've definitely noticed how slow ARM is compared to even a low-powered x86 CPU. It does use less than 5 watts though, so it's fair enough really. I do use nice, with 15 as the niceness. It seems not to matter, it still brings the system to its knees. But I'll try and play with the settings and see what I can do. According to htop the RAM usage isn't worse than about 80%, and there is no swap space at all. I might try adding some swap to see what happens.
  • Ismael Miguel
    Ismael Miguel over 9 years
    You should have always some swap. Even if it completely empty. I don't think that swap will help a lot, but it is a great idea to keep it around. Have you tried to check your disk for damaged sectors? Can you try to install Debian and try to configure the same way? I've noticed that Debian is A LOT lighter. Try to find the LXDE version (I know, I know. It isn't as pretty as Unity). Use that one. I had fantastic results with it running on VirtualBox.
  • seanlano
    seanlano over 9 years
    I'm running this box completely headless, so Unity doesn't bother me. ;) Alright so my plan of action to work on this: 0) Add some swap space 1) Change some Transmission parameters to see if it improves 2) Try different versions of Transmission 3) Try using Debian instead of Ubuntu. After that I give up. :P I'll let you know how I get on.
  • Ismael Miguel
    Ismael Miguel over 9 years
    In my opinion, you should try with Debian first. Then you can mess with all the other stuff. But I get your reasoning. My argument against your decision is that Debian is so easy to configure and get up running that and so much faster (when using LXDE) than Ubuntu (with or without Unity) and jumping all the middle stuff to this step may be beneficial. The argument against is that I don't know exactly what is going on. And messing with Transmission is easier and less cumbersome and dangerous than installing another OS. But I'm curious about the outcome of your attempts!
  • Ismael Miguel
    Ismael Miguel over 9 years
    You should also read this: unix.stackexchange.com/questions/88693/… (It's a great answer.) This will help you, I'm sure of it.
  • seanlano
    seanlano over 9 years
    I'll give it a go then, if I can figure out how to make an image of the BeagleBone onboard disk so I can restore this Ubuntu setup if I want to. Since Ubuntu is derived from Debian, I'm imagining that the installation steps I made above will be identical - except for the Upstart scripts I suppose. They might be a bit of a pain.
  • Ismael Miguel
    Ismael Miguel over 9 years
    You can make an entire copy of your disk using Clonezilla. You need to have somewhere to store it. They have pretty nice examples, very well explained (I was able to copy a few disks, so, it must be extremelly well explained!). Their website (clonezilla.org) has the iso files to download and run from a CD/DVD or usb.
  • seanlano
    seanlano over 9 years
    Alright, so I've tried a few different versions of Transmission, back down to 2.51. I also added swap space. The issue persists. :/ Next I might try using Raspbian on the Beaglebone, to see if that helps.
  • Ismael Miguel
    Ismael Miguel over 9 years
    That is so weird in so many levels... Did you compiled the source-code or you installed from the package manager?
  • seanlano
    seanlano over 9 years
    I just used the packages from the repository, I didn't do any compiling. I still haven't had time to mess around with Debian yet, but I hope to do so soon. Needless to say, the issue hasn't magically resolved itself. :P
  • Ismael Miguel
    Ismael Miguel over 9 years
    You really should look into a way to compile the sourcecode. You can try to look into bittorrent or similar. If you don't have any alternative, try to use WINE with the Windows version of a client. In case everything fails, install Opera 12.17 and pray that the torrent client in it works.
  • seanlano
    seanlano about 9 years
    Just out of interest, is this also running on a BeagleBone? If so, do you see performance issues with Transmission? Also, great write-up. :)
  • Jonas Kalderstam
    Jonas Kalderstam about 9 years
    Ah no. It's running on my normal desktop machine and I have noticed no issues there.
  • seanlano
    seanlano about 9 years
    Fair enough. Works fine for me on an Intel machine, I was hoping I could make a cheap torrent box with an ARM processor - but apparently it is not to be.
  • Jonas Kalderstam
    Jonas Kalderstam about 9 years
    Check out rtorrent. It is very performant
  • seanlano
    seanlano about 9 years
    Thanks, I will. Other things run fine on the ARM box, so maybe rtorrent will work properly.
  • seanlano
    seanlano almost 9 years
    I spent ages trying to find a solution like this, I wish I'd found miniupnpc ! And hopefully the patch does get merged and this issue will be fixed forever. In the meantime I'll definitely be trying to use your handy tip.
  • seanlano
    seanlano almost 9 years
    I'm now using a 15.04 box, and so your systemd config is coming in handy! I've got a quick question, in your systemd my-vpn.service you have Type=forking and then start OpenVPN with /usr/sbin/openvpn --daemon and use the PID file etc. How come you didn't leave out the Type=forking directive and the --daemon flag and let systemd manage it in the foreground? I'm pretty sure that Upstart prefers foreground processes, but I don't have much experience with systemd yet.
  • gapple
    gapple over 8 years
    I ran into a problem where SystemD would start transmission before openvpn had written the environment file in route-up.sh, and so the transmission service would fail. To fix, I added a sleep to the transmission service definition with ExecStartPre=/bin/sleep 10, so that it will give some time for openvpn to fully complete its setup.
  • P A N
    P A N over 8 years
    @JonasKalderstam Thanks for your write-up. I tried following you (also running Debian), but when trying to sudo systemctl start my-vpn.service I get the error: Active: failed (Result: exit-code) and ... (code=exited, status=1/FAILURE). Any idea why?
  • Jonas Kalderstam
    Jonas Kalderstam over 8 years
    @Winterflags Nope, it's still going strong on my machine. What do you see from sudo systemctl status my-vpn.service -l and sudo journalctl -u my-vpn.service ?
  • Jonas Kalderstam
    Jonas Kalderstam over 8 years
    @Winterflags the problem is --config vpn.conf, you are not specifying the full path to the config file. I'll update my example code above to make this clear. SystemD always requires full paths
  • P A N
    P A N over 8 years
    Ah, thanks. I did see your remark about that, but didn't realise it tied in to the --config argument. :)
  • Jonas Kalderstam
    Jonas Kalderstam over 8 years
    @winterflags that seems related to your vpn settings. Make sure you can start a vpn connection manually in the terminal before shoving it into the service file.
  • P A N
    P A N over 8 years
    Thanks for the update! I'm having an issue now where the current IP of the VPN is saved to ifconfig_local= in vpn.env, but the IP isn't passed on to settings.json. It's only there once I restart. I think the reason is that, when I check the timestamps, settings.json is actually written by the daemon a few seconds before vpn.env is updated. So the next time I connect, the IP will be there. But this is a problem because I'm given a new IP each time I connect to the VPN, effectively "lagging" behind by one IP all the time in settings.json. Any idea how to fix this?
  • Jonas Kalderstam
    Jonas Kalderstam over 8 years
  • Jonas Kalderstam
    Jonas Kalderstam over 8 years
    @Winterflags Yes possibly. I have experienced some problems with simple, with Transmission not having the right ip. "loaded" and "inactive" sounds like you haven't started the transmission service. Note that manually starting the vpn service will not automatically start transmission, that only happens automatically on boot.
  • P A N
    P A N over 8 years
    @JonasKalderstam Okay, got it working now :) I added a .timer script in systemd with OnBootSec=20 that then starts the Transmission daemon. Guide here. That allows settings.json to get the current IP from vpn.env. It works with simple for the OpenVPN service. Many thanks!
  • seanlano
    seanlano over 8 years
    I've just realised, after setting my DNS server to use OpenDNS and looking through the stats, that this config leaks DNS through the normal WAN connection. I'll investigate further to see if I can fix this. I'm going to keep running anyway, since the connection itself is through the VPN - but it's not ideal.
  • P A N
    P A N over 8 years
    @seanlano Thanks for bringing this to our attention. Let us know if/when you find a fix.
  • P A N
    P A N about 8 years
    Is there reason to believe that this configuration leaks DNS queries similarly to what @seanlano updated his answer with?
  • P A N
    P A N about 8 years
    @JonasKalderstam I believe there might be some problems with leaks. See my question here.
  • Motsel
    Motsel over 7 years
    instead of the "crontab" i think it would be more efficient to stop the transmission service in an openvpn "route-pre-down" script, and start transmission in an openvpn "route-up" script...