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