Deploying Wireguard and qBittorrent container stack
2024-11-15
6 min read
There are numerous existing tutorials about setting up qBittorrent and Wireguard containers, but many neglected enabling IPv6 for the containers. Another commonly neglected point is you can tunnel IPv6 traffic over a v4-only Wireguard connection, so one can torrent over IPv6 even if they don't have a global IPv6 address. As a result, their qBittorrent setups lost a great percentage of peers that are only reachable via IPv6. This guide walks you through creating a Docker Compose stack that includes a Wireguard and a qBittorrent container. With this setup, we'll have a 24/7 torrenting service that has maximal IPv6 capability.
Install Docker
This setup assumes a Debian 12 (Bookworm) server environment, but any Linux distribution with Docker will work. Install Docker using your package manager, or run the official installation script:
curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh
Enable Docker IPv6 Support
By default, Docker's IPv6 support is experimental. (Yes, you hear it right: Docker's IPv6 support is STILL in experimental stage in 2024.) To enable it, edit (or create) /etc/docker/daemon.json
and add the following configuration:
{
"experimental": true,
"ip6tables": true,
"fixed-cidr-v6": "2001:db8:1::/64" # Optional, replace with your desired GUA range for containers
}
These flags enable Docker's IPv6 functionality. The optional fixed-cidr-ipv6
flag sets a default address range for all the containers created directly with the docker
command. But since we create our application containers using Docker Compose, the default range won't apply. We'll need to manually set up a range for each container network that needs IPv6 connectivity.
Per official Docker guide on IPv6 networking, we don't have to set the IPv6 flag in order to use IPv6 networking in containers. My testing, however, tells otherwise.
Restart Docker daemon to apply the changes. You won't see anything special, but we'll know it's working when we run our qBittorrent container.
sudo systemctl restart docker
Create Wireguard and qBittorrent containers
Create a directory for our application stack (e.g., qbittorrent), and navigate into it. Create a file named docker-compose.yaml
with the following content:
services:
wireguard:
image: linuxserver/wireguard
container_name: wireguard
cap_add:
- NET_ADMIN
- SYS_MODULE
environment:
- PUID=1000
- PGID=1000
- TZ=America/Los_Angeles # Change to your time zone
volumes:
- ./wg-config:/config
- /lib/modules:/lib/modules
ports:
- "127.0.0.1:8080:${QBT_WEBUI_PORT}"
- "[::1]:8080:${QBT_WEBUI_PORT}"
- "12345:12345/udp" # Replace with your VPN's port-forwarding configuration
- "51820:51820/udp" # Default Wireguard port
networks:
- qbt-wg-network
sysctls:
- net.ipv4.conf.all.src_valid_mark=1 # Required for Wireguard container. See https://github.com/linuxserver/docker-wireguard
- net.ipv6.conf.all.disable_ipv6=0 # Required for IPv6 capability
restart: unless-stopped
qbittorrent-nox:
container_name: qbittorrent-nox
environment:
- PUID=1000
- PGID=1000
- QBT_EULA=${QBT_EULA}
- QBT_VERSION=${QBT_VERSION}
- QBT_WEBUI_PORT=${QBT_WEBUI_PORT}
- TZ=America/Los_Angeles # Change to your time zone
image: qbittorrentofficial/qbittorrent-nox:${QBT_VERSION}
network_mode: service:wireguard
read_only: true
restart: unless-stopped
stop_grace_period: 30m
tmpfs:
- /tmp
volumes:
- ${QBT_CONFIG_PATH}:/config
- ${QBT_DOWNLOADS_PATH}:/downloads
networks:
qbt-wg-network:
enable_ipv6: true
ipam:
config:
# Set this to a subnet that won't be used by any GUA address. See the explanation below.
- subnet: d000::/112 # Change to your favorite CIDR
In the same folder, create an .env
file with the environmental variables:
QBT_EULA=accept
QBT_VERSION=latest
QBT_WEBUI_PORT=8080
QBT_CONFIG_PATH=./qb-config
QBT_DOWNLOADS_PATH=/path/to/your/media/drive
Some remarks on the Docker Compose config:
- We need a sysctl flag
net.ipv4.conf.all.src_valid_mark=1
to make Wireguard container work properly. Getting it working under IPv6 requires another flagnet.ipv6.conf.all.disable_ipv6=0
. - As a result, we also need to add the
NET_ADMIN
capability to set the flags and theSYS_MODULE
capability to load Wireguard kernel module. - To utilize the port-forwarding feature of our VPN, we need to expose that UDP port (12345 in this example) in the config.
- We also need to set an IPv6 subnet for the container network if we want IPv6 connectivity. The subnet should be a GUA address that won't be used by any existing device, for example
d000::/112
.
Add Wireguard Config
Cool, let's run the stack once to initialize the configuration directory:
docker compose up -d
docker compose down
We should see a wg-config
folder now. Grab your Wireguard config from your VPN provider, and move it to wg-config/wg_confs/wg0.conf
. Here's the config generator setup I used at AirVPN (NOT affiliated).
Add some routing rules to the config, or we wouldn't be able to access the qBittorrent UI. Here's what the config file should look like after editing:
[Interface]
Address = <redacted>, <redacted_ipv6>
PrivateKey = <redacted>
ListenPort = 51820
MTU = 1320
DNS = <redacted>, <redacted_ipv6>
# The following rule excludes 172.16.0.0/12 and 192.168.0.0/16 from Wireguard, so it can interact with the container host.
# Excluding the ranges using `AllowedIPs` would also work but ugly
# Check https://www.procustodibus.com/blog/2021/03/wireguard-allowedips-calculator/ to see how complicated the range would be
PostUp = DROUTE=$(ip route | grep default | awk '{print $3}'); HOMENET=192.168.0.0/16; HOMENET2=172.16.0.0/12; ip route add $HOMENET via $DROUTE; ip route add $HOMENET2 via $DROUTE; iptables -I OUTPUT -d $HOMENET -j ACCEPT;iptables -A OUTPUT -d $HOMENET2 -j ACCEPT; iptables -A OUTPUT ! -o %i -m mark ! --mark $(wg show %i fwmark) -m addrtype ! --dst-type LOCAL -j REJECT
PreDown = HOMENET=192.168.0.0/16; HOMENET2=172.16.0.0/12; ip route delete $HOMENET; ip route delete $HOMENET2; iptables -D OUTPUT ! -o %i -m mark ! --mark $(wg show %i fwmark) -m addrtype ! --dst-type LOCAL -j REJECT; iptables -D OUTPUT -d $HOMENET -j ACCEPT; iptables -D OUTPUT -d $HOMENET2 -j ACCEPT
[Peer]
PublicKey = <redacted>
PresharedKey = <redacted>
Endpoint = <redacted>
AllowedIPs = 0.0.0.0/0, ::/0
PersistentKeepalive = 15
If your home network lacks IPv6 access, remove the IPv6 endpoints in the Address
and DNS
fields and ensure the peer Endpoint
address is reachable via IPv4.
Restart the service.
docker compose up -d
You should be able to access the qBittorrent web UI over port 8080.
Configure qBittorrent client
We are almost done. Let's configure the qBittorrent client now.
- Open the qBittorrent web UI. Navigate to Tools->Options->Connections, and set the
Listening Ports
to match the VPN's forwarded port. - Follow the qBittorrent optimization guide from your VPN provider website.
- (Optionally) set qBittorrent to use the VPN interface exclusively, so that we can safely download our Linux ISOs. Go to Tools->Options->Advanced, and select
wg0
from theNetwork interface
dropdown. Remember to scroll all the way down and click Save! - On the other hand, if you don't want to use your VPN, you can select
eth0
or whatever interface from the same dropdown and save.
Have fun!