270 lines
10 KiB
Markdown
270 lines
10 KiB
Markdown
---
|
||
layout: post
|
||
author: Sam Hadow
|
||
tags: podman sysadmin torrent
|
||
---
|
||
|
||
In this blog post I'll show you how to run qbittorrent in a podman (in rootless) container and route its traffic through a VPN connection, in this case ProtonVPN.
|
||
|
||
### note: does the VPN provider matter?
|
||
The VPN provider, if we don't take into account privacy, doesn't matter much as long as port forwarding is supported. Without port forwarding downloading torrents might still be possible but don't expect a good seeding/leeching ratio.
|
||
|
||
For BitTorrent, the protocol behind, to work, at least one peer has to be an active node (have a publicly open port) and the goal of port forwarding is to have this publicly open port. With port forwarding enabled you increase the number of peers you can communicate with. And since more peers will be able to initiate a connection with you (passive nodes can always initiate a connection), you'll have a better seeding/leeching ratio.
|
||
|
||
On less active or older torrents, port forwarding matters even more as if you end up in a situation where one peer has all the files, another peer wants to download them, but both have their ports closed, they won't be able to establish a connection between each-other and the second peer won't be able to download the torrent.
|
||
|
||
*Even with closed ports, peers are still able to discover each other with the trackers, DHT (Distributed Hash Table) or PEX (Peer Exchange). Only the connection establishement part is affected.*
|
||
|
||
### note: Why is a VPN prefered when torrenting?
|
||
A VPN is prefered when torrenting mainly for privacy and risks reductions.
|
||
BitTorrent is not anonymous by design, every peer in the swarm can see your public IP address. By the way it's how copyright monitoring companies are able to identify seeders and send copyright infrigement letters.
|
||
|
||
A VPN hides your public IP by exposing only the VPN endpoint. It helps not getting identified by copyright monitoring companies, and also against direct attack to your home connection from malicious peers. Without a VPN your IP can be logged accross long time periods and multiple torrents which allows profiling and targeted harassment.
|
||
|
||
It also encapsulates and encrypts traffic further so BitTorrent usage isn’t visible. Obfuscating your traffic might be useful against throtling as some ISPs detects BitTorrent via DPI (deep packet inspection) to throttle it or even throttle any kind of P2P traffic.
|
||
|
||
But keep in mind that a VPN doesn't guarantee anonimity, the VPN provider can still see (and potentially log) your real IP address as well as the packets going through it.
|
||
|
||
#### Disclaimer:
|
||
hiding your IP address from copyright monitoring companies obviously doesn't make piracy legal, it just drastically reduces the risks of you getting identified and caught.
|
||
|
||
#### Disclaimer 2:
|
||
A VPN doesn't protect you against malicious torrent payloads (a trojan disguised as media for example) and attacks over the existing torrent connection (exploit vulnerabilities in the client, sending malformed data and so on...)
|
||
|
||
|
||
|
||
# Steps
|
||
|
||
## Creating the containers
|
||
|
||
### 1. Pod creation
|
||
|
||
First I created a pod, without an infrastructure `--infra=false` because we'll use gluetun network and not the host network (which wouldn't go through the VPN connection). A pod is not required, you could just create the qbittorrent and the gluetun container. But I prefered to create one to logically group the containers and also see them with the command `podman pod ls`.
|
||
|
||
The systemd unit file will look like this:
|
||
```ini
|
||
# pod-qbittorrent.service
|
||
|
||
[Unit]
|
||
Description=Podman pod-qbittorrent.service
|
||
Wants=network-online.target
|
||
After=network-online.target
|
||
RequiresMountsFor=/run/user/1000/containers
|
||
Wants=container-torrent-qbit.service container-torrent-gluetun.service
|
||
|
||
[Service]
|
||
Type=oneshot
|
||
RemainAfterExit=yes
|
||
Environment=PODMAN_SYSTEMD_UNIT=%n
|
||
TimeoutStartSec=30
|
||
TimeoutStopSec=30
|
||
|
||
ExecStart=/usr/bin/podman pod create \
|
||
--pod-id-file %t/pod-qbittorrent.pod-id \
|
||
--exit-policy=stop \
|
||
--name qbittorrent \
|
||
--infra=false \
|
||
--replace
|
||
|
||
ExecStop=/usr/bin/podman pod rm -f --pod-id-file %t/pod-qbittorrent.pod-id
|
||
|
||
[Install]
|
||
WantedBy=multi-user.target
|
||
```
|
||
|
||
## 2. Gluetun container
|
||
|
||
We will use [gluetun](https://github.com/qdm12/gluetun) for the VPN connection.
|
||
|
||
First you need to create the secrets for `WIREGUARD_ENDPOINT_IP`, `WIREGUARD_PUBLIC_KEY`, `WIREGUARD_PRIVATE_KEY`. Creating these secrets is not necessary but it avoids exposing sensitive information in your configuration files.
|
||
|
||
With ProtonVPN when downloading a wireguard configuration it'll look like this:
|
||
```ini
|
||
[Interface]
|
||
PrivateKey = <private_key>
|
||
Address = 10.2.0.2/32
|
||
DNS = 10.2.0.1
|
||
|
||
[Peer]
|
||
# BE#67
|
||
PublicKey = <peer_public_key>
|
||
AllowedIPs = 0.0.0.0/0, ::/0
|
||
Endpoint = <endpoint_IP>:51820
|
||
```
|
||
|
||
To create the secrets you'll need to first derive the public key from the private key:
|
||
```bash
|
||
echo -n "private_key" > privkey
|
||
wg pubkey < privkey
|
||
```
|
||
|
||
Then you can create the secrets
|
||
```bash
|
||
echo -n "private_key" > /tmp/secret
|
||
podman secret create wg_sk /tmp/secret
|
||
echo -n "public_key" > /tmp/secret
|
||
podman secret create wg_pk /tmp/secret
|
||
echo -n "endpoint_IP" > /tmp/secret
|
||
podman secret create wg_ip /tmp/secret
|
||
```
|
||
|
||
Then the container unit file will look like this:
|
||
*Of course you'll need to adapt the path for the volume*
|
||
```ini
|
||
# container-torrent-gluetun.service
|
||
|
||
[Unit]
|
||
Description=Podman container-torrent-gluetun.service
|
||
Documentation=man:podman-generate-systemd(1)
|
||
Wants=network-online.target
|
||
After=network-online.target
|
||
RequiresMountsFor=%t/containers
|
||
BindsTo=pod-qbittorrent.service
|
||
After=pod-qbittorrent.service
|
||
|
||
[Service]
|
||
Environment=PODMAN_SYSTEMD_UNIT=%n
|
||
Restart=on-failure
|
||
TimeoutStopSec=90
|
||
ExecStart=/usr/bin/podman run \
|
||
--cidfile=%t/%n.ctr-id \
|
||
--cgroups=no-conmon \
|
||
--rm \
|
||
--pod-id-file %t/pod-qbittorrent.pod-id \
|
||
--sdnotify=conmon \
|
||
--replace \
|
||
-d \
|
||
--name=torrent-gluetun \
|
||
-p 8080:8080 \
|
||
--stop-timeout 60 \
|
||
--tmpfs /tmp \
|
||
--cap-add NET_ADMIN \
|
||
--cap-add NET_RAW \
|
||
--device /dev/net/tun:/dev/net/tun \
|
||
-v /home/data/podman/gluetun:/gluetun:z \
|
||
-e VPN_SERVICE_PROVIDER=custom \
|
||
-e VPN_TYPE=wireguard \
|
||
--secret wg_ip,type=env,target=WIREGUARD_ENDPOINT_IP \
|
||
-e WIREGUARD_ENDPOINT_PORT=51820 \
|
||
--secret wg_pk,type=env,target=WIREGUARD_PUBLIC_KEY \
|
||
--secret wg_sk,type=env,target=WIREGUARD_PRIVATE_KEY \
|
||
-e WIREGUARD_ADDRESSES=10.2.0.2/32 \
|
||
-e VPN_PORT_FORWARDING_PROVIDER=protonvpn \
|
||
-e VPN_PORT_FORWARDING=on \
|
||
--label io.containers.autoupdate=registry \
|
||
docker.io/qmcgaw/gluetun:latest
|
||
ExecStop=/usr/bin/podman stop \
|
||
--ignore -t 30 \
|
||
--cidfile=%t/%n.ctr-id
|
||
ExecStopPost=/usr/bin/podman rm \
|
||
-f \
|
||
--ignore \
|
||
--cidfile=%t/%n.ctr-id
|
||
Type=notify
|
||
NotifyAccess=all
|
||
|
||
[Install]
|
||
WantedBy=default.target
|
||
```
|
||
|
||
Here I put "custom" in the `VPN_SERVICE_PROVIDER` environment variable instead of "protonvpn", or whichever VPN provider you might be using, because port forwarding wouldn't work otherwise. "protonvpn is then later specified in the`VPN_PORT_FORWARDING_PROVIDER` environment variable.
|
||
You can have a look at the [wiki](https://github.com/qdm12/gluetun-wiki) in the option section for port forwarding if you use another VPN provider.
|
||
|
||
When looking at the logs from gluetun container with the command:
|
||
```bash
|
||
podman logs torrent-gluetun
|
||
```
|
||
you should see a line like this:
|
||
```ini
|
||
INFO [port forwarding] port forwarded is 45497
|
||
```
|
||
It's the port you'll want to use in qbittorrent. However check it again when you restart the container as this port can sometimes change.
|
||
|
||
## 3. Qbittorrent container
|
||
|
||
After the gluetun container, we can create the container for qbittorrent, we'll make this container bind to gluetun container in order to use the network provided by it and correctly route the traffic through the VPN.
|
||
*Don't forget to adapt QBT_WEBUI_PORT to the one you prefer*
|
||
```ini
|
||
# container-torrent-qbit.service
|
||
|
||
[Unit]
|
||
Description=Podman container-torrent-qbit.service
|
||
Wants=network-online.target container-torrent-gluetun.service
|
||
After=network-online.target container-torrent-gluetun.service
|
||
RequiresMountsFor=%t/containers
|
||
BindsTo=pod-qbittorrent.service container-torrent-gluetun.service
|
||
After=pod-qbittorrent.service
|
||
|
||
[Service]
|
||
Environment=PODMAN_SYSTEMD_UNIT=%n
|
||
Restart=on-failure
|
||
TimeoutStopSec=1860
|
||
ExecStart=/usr/bin/podman run \
|
||
--cidfile=%t/%n.ctr-id \
|
||
--cgroups=no-conmon \
|
||
--sysctl net.ipv6.conf.all.disable_ipv6=1 \
|
||
--rm \
|
||
--pod-id-file %t/pod-qbittorrent.pod-id \
|
||
--sdnotify=conmon \
|
||
--replace \
|
||
-d \
|
||
--name=torrent-qbit \
|
||
--network container:torrent-gluetun \
|
||
--stop-timeout 1800 \
|
||
--tmpfs /tmp \
|
||
-e QBT_LEGAL_NOTICE=confirm \
|
||
-e QBT_WEBUI_PORT=8080 \
|
||
-v /home/data/podman/qbittorrent/config:/config:z \
|
||
-v /home/data/podman/qbittorrent/data:/downloads:z \
|
||
--label io.containers.autoupdate=registry docker.io/qbittorrentofficial/qbittorrent-nox:latest
|
||
ExecStop=/usr/bin/podman stop \
|
||
--ignore -t 1800 \
|
||
--cidfile=%t/%n.ctr-id
|
||
ExecStopPost=/usr/bin/podman rm \
|
||
-f \
|
||
--ignore -t 1800 \
|
||
--cidfile=%t/%n.ctr-id
|
||
Type=notify
|
||
NotifyAccess=all
|
||
|
||
[Install]
|
||
WantedBy=default.target
|
||
```
|
||
|
||
## managing the containers
|
||
|
||
All my unit files are in `~/.config/systemd/user`
|
||
|
||
When you create new unit files, or change them, don't forget to run
|
||
```bash
|
||
systemctl --user daemon-reload
|
||
```
|
||
|
||
Then you can start the pod like this:
|
||
```bash
|
||
systemctl --user start pod-qbittorrent.service
|
||
```
|
||
*(or start it and enable it with* `enable --now` *instead of* `start`*)*
|
||
|
||
|
||
And to stop it:
|
||
```bash
|
||
systemctl --user stop pod-qbittorrent.service
|
||
```
|
||
|
||
|
||
In case qbittorrent doesn't get an external IP because it started before the VPN connection was established you can restart it like this
|
||
```bash
|
||
systemctl --user restart container-torrent-qbit.service
|
||
```
|
||
|
||
### note:
|
||
You might have noticed that I use the option `:z` on my containers, this is because I use SELinux. You can read my post about SELinux [here](/blog/why-you-should-use-SELinux-and-how.html) for more details.
|
||
|
||
### note 2:
|
||
You might also have noticed I use a label on my containers:
|
||
```ini
|
||
--label io.containers.autoupdate=registry
|
||
```
|
||
This label is used to automatically pull the latest image and update the container whenever a new latest image is released. It is not necessary for this setup to work but is useful to have your containers automatically updated.
|