Introduction

One of the services I always wanted to have on my raspberry pi home server is VPN and BitTorrent, which basically, route all BitTorrent traffic through a VPN container. Then I saw Wolfgang’s “Set Up Your Own Wireguard VPN Server with 2FA in 5 Minutes!” on Youtube, which inspired me to set up my own VPN server. I quickly created an instance on Oracle Cloud and ran the ansible playbook to deploy the wireguard VPN. After I tested a few months on Mobile and PC, I’m comfortable setting up server and client. So, I decided to use the Wireguard in my raspberrypi-homeserver project.

blog-14-1

But why BitTorrent with VPN?

BitTorrent does not, on its own, offer its users anonymity. One can usually see the IP addresses of all peers in a swarm in one’s own client or firewall program. This may expose users with insecure systems to attacks.

https://en.wikipedia.org/wiki/BitTorrent#Anonymity

For better anonymity, I decided to use VPN for BitTorrent and to download my favourite linux distros

Goal

The goal of this blog is a how-to guide on routing BitTorrent client traffic through Wireguard VPN on the Docker swarm cluster.

blog-14-1

NOTE ✋: The scope of the post is to set up qBittorent and Wireguard VPN clients only, DOES NOT include wireguard server setup. I would recommend checking Set Up Your Own Wireguard VPN Server with 2FA in 5 Minutes! to know how to set up Wireguard VPN server.

This blog post is divided into 2 parts

  • ✒️ Part 1 covers
    • Intro
    • Challenges on docker swarm
    • Architecture
    • Deployment
  • ✒️ Part 2 covers
    • Testing the stack
    • qBittorrent proxy configuration and testing
    • Kill switch configuration
    • Conclusion

By the way, recently I migrated my raspberry pi home server docker-compose setup to docker swarm services, maybe that is for another blog on what were the challenges. But for now, let’s see how to route BitTorrent traffic through the Wireguard VPN docker container.

Source code available in my GitHub repo: https://github.com/veerendra2/raspberrypi-homeserver/tree/main/services/torrent

Challenges on docker swarm

There are some challenges I faced while deploying the BitTorrent client using wireguard.

Container linking

👉 https://docs.docker.com/network/links/

Unlike docker-compose container linking, docker swarm doesn’t allow container linking.

It would have been a very easy and secure link between qBittorent and wireguard client

🟢 Github open issue: https://github.com/moby/moby/issues/33055

Alternate options

1. ip routes and iptable rules

Create some iptable rules to make Wireguard container a NAT router and set default route to Wireguard in qBittorrent container. In docker-compose, assign ip address to the container like below

...
  networks:
    dhcp-relay-net:
        ipv4_address: '172.31.0.10'
    front-tier: {}
...

then I can create a shell script to create iptables rules and routes, but in docker swarm, it is not possible to assign ip to a container in the stack

🟢 Github open issue: https://github.com/moby/moby/issues/31860

2. Go back to docker-compose

Since docker-compose has container linking, one option is to go back to the docker-compose setup for this stack. I use traefik for reverse proxy with sub path. After I googled, traefik can’t support both docker standalone(docker-composer) and docker swarm at the same time.

🟢 Github open issue: https://github.com/traefik/traefik/issues/6063

3. Monolithic Docker image

Use all-in-one docker image which has qBittorrent and Wireguard. This options looks good, but the down side of the options is typical monolithic approach issues

  • If I want to add or remove services like radarr, jackett, etc I have re-build and have no flexibility
  • Have to rebuild the image if there is a version change

4. SOCKS5 proxy with internal network

The final and decent approach is to make sure qBittorrent container does NOT directly connect to the Internet and connect to Wireguard container via the internal network i.e. internal: true to access the Internet with SOCKS5 proxy protocol (As you can see in below diagram)

qBittorrentSOCKS5ProxyWiCrleigeunatrdINTERNET

After googling, I found dante-server “A free SOCKS server”. I opened github issue, feature request #250 in linuxserver/docker-wireguard to add dante-server in Wireguard image. But, it was rejected, because, it can be done in either customizing containers or as a docker mods.

So, I customized the linuxserver’s Wireguard container by installing and starting the dante-server while bootstrapping the Wireguard container, as you can next sections

Architecture

Finally, here is the architecture with traefik reverse proxy

blog-14-2

From the above diagram, the traefik_private overlay network is configured with internal: true, which mean there is no external connectivity, but traefik can set up the reverse proxy to qBittorrent, so that I can access. Wireguard is connected to traefik_private and internal overlay network with internal: false i.e. there is external connectivity. So, the idea here is run a SOCKS5 server on Wireguard and configure qBittorrent proxy.

  • qBittorent can connect Wireguard, but not directly to the Internet
  • Wireguard is accessible to qBittorent and connected to the Internet too

In a nutshell, qBittorent can reach the Internet via Wiregaurd SOCKS5 proxy… ta-da!🎉

Deploy

📂 You can browse source code in my GitHub repo: https://github.com/veerendra2/raspberrypi-homeserver

I created a simple ansible playbook to deploy all services on my raspberry pi. But for the sake of the blog, I will show you how to deploy manually with traefik reverse proxy

Traefik reverse proxy

Since I’m using traefik reverse proxy in my raspberry pi. I’m showing how to deploy it, if you have a different reverse proxy(like Nginx), skip this step. But, make sure you make it compatible with the above architecture

$ git clone https://github.com/veerendra2/raspberrypi-homeserver.git
$ cd services/traefikv2

# Create traefik_private and traefik_public network
$ docker stack deploy -c traefik.yml traefik

$ docker network ls
NETWORK ID     NAME                  DRIVER    SCOPE
9ov3x46i6ci0   traefik_private       overlay   swarm
ydbzvtoc1xvg   traefik_public        overlay   swarm

# Deploy traefik reverse proxy
$ docker stack deploy -c docker-stack.yml traefikv2

$ $ docker stack ls
NAME          SERVICES
traefik       1
traefikv2     1

Wireguard VPN and qBittorrent

📂 https://github.com/veerendra2/raspberrypi-homeserver/tree/main/services/torrent

Make sure you have Wireguard VPN server up and running and get wg0.conf

Here is my directory structure(Ignore jackett and radarr for now)

$ cd services/torrent

$ tree .
.
├── README.md
├── docker-stack.yml
├── ip-test.sh
├── jackett
│   └── ServerConfig.json
├── qbittorrent
│   └── qBittorrent.conf
├── radarr
│   └── config.xml
└── wireguard
    ├── dante-server
    │   ├── danted.conf
    │   ├── install.sh
    │   └── run.sh
    └── wg0.conf

5 directories, 10 files

The dante-server installation and bootstrapping is straight forward, you just create a scripts like below

$ cd services/torrent

$ tree wireguard/dante-server/
wireguard/dante-server/
├── danted.conf <---- danted configuration
├── install.sh <----- Install dante-server
└── run.sh <--------- Start the danted daemon

0 directories, 3 files

And mount these files in wireguard container like below(docker-stack.yml#L38-#L43)

...
    volumes:
      - ./wireguard/dante-server/danted.conf:/etc/danted.conf
      - ./wireguard/dante-server/install.sh:/custom-cont-init.d/install.sh:ro
      - ./wireguard/dante-server/run.sh:/custom-services.d/run.sh:ro
...

That’s it! the scripts will install and bootstrap dante-server in Wireguard container

$ cd services/torrent

# Deploy stack
$ docker stack deploy -c docker-stack.yml torrent

$ docker stack ls
NAME          SERVICES
torrent       4
traefik       1
traefikv2     1


That’s it for now! Next, in part 2, we will see how to test connections and configure clients