Mullvad VPN and qBittorrent in Docker

The other day, I had the worst customer support experience with a company called NordVPN.
I used their service for over a year for pure convenience; a Docker stack for both their VPN service and qBittorrent exists and runs with a single compose deployment.

I no longer wanted to deal with this company and started looking for alternatives with a similar setup.
I couldn’t find anything turnkey, so I had to create my own.
I’ve chosen Mullvad as my new VPN provider; let’s see how it works out long-term!

Let me show you how to do it; it’s easier than I thought: Mullvad VPN and qBittorrent in Docker.

OpenVPN Container

I’m using this dude:
https://github.com/wfg/docker-openvpn-client

And this is my setup:

version: "2"
services:
  openvpn-client:
    image: yacht7/openvpn-client
    container_name: openvpn-client
    cap_add:
        - NET_ADMIN
    environment:
        - KILL_SWITCH=on
        - FORWARDED_PORTS=58670
        - SUBNETS=10.0.0.0/24
    devices:
        - /dev/net/tun
    volumes:
        - /opt/mullvad/data/vpn:/data/vpn
    ports:
        - 8080:8080
    restart: unless-stopped

We need the cap_add as the container requires permissions to create connections.
The killswitch stays on as a security measure, and the subnet is my local subnet so that I can access it.

At the bottom, we’re opening port 8080, which will be passed through to qBittorrent’s web interface later.

But what is the other stuff?

I created a folder on the Docker host at /opt/mullvad/data/vpn and attached it to the container.
Let’s have a look inside:

Get the config files from Mullvad

Over at Mullvad, click My account and enter your unique account number.

Once logged in, go to their OpenVPN configurator.

Select Linux and a country and city of your choice, and download the zip file.

Unzip it and throw the files via SSH into the /vpn folder.

Now we go back to Mullvad and select “Manage devices and ports,” scroll all down, and choose the same city and “no device.”

The result is a random high port, and you add it into the compose file as “forwarded ports.”
Start the container either per CLI or Portainer.

Portainer makes the verification pretty convenient.
Go to the container and select Console:

Make sure to change from bash to /sh:

And paste the following command into the console:

wget http://ipecho.net/plain -O - -q ; echo

The result should be different than https://www.whatismyip.com/

That’s it, and the VPN container part is alive.

qBittorrent Container

The obvious choice is this one.
Is there even an alternative? I don’t think so.

Here’s my compose file:

version: "2.1"
services:
  qbittorrent:
    image: lscr.io/linuxserver/qbittorrent:latest
    container_name: qbittorrent
    environment:
      - PUID=0
      - PGID=0
      - TZ=Europe/Berlin
    volumes:
      - /opt/qbittorrent:/config
      - /mnt/downloads:/downloads
    network_mode: container:openvpn-client
    restart: unless-stopped
    depends_on:
      - openvpn-client

There are a few things which require special attention.

First, I removed all port-related lines from the original compose files, as we don’t need them here. 
We’re forwarding 8080 from the VPN container.

I created a persistent folder for the config files and mapped my downloads folder to the container.

Also, there are two references to the VPN container.
One is the network_mode, telling qBt to talk to the openvpn-client container.

The other is the “depends-on,” another failsafe mechanism. 

Before starting downloading another Linux distro via torrent, let’s try the same connection test again from inside the qBt container:

The expected result is the same IP as from inside the openvpn-client container.

And that’s it, really, a few steps but no rocket science.

Update:
Steps with Wireguard added.

More homelab posts:

1 2 3 4

Leave a Comment

Your email address will not be published. Required fields are marked *