This is how I torrent over Mullvad. I have no hesitation to recommend Mullvad - but I am not a crypto or security expert.
The main image fails closed - if the VPN goes down, transmission disconnects.
This setup also includes a SOCKS server that proxies your traffic over the same VPN. I use a separate browser (librewolf) and set the SOCKS proxy to :2020 including sending DNS over SOCKS. That’s because my country blocks piracy-related sites at the DNS level. If you don’t need this, you can delete the socks section of the docker-compose file.
On my ubuntu laptop, I install transmission-remote-gtk in order to click on a magnet link and have it added. Otherwise you have to browse to the container’s web interface, which gets tiresome.
I have this installed as a systemd service so it runs on boot. I use the systemd state and credential features as a safeguard against my own mistakes with permissions, but my long-term goal is to encrypt these files on disk. Linux can be pwned - I have read that around 35% of botnet nodes are linux (although these are presumably mostly weak IoT devices). The secondary benefit of the LoadCredential/CREDENTIALS_DIRECTORY mechanism is that it doesn’t expose secrets as environment variables.
The p2p.service file needs to be in that path, but you can put the other files wherever you want.
Known issues / todo list
The socks proxy sometimes falls over, I haven’t looked into why
The downloaded files will be owned by root, since that’s what the container runs as
File contents
/root/.secrets/mullvad:
123456789
""
For mullvad, there is no password, only an account number. I believe that the empty quotes are necessary. This file should be owned by root and chmod 600; containing dir should be 700. Replace the account number with your own account, obvs!
/etc/systemd/system/p2p.service:
[Unit]Description=p2p
Requires=docker.service multi-user.target
After=docker.service network-online.target dhcpd.service
[Service]Restart=always
RemainAfterExit=yesWorkingDirectory=/usr/local/bin/p2p
ExecStart=docker compose up --remove-orphans
ExecStop=docker compose down
LoadCredential=mullvad:/root/.secrets/mullvad
DynamicUser=yesSupplementaryGroups=docker
StateDirectory=p2p
StateDirectoryMode=700[Install]WantedBy=multi-user.target
/usr/local/bin/p2p/docker-compose.yml:
---version:"3.7"services:p2p:restart:alwayscontainer_name:p2pimage:haugene/transmission-openvpn# see also: https://www.nickkjolsing.com/posts/dockermullvadvpn/cap_add:-NET_ADMINsysctls:-"net.ipv6.conf.all.disable_ipv6=0"# ipv6 must be enabled for Mullvad to workvolumes:-${STATE_DIRECTORY:-./config/}:/config# dir managed by systemd - but defaults to ./config if running interactively-${CREDENTIALS_DIRECTORY:-.}/mullvad:/config/openvpn-credentials.txt:ro# var populated by LoadCredential - but defaults to ./mullvad if running interactively-transmission:/data-transmission_incomplete:/data/incomplete-/my/directory/Downloads:/data/completedenvironment:-OPENVPN_PROVIDER=MULLVAD-OPENVPN_CONFIG=se_all# sweden-LOCAL_NETWORK=192.168.1.0/24# put your own LAN network here - in most cases it should end in .0/24-TRANSMISSION_WEB_UI=flood-for-transmission# optionalports:-9091:9091-80:9091-2020:2020socks:restart:alwayscontainer_name:socksimage:lthn/dantenetwork_mode:"service:p2p"volumes:-./sockd.conf:/etc/sockd.confdepends_on:-p2pvolumes:transmission:external:falsetransmission_completed:external:falsetransmission_incomplete:external:false
/usr/local/bin/p2p/sockd.conf:
logoutput: stderr
# debug: 2
internal: 0.0.0.0 port = 2020
external: tun0
external.rotation: route
clientmethod: none
socksmethod: username none
user.privileged: root
user.notprivileged: nobody
user.unprivileged: sockd
# Allow everyone to connect to this server.
client pass {
from: 0.0.0.0/0 to: 0.0.0.0/0
log: connect error # disconnect
}
# Allow all operations for connected clients on this server.
socks pass {
from: 0.0.0.0/0 to: 0.0.0.0/0
command: bind connect udpassociate
log: error # connect disconnect iooperation
#socksmethod: username
}
# Allow all inbound packets.
socks pass {
from: 0.0.0.0/0 to: 0.0.0.0/0
command: bindreply udpreply
log: error # connect disconnect iooperation
}
Steps
Install docker and docker-compose, e.g. with sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
Create the files with contents as above
sudo systemctl enable p2p
sudo systemctl start p2p
Check what it’s doing: systemctl status p2p
On first start, it will take a few minutes to pull the images
To debug interactively while also passing the creds, use sudo systemd-run -P --wait -p LoadCredential=mullvad:/root/.secrets/mullvad docker compose up --remove-orphans
Every so often, cd into /usr/local/bin/p2p and run docker compose pull to update the images.
Yes!!!
Implementation of VPN’d torrent client
This is how I torrent over Mullvad. I have no hesitation to recommend Mullvad - but I am not a crypto or security expert.
The main image fails closed - if the VPN goes down, transmission disconnects.
This setup also includes a SOCKS server that proxies your traffic over the same VPN. I use a separate browser (librewolf) and set the SOCKS proxy to :2020 including sending DNS over SOCKS. That’s because my country blocks piracy-related sites at the DNS level. If you don’t need this, you can delete the socks section of the docker-compose file.
On my ubuntu laptop, I install
transmission-remote-gtk
in order to click on a magnet link and have it added. Otherwise you have to browse to the container’s web interface, which gets tiresome.I have this installed as a systemd service so it runs on boot. I use the systemd state and credential features as a safeguard against my own mistakes with permissions, but my long-term goal is to encrypt these files on disk. Linux can be pwned - I have read that around 35% of botnet nodes are linux (although these are presumably mostly weak IoT devices). The secondary benefit of the
LoadCredential
/CREDENTIALS_DIRECTORY
mechanism is that it doesn’t expose secrets as environment variables.The p2p.service file needs to be in that path, but you can put the other files wherever you want.
Known issues / todo list
File contents
/root/.secrets/mullvad
:/etc/systemd/system/p2p.service
:[Unit] Description=p2p Requires=docker.service multi-user.target After=docker.service network-online.target dhcpd.service [Service] Restart=always RemainAfterExit=yes WorkingDirectory=/usr/local/bin/p2p ExecStart=docker compose up --remove-orphans ExecStop=docker compose down LoadCredential=mullvad:/root/.secrets/mullvad DynamicUser=yes SupplementaryGroups=docker StateDirectory=p2p StateDirectoryMode=700 [Install] WantedBy=multi-user.target
/usr/local/bin/p2p/docker-compose.yml
:--- version: "3.7" services: p2p: restart: always container_name: p2p image: haugene/transmission-openvpn # see also: https://www.nickkjolsing.com/posts/dockermullvadvpn/ cap_add: - NET_ADMIN sysctls: - "net.ipv6.conf.all.disable_ipv6=0" # ipv6 must be enabled for Mullvad to work volumes: - ${STATE_DIRECTORY:-./config/}:/config # dir managed by systemd - but defaults to ./config if running interactively - ${CREDENTIALS_DIRECTORY:-.}/mullvad:/config/openvpn-credentials.txt:ro # var populated by LoadCredential - but defaults to ./mullvad if running interactively - transmission:/data - transmission_incomplete:/data/incomplete - /my/directory/Downloads:/data/completed environment: - OPENVPN_PROVIDER=MULLVAD - OPENVPN_CONFIG=se_all # sweden - LOCAL_NETWORK=192.168.1.0/24 # put your own LAN network here - in most cases it should end in .0/24 - TRANSMISSION_WEB_UI=flood-for-transmission # optional ports: - 9091:9091 - 80:9091 - 2020:2020 socks: restart: always container_name: socks image: lthn/dante network_mode: "service:p2p" volumes: - ./sockd.conf:/etc/sockd.conf depends_on: - p2p volumes: transmission: external: false transmission_completed: external: false transmission_incomplete: external: false
/usr/local/bin/p2p/sockd.conf
:Steps
sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
sudo systemctl enable p2p
sudo systemctl start p2p
systemctl status p2p
sudo systemd-run -P --wait -p LoadCredential=mullvad:/root/.secrets/mullvad docker compose up --remove-orphans
/usr/local/bin/p2p
and rundocker compose pull
to update the images.