UPDATE: added an alternative docker-compose section in case you want to run this container on a custom non-8080 port: "Running container UI on a custom non-8080 port"
UPDATE: added section on the bottom about using this VPN container as a gateway for any other container in order to tunnel that traffic inside VPN as well

Personally, I don’t use torrents. My preferred choice is Usenet. Still, every now and then people tend to ask me how to setup docker containers and most often is how to set up a torrent client with VPN protection.

I have written in the past how to utilize VPN on your NAS and one method of tunneling your torrent traffic via your NAS and a VPN connection is using a VDSM instance that will be protected with a VPN and in return, any other app running under that VDSM instance will be protected as well.

Now, this is useful if you will be using that same instance for more then just torrenting. If you are looking for occasional torrent download, then maybe a docker container will be far less resource demanding, not to mention that you will not need a VDSM license (unless you have the free license still open to use).

In these steps, I will explain a bit how to use qBittorrent client in a combination with a VPN provider of your choice. For this, I will use https://hub.docker.com/r/markusmcnugen/qbittorrentvpn image.

  1. Download the image from docker repository

  2. Log into your NAS via SSH and elevate to root
    a) use sudo -i to get root access

  3. Create openvpn folder inside the future /config location where you will copy your OVPN file of choice

  4. Run the following docker run as a single line and change the settings to match your needs.

docker run --privileged -d \
              --name=qbittorrent
              -v /your/config/path/:/config \
              -v /your/downloads/path/:/downloads \
              -e "VPN_ENABLED=yes" \
	      -e "VPN_USERNAME=your_VPN_username" \
	      -e "VPN_PASSWORD=your_VPN_password" \
              -e "LAN_NETWORK=192.168.1.0/24" \
              -e "NAME_SERVERS=8.8.8.8,8.8.4.4" \
              -p 8080:8080 \
              -p 8999:8999 \
              -p 8999:8999/udp \
              markusmcnugen/qbittorrentvpn
Keep in mind that you need to run this as a single line so just delete each \ and replace it with a single space

Or run the following docker-compose file (via Portainer stacks option for example):

version: "3.5"

services:
  qbittorrent:
    image: markusmcnugen/qbittorrentvpn:latest
    network_mode: "bridge"
    privileged: true
    container_name: qbittorrent
    volumes:
      - "/your/config/path/:/config"
      - "/your/downloads/path/:/downloads"
    ports:
      - "8080:8080"
      - "8999:8999"
      - "8999:8999/udp"
    environment:
      - "VPN_ENABLED=yes"
      - "VPN_USERNAME=your_VPN_username"
      - "VPN_PASSWORD=your_VPN_password"
      - "LAN_NETWORK=192.168.1.0/24"
      - "NAME_SERVERS=8.8.8.8,8.8.4.4"
    restart: always

Running container UI on a custom non-8080 port

This is just an alternative to this compose above in case you want to run this container on some other port other then 8080 for whatever reason.

version: "3.5"

services:
  qbittorrent:
    image: markusmcnugen/qbittorrentvpn:latest
    network_mode: "bridge"
    privileged: true
    container_name: qbittorrent
    volumes:
      - "/your/config/path/:/config"
      - "/your/downloads/path/:/downloads"
    ports:
      - "8085:8085"
      - "8999:8999"
      - "8999:8999/udp"
    environment:
      - "VPN_ENABLED=yes"
      - "VPN_USERNAME=your_VPN_username"
      - "VPN_PASSWORD=your_VPN_password"
      - "LAN_NETWORK=192.168.1.0/24"
      - "NAME_SERVERS=8.8.8.8,8.8.4.4"
      - "WEBUI_PORT=8085"
    restart: always
NOTE: if you want to run on a port other then 8080 then use the WEBUI_PORT variable and set the value. On top of this you will have to change the port mappings on both the local and container side. So make sure both site match to the value you have set in the variable (8085 in this example)

Once you star the container in the end you might not be able to access the webUI on that custom port, just restart the container once again and then try. Until the /config/qBittorent.conf file has both value set in it, it will not work:

WebUI\Port=8085
WebUIPort=8085

Once you have both of those values in the config file you should be able to access your web UI on a custom port.


The most important option here is the fact that you will need to make an openvpn folder inside your config mount point. This is explained in the steps, but if you are not reading carefully you might miss it. In that folder drop the OVPN file that you wanna use.

Getting OVPN files from your provider will depend on the provider and also some providers use different username/password combination that’s different from your login credentials to use their service, so keep that in mind as well when filling out the configuration parameters.

So, for example, let's say that you will use this location for your config volume mount: /volume1/docker/qbittorrent. You will need to make openvpn folder inside that qbittorrent folder and copy the OVPN file inside it.

  1. Now that you have your container running, check the logs for any error and if all is well you should have the container running.
  2. Access the qBittorrent using your NAS IP address on port 8080

If you get an error in log saying "Cannot open TUN/TAP dev /dev/net/tun", read the next section, if all is well, skip to "How to check if you are running inside the VPN?"

I get the "ERROR: Cannot open TUN/TAP dev /dev/net/tun: No such file or directory (errno=2)"

NOTE: All credits for this fix go to Rui Marinho (@ruipmarinho) at https://ruimarinho.github.io/post/fix-tun-tap-not-available-on-a-synology-nas/

If this error happens plese follow the steps described bellow:

Check the tun module status

Check if you have the tunmodule installed:

lsmod | grep tun

If the result comes out empty, try installing it:

insmod /lib/modules/tun.ko

If everything went fine, move on to the next test.

Test if the tun.ko module works

Now let’s make sure the tun.komodule works as expected (run each line one at a time. If you get errors that the locations already exist just keep running the next line):

mkdir /dev/net
mknod /dev/net/tun c 10 200
chmod 600 /dev/net/tun
cat /dev/net/tun

If the result of the catcommand was File descriptor in bad state, it means the module has been correctly installed.

Make tun.ko module persistent

The module installation needs to be made persistent otherwise on every Synology restart, you’ll have to repeat the insmod command.

Create the following file to run on every system boot:

vi /usr/local/etc/rc.d/tun.sh

This will open up a tun.sh file and inside it copy this block and hit return:

#!/bin/sh -e

insmod /lib/modules/tun.ko
EOF

Make the script executable:

chmod a+x /usr/local/etc/rc.d/tun.sh

Reboot your Synology NAS or execute the script manually once. Done!

How to check if you are running inside the VPN?

Now that you have it running the question is are you inside the VPN or not. The easy way to test this is to use the Docker UI Terminal tab (of via console inside Portainer if you are running that as well) and open up a bash command.

Inside the command line, run this command:

curl ifconfig.me

This command will contact the service that will in return tell you what’s your public IP address. If you have a public address that’s different from the one you get when you visit whatsmyip address from your computer, then you are golden.

In my example, I will be using a NORDVPN provider connection to Switzerland. In the following steps, I will explain how to confirm that your traffic is inside the VPN tunnel and not exposed to your ISP.

  1. Once you get logged into your VPN container using the Terminal tab and running the curl ifconfig.me command, run that IP address result on http://whois.domaintools.com website.

Depending on the VPN file that you decided to use, you will get a different result and a different country. In this example, Switzerland was my destination.

Confirmation that the active docker IP is in Switzerland

Now that we have confirmation that we are indeed in a different country, it would be nice to see if the traffic is completely inside the VPN tunnel as well. The best way to do this is to trace traffic to a certain destination and see if we get a hit to our ISP provider along the way.

To do this we will use traceroute command inside the container. So again, log into it with a bash command (using the Terminal tab inside Docker UI). Now that you are inside you will need to install traceroute first. To do this run the following commands:

apt update
apt install traceroute
  1. With traceroute command line installed, run this to see how traffic is running:

traceroute protonmail.ch

traceroute command - second hop has the same IP address from picture 1, VPN destination and not your router. We want that.

As you can see from the image, the second hop (number 2) is hitting our VPN address confirming that we are indeed getting out in Switzerland (same IP as provided by using whois.domaintool.com. If this was not the case, the second hop would be your local router IP address and then a few more hops from your ISP. Considering that in this image there is no router local IP address as well as no ISP addresses, we can be sure that the traffic is completely tunneled.

One more bonus thing here is that once the VPN goes down, your torrenets will stop as well, so you have a kill switch scenario as well.

Again, logging onto your NAS IP address on port 8080 should land you on the main qBittorrent page where you can log in using username/password combination: admin/adminadmin (default values).

Main qBittotrrent login page on default port 8080
qBittorrent in action running via VPN

UPDATE: How to use this VPN qBittorrent container as a gateway for any other container

Now that you have this setup up and running  and you have qbittorrent container behind a VPN, it might be an idea to get some more containers that are not inside a VPN behind one for whatever reason.

Let's see how to set that up.

STEP01 - changes to the VPN container

In order to make this work you will need to publish more ports inside your VPN container first. So make changes to this VPN container by adding all the port mappings of the destination container that you want to access via the tunnel.

What does that mean? Let's say that your non-VPN container runs on port 17442, you will need to add that port mapping to this VPN/qbittorrent container.

At the moment, port mappings look like this:

    ports:
      - "8080:8080"
      - "8999:8999"
      - "8999:8999/udp"

But to have access to the UI of your non-VPN container you will need to add its port mapping here (why, coming up later on). So the new mapping for this VPN container need to look like this:

    ports:
      - "8080:8080"
      - "8999:8999"
      - "8999:8999/udp"
      - "17442:17442"

Start the VPN contianer again, make sure its running fine and carry on.

STEP02 - adding your non-VPN container to use your VPN container network

Now that we have made the change to the VPN container, you will need to start your non-VPN container the same way as you normally would but you will need to make few changes:

01 - remove the port mappings (the reason is that we have added its port to the VPN container port list)
02 - add it to the VPN network
03 - remote any current network definitions

So, we need to remove all the ports (or one port in this example, 17442) from the docker run or docker-compose file because we have already added them to our VPN container.

Next, we need to add this non-VPN contianer to use the VPN container network by adding this:

network_mode: container:<nameOfVPNcontainer>

What this will do is tell our current non-VPN container to use our VPN container as its network.

NOTE: be sure to remove all the ports and default network definitions from the current setup as you will not be able to run the container if you have those defined!

For example this is how a non-VPN container should be configured when being added to the VPN container network:

version: "3.5"
services:
  name_of_service:
    image: name_of_the_image
    network_mode: container:<nameOfVPNcontainer>
    container_name: name_of_nonVPN_container
    volumes:
      - "local_path:/container_path"
      - ...
    restart: always

So, you configure your non-VPN container as normal (name of the container, image, volumes, etc, but leave out port mapping and set the network_mode to match the VPN container name.

Now you are ready to start running this container and then just access its UI using the default port mapping that the image has configured for it (in this example 17442) by going to your NASIP and adding that port:

http://nasip:17442

All the traffic from this container will not run and flow via your VPN container completely encrypted.


If you have any questions, comments, or suggestions, please leave a comment down below.