Transmission Over VPN
Streaming services have become more and more annoying to deal with over the years. Trying to find a particular movie and realizing you either need to watch ads or pay even more money to rent the movie on a platform you already pay for has become the norm. As a result, more and more people have switched back to torrenting as opposed to paying multiple subscriptions for all the various streaming services.
I personally haven’t torrented anything since I was 16 years old. Why? Because up until then, streaming services provided everything I needed. Now, all the wannabe-FAANG companies have spun up their own lesser and more expensive versions of a failing streaming platform. Content that used to be available entirely in one place is now fragmented across many greedy domains. The custody battles over our favorite TV shows and movies has turned streaming into an unaffordable nuisance.
At first I didn’t want to bother setting up a Plex Media server in my homelab. Afterall, I work in tech and make plenty of money to afford a subscription to as many media services as I’d like. As time went on however, I got bored and craved a new project. Eventually, I caved and decided I’d finally deploy Plex along with all the other microservices I’d need to torrent effectively.
Back in my early days of torrenting, I didn’t have a dedicated computer or even my own PC. I only had the shared family computer. I rememebr my dad receiving letters in the mail from our ISP notifying us that they caught us downloading movies illegaly. My dad, nostrils flaring at the sight of defiance, demanded I stop at once. The idea of cheating a defenseless company like Paramount was unspeakable. Which is why I’m writing about it instead.
Over the last 5 or 10 years, VPN providers have become pretty mainstream. I never felt that I actually required one. Now with torrenting I felt I had an appropriate reason to choose one. I won’t bother mentioning the name of my VPN provider, I’m sure they appreciate the discretion.
One quiet evening I was bored enough to confiugre all the media services I’d need on my homelab. I really wanted to check out this movie, “Edge of Tomorrow” that my friendly neighborhood drug dealer Bob Calloway kept going on about. I’m pretty sure he’d already spoiled the ending but I’m a sucker for SciFi.
Wireguard
Wireguard is a open source communication protocol that we can use to setup a VPN. There were a few ways I could setup Wireguard. My homelab is a baremetal Kubernetes cluster which means each node in the cluster is an actual server, not a VM. There were three main options I could choose to deploy Wireguard:
- Deploy Wireguard as a systemd service on the node
- Deploy Wireguard as a Kubernetes service
- Deploy Wireguard as a Pod sidecar
I went with option 3 as right now, the only thing needing to use Wireguard is my torrenting client, Transmission. In addition, if any services needed a VPN tunnel in the future they could also easily deploy this sidecar with minimal configuration.
My deployment was simple:
- Wireguard runs as a sidecar and establishes a VPN Connection
- Transmission downloads and seeds torrents through the VPN tunnel
My VPN provider was kind enough to provide an easy way to generate wireguard configurations. My wireguard config looks something like this:
|
|
I then convert this to a Kubernetes configmap by running:
|
|
Wireguard requires special permissions in order to tunnel traffic. I highlighted these permissions below:
|
|
The entire deployment looks something like this (I’ll include a Github gist at the very bottom of this post):
|
|
To verify this works as expected we can apply the deployment file and test
our VPN connection by running curl http://ip.me
|
|
Everything seemed to work as expected…or so I thought. Torrenting traffic was going through the VPN tunnel. However, after a few hours I noticed that none of my torrents were seeding properly. Transmission also reported that the port I was using was closed. After more digging I realized that although my Wireguard configuration allowed port-forwarding, that didn’t mean it did the leg work to setup port-forwarding for me. In order to seed my torrents properly, I’d need to setup something called NAT-PMP.
Port-forwarding with NAT PMP
NAT Port Mapping Protocol (NAT PMP), is a network protocol that allows us to establish port-forwarding configurations. You can read the full paper here if that’s the kind of person you are: https://datatracker.ietf.org/doc/html/rfc6886
Having realized that I needed my transmission image to include additional binaries I feared that I would need to setup a private docker repository in order to deploy my own modified version of transmission. While this is something I plan on doing in the future, for the purpose of this project I was less enthused.
I figured there must have been plenty of people with a similar dilemma and after searching Github I came across this issue: https://github.com/linuxserver/docker-transmission/issues/248
It turns out that the linuxserver org has a universal package install repo: https://github.com/linuxserver/docker-mods/tree/universal-package-install
This allows someone to modify the image with additional packages, binaries, etc. at runtime. Someone had already gone ahead and setup a docker mod to support NAT-PMP and all you had to do was add an environmental variable to your deployment. Things are never this easy!

My transmission deployment was modified to include the new environment variable:
|
|
Before blindly running arbitrary code, let’s at least see what this docker mod is actually doing.
https://github.com/jordanpotter/transmission-nat-pmp/blob/main/main.go#L44-L66
|
|
At a glance, this code is doing two things:
- Establishe a port through NAT PMP
- Update Transmission to use that port through a Transmission RPC package
Ports through NAT-PMP have a timeout. Having Transmission automatically reconfigured everytime a new port is established is a huge quality-of-life feature for us.
Verification
I redeployed Tranmissions with the newly added environment variable and checked to see that our VPN was still properly setup.
|
|
I then checked the logs to see that the docker mod was running correctly and that a port was now being forwarded.
|
|
I then curl'd canyouseeme.org to see if this port was visible from the outside world:
|
|
The Transmission service also reported that the port was open.

All checks looked promising, and after a few hours I could see that some torrents were seeding now.
Security
While convenient, this solution has several security considerations. Wireguard is running as a privileged sidecar with special permissions. We are installing a docker mod that has the ability to install arbitrary code onto a pod with elevated access to the host system. The potential for a malicious attack involving privilege escalation is pretty high. Long-term a better, albiet less convenient, solution should be used instead.
In a future post I plan to revisit setting up NAT-PMP and explore possible ways an attacker could exploit a pod with these privileges.