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)
  • 3
    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 Feb 10, 2015 at 6:09
  • Agreed with @hbdgaf. No need to apologize. Great work on all fronts. Feb 10, 2015 at 8:54

5 Answers 5


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.


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
dev tap1
resolv-retry infinite
script-security 3 system
explicit-exit-notify 3
ca ibvpn.com.crt
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
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.


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]

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:


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": ",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, 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 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. 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
# 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 LOCAL_IP
env PORT=51413


    # 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


    # 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
# 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.

  • Wow! How long did you spend looking for all this stuff? Feb 10, 2015 at 10:45
  • 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
    – seanlano
    Feb 10, 2015 at 10:59
  • 1
    You should also read this: unix.stackexchange.com/questions/88693/… (It's a great answer.) This will help you, I'm sure of it. Feb 17, 2015 at 0:03
  • 3
    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.
    – seanlano
    Feb 22, 2016 at 1:25
  • 1
    @seanlano Thanks for bringing this to our attention. Let us know if/when you find a fix.
    – P A N
    Mar 7, 2016 at 19:08

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-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).



# 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.


Description=VPN connection

ExecStart=/usr/sbin/openvpn --cd /etc/openvpn/myprovider --config /etc/openvpn/myprovider/myconfig.ovpn --daemon --writepid /var/run/openvpn/vpn.pid


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.


Description=Transmission BitTorrent Daemon Under VPN
After=network.target my-vpn.service

ExecStart=/usr/bin/transmission-daemon -f --log-error --bind-address-ipv4 $ifconfig_local --rpc-bind-address --no-portmap
ExecReload=/bin/kill -s HUP $MAINPID


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
  • Just out of interest, is this also running on a BeagleBone? If so, do you see performance issues with Transmission? Also, great write-up. :)
    – seanlano
    May 12, 2015 at 9:53
  • Ah no. It's running on my normal desktop machine and I have noticed no issues there. May 12, 2015 at 9:56
  • 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.
    – seanlano
    May 13, 2015 at 12:17
  • Check out rtorrent. It is very performant May 13, 2015 at 13:13
  • Thanks, I will. Other things run fine on the ARM box, so maybe rtorrent will work properly.
    – seanlano
    May 16, 2015 at 3:09

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 -a 51515 51515 TCP
upnpc -m -a 51515 51515 UDP

Where 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.


  • 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
    Sep 10, 2015 at 1:53

On top what its already written regarding SystemD service... it would make more sense to bound VPN service with Transmission serivce - so when You will restart VPN then Transmission should also be restarted... to achieve this You need to edit VPN serice file

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

and add those lines:

ExecStartPost=/bin/sleep 30

Into the [Service] section.

PartOf will make one direction dependency - If VPN will be restarted then restart metioned those service as well. (documentation)

In my case - VPN needed few seconds more to setup and immediate start of Transmission caused that Transmission daemon was using "old" env file - therefore I have added extra "wait" time 30s (ExecStartPost=/bin/sleep 30) after VPN has started just to make sure.

Im in the testing phase right now - so this is not yet "home production server" yes - so I often yet put on sleep my PC. after that my VPN connection does not work. So I didnt yet make it but it would be nice to have some kind of watchdog functionality to test if VPN connection is still alive - but this is on my TO DO list yet...

Additionally, to test if Your setup actually works then You may use this service torguard.net where You can "download" torrent file and open it in Your remote Transmission and verify what error / comment is returned from Tracker - it should return Your VPN/masked IP and on same page You can track current connections to check if this works at all.


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:

  version: 2
  renderer: networkd
      dhcp4: no
      dhcp6: no
      interfaces: [enp1s0]
      dhcp4: no
      dhcp6: yes
       use-dns: yes
       use-ntp: yes
       send-hostname: yes
       use-hostname: no
        - "aaaa:bbbb:cccc::200:1/64"
      ipv6-privacy: yes

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:


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

# If you need DHCP

# Set a static MAC, helpful with DHCP

# Device name outside netns
# Device name inside netns

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:

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

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:

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


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 The Transmission UI is then accessible at , 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

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .