My qBittorrent runs on TrueNAS at home, and for a long time every peer in every swarm could see my home IP address. I wanted that hidden, but I didn't want another monthly bill, and most of the VPN plans I looked at either didn't allow port forwarding or charged extra for it. Without an open port, torrents still work, but they connect to far fewer peers.
So I built my own. A free Oracle Cloud VM runs WireGuard, TrueNAS sends qBittorrent through it with Gluetun, and the torrent port is forwarded from the VM back to my NAS. It cost nothing, it has a kill switch, and I found a security hole in my old setup along the way. This is exactly what I did, including the parts I got wrong.
Quick answer
Create an Oracle Cloud Always Free VM, install WireGuard on it, open UDP 51820 and your torrent port in the Oracle Security List, and forward the torrent port to the WireGuard client with an iptables DNAT rule. On TrueNAS, run Gluetun as a custom WireGuard client and put qBittorrent inside it with network_mode: service:gluetun. That is your kill switch: if the tunnel drops, qBittorrent has no internet at all. Peers see the Oracle IP, never yours. The free AMD VM is limited to 50 Mbps, so it suits steady downloads, not maximum speed.
What this hides, and what it doesn't
Before building anything, I wanted to be clear about what a VPN I own actually changes. It's not the same as a commercial VPN where thousands of people share one address.
| Who | What they see after the change |
|---|---|
| Torrent peers and trackers | The Oracle VM's IP and an Oracle data centre location. Not my home IP. |
| My ISP | Encrypted WireGuard traffic to one Oracle address. Not what I'm downloading. |
| Oracle | Torrent traffic leaving their VM, and the account is in my name with my card on file. |
| Everything else on my network | Unchanged. Only qBittorrent goes through the tunnel. |
That third row matters. A self-hosted VPN hides your home address from strangers, but it doesn't make you anonymous. Any complaint about what leaves the VM goes to Oracle, and Oracle knows who you are. I use this for privacy from peers, and I only download things I'm allowed to download. A VPN changes the network path, not the law.
The setup at a glance
Torrent peers
|
v
Oracle VM 203.0.113.10 (WireGuard server 10.66.66.1,
| UDP 51820 tunnel port 51413 forwarded inside)
v
TrueNAS 192.168.0.50
Gluetun (WireGuard client 10.66.66.2, firewall = kill switch)
qBittorrent (shares Gluetun's network, web UI on :30024)
saves to /mnt/Pool/Jellyfin/JellyFin_Content
The addresses in this post are examples. Swap in your own.
| Part | What I used |
|---|---|
| VPN server | Oracle Always Free VM.Standard.E2.1.Micro, Ubuntu 24.04, India South (Hyderabad) |
| Tunnel | WireGuard, UDP 51820, with a preshared key |
| VPN client | Gluetun v3 as a TrueNAS SCALE custom app |
| Torrent client | qBittorrent 5.2.4 (home-operations image) |
| Torrent port | 51413 TCP and UDP, forwarded from the VM |
| Cost | Zero, as long as the Oracle account stays on Always Free |
Step 1: Get a free Oracle VM
I went with Oracle because its Always Free VMs don't expire after a year and come with a public IP and 10 TB of outbound data a month, which is plenty for torrent traffic. You sign up with a card for verification, but nothing is charged unless you upgrade the account to Pay As You Go. I never did, and you shouldn't either.
I first tried the Ampere A1 shape, because it's the generous one (2 OCPUs and 12 GB of memory on Always Free since Oracle cut the limits in 2026). Hyderabad replied with "Out of capacity for shape VM.Standard.A1.Flex". That's common, so I took the AMD one instead.
| Setting | What I picked |
|---|---|
| Image | Canonical Ubuntu 24.04 |
| Shape | VM.Standard.E2.1.Micro (1/8 OCPU, 1 GB RAM), marked "Always Free eligible" |
| Network | Public subnet, assign a public IPv4 address |
| SSH key | Let Oracle generate it and download the private key |
One gigabyte of memory is tight for Ubuntu updates, so the first thing I did after logging in was add a 1 GB swap file. WireGuard itself uses almost nothing.
Know the limit before you start: Oracle's Always Free resource page says this shape gets up to 50 Mbps to the internet. That's about 6 MB/s. The data allowance is generous, but the speed cap is real. If you manage to get an A1 VM, use that instead.
Step 2: Open the ports in Oracle (and my first mistake)
Oracle has its own firewall in front of the VM, called a Security List, under Networking > Virtual Cloud Networks > your VCN > Security. I added three ingress rules from 0.0.0.0/0:
- UDP 51820, for WireGuard
- TCP 51413, for incoming torrent peers
- UDP 51413, for incoming torrent peers and DHT
Then the VM couldn't reach the internet at all. apt update just hung. My VCN was an old one from 2025, and its only egress rule was set to Stateless. With a stateless rule, the replies coming back aren't allowed in unless you write a matching ingress rule too. I edited the egress rule (0.0.0.0/0, all protocols) and unticked Stateless. Everything worked straight away.
Step 3: WireGuard on the VM
Install it and generate keys for the server and for one client (the NAS):
sudo apt update && sudo apt install -y wireguard
cd /etc/wireguard && sudo -s
umask 077
wg genkey | tee server.key | wg pubkey > server.pub
wg genkey | tee client.key | wg pubkey > client.pub
wg genpsk > client.psk
Here's the trap that cost me time. Oracle's Ubuntu image ships with iptables rules that REJECT everything in INPUT and FORWARD that isn't SSH. If you add your ACCEPT rules with -A, they land after the REJECT and never match. They have to go in at the top with -I. My /etc/wireguard/wg0.conf, with the network card called ens3:
[Interface]
Address = 10.66.66.1/24
ListenPort = 51820
PrivateKey = <contents of server.key>
PostUp = iptables -I INPUT 1 -p udp --dport 51820 -j ACCEPT
PostUp = iptables -I FORWARD 1 -i wg0 -j ACCEPT
PostUp = iptables -I FORWARD 1 -o wg0 -m state --state RELATED,ESTABLISHED -j ACCEPT
PostUp = iptables -I FORWARD 1 -i ens3 -o wg0 -p tcp --dport 51413 -j ACCEPT
PostUp = iptables -I FORWARD 1 -i ens3 -o wg0 -p udp --dport 51413 -j ACCEPT
PostUp = iptables -t nat -A POSTROUTING -s 10.66.66.0/24 -o ens3 -j MASQUERADE
PostUp = iptables -t nat -A PREROUTING -i ens3 -p tcp --dport 51413 -j DNAT --to-destination 10.66.66.2
PostUp = iptables -t nat -A PREROUTING -i ens3 -p udp --dport 51413 -j DNAT --to-destination 10.66.66.2
# PostDown: the same lines with -D instead of -I / -A
[Peer]
# TrueNAS (Gluetun)
PublicKey = <contents of client.pub>
PresharedKey = <contents of client.psk>
AllowedIPs = 10.66.66.2/32
The two DNAT lines are the port forwarding. Anything that hits the VM on 51413 is passed down the tunnel to the NAS. Turn on IP forwarding and start it:
echo 'net.ipv4.ip_forward=1' | sudo tee /etc/sysctl.d/99-wireguard.conf
sudo sysctl --system
sudo systemctl enable --now wg-quick@wg0
sudo wg show
Step 4: Test it on a spare port first
My real qBittorrent already had settings, categories for Radarr and Sonarr, and a save path into the Jellyfin library. I didn't want to break any of that on a first attempt. So I installed a throwaway copy on port 30025 with a fresh config, checked the tunnel there, and only then switched the real one. That turned out to be the most useful decision of the whole project, because the test copy is where I found every problem.
Step 5: Gluetun and qBittorrent on TrueNAS
On TrueNAS SCALE I used Apps > Discover Apps > Custom App > Install via YAML. Gluetun connects to the VM, and qBittorrent borrows Gluetun's network instead of having its own. The keys go in as placeholders here. Never post your real ones.
services:
gluetun:
image: qmcgaw/gluetun:v3
cap_add: [NET_ADMIN]
devices: ["/dev/net/tun:/dev/net/tun"]
ports: ["30024:30024"]
environment:
- VPN_SERVICE_PROVIDER=custom
- VPN_TYPE=wireguard
- WIREGUARD_ENDPOINT_IP=203.0.113.10
- WIREGUARD_ENDPOINT_PORT=51820
- WIREGUARD_PUBLIC_KEY=<server.pub>
- WIREGUARD_PRIVATE_KEY=<client.key>
- WIREGUARD_PRESHARED_KEY=<client.psk>
- WIREGUARD_ADDRESSES=10.66.66.2/32
- FIREWALL_VPN_INPUT_PORTS=51413
- FIREWALL_OUTBOUND_SUBNETS=192.168.0.0/24
restart: unless-stopped
qbittorrent:
image: ghcr.io/home-operations/qbittorrent:5.2.4
user: "568:568"
network_mode: "service:gluetun"
depends_on:
gluetun:
condition: service_healthy
environment:
- QBT_WEBUI_PORT=30024
- QBT_TORRENTING_PORT=51413
volumes:
- /mnt/.ix-apps/app_mounts/qbittorrent/config:/config
- /mnt/Pool/Jellyfin/JellyFin_Content:/mnt/Pool/Jellyfin/JellyFin_Content
restart: unless-stopped
A few lines worth explaining:
- The web UI port lives on Gluetun, not qBittorrent, because qBittorrent has no network of its own any more.
- FIREWALL_VPN_INPUT_PORTS lets the forwarded torrent port in through Gluetun's firewall. Without it, the port forward on the VM goes nowhere.
- FIREWALL_OUTBOUND_SUBNETS lets my LAN reach the web UI, and lets Radarr and Sonarr talk to qBittorrent.
- The config volume points at the folder the old TrueNAS qBittorrent app was using, so the new one starts with all my old settings.
- The download folder is mounted at the same path inside and outside. That's so the save path qBittorrent reports matches what Radarr, Sonarr and Jellyfin see.
On the test copy I left that last mount out, and my test download landed in /config/Downloads instead of the Jellyfin folder. qBittorrent can only save to folders the container can see. If a path isn't mounted, it quietly falls back to its default.
Step 6: The kill switch, and how I tested it
With network_mode: service:gluetun, qBittorrent has no route to the internet except through Gluetun. Gluetun's firewall only allows traffic through the tunnel. So if WireGuard drops, qBittorrent doesn't fall back to my home connection. It just goes quiet. No extra kill switch app needed.
I didn't want to take that on trust. The TrueNAS app shell wouldn't let me run commands in the container, so I tested from the other end and shut the tunnel down on the VM:
sudo wg-quick down wg0
# wait a couple of minutes, watch qBittorrent
sudo wg-quick up wg0
While the tunnel was down, the DHT node count in qBittorrent's status bar fell from 51 to 42 to 33, and no new connections came in. At no point did the external IP change to my home address. When I brought the tunnel back up, Gluetun reconnected on its own and the numbers climbed again.
Step 7: Check what peers really see
The simplest test is the torrent check on ipleak.net. It gives you a magnet link, you add it to qBittorrent, and the page shows the IP address your client reports to the tracker.
My first result showed my home IP, and for a minute I thought the whole thing had failed. Then I noticed I'd added the magnet to the old qBittorrent on 30024, which wasn't on the VPN yet. On the test copy it showed the Oracle address. After the switch, the real one on 30024 shows the Oracle address too. Check which tab you're in before you panic.
The forwarded port is easy to check as well. In qBittorrent, the connection icon at the bottom turns green when incoming connections work, and any online port checker pointed at the VM's IP on 51413 should say open.
The security hole I found on the way
My qBittorrent web UI is also published through a Cloudflare Tunnel so I can reach it from my phone. While checking settings, I found that the old app had "Bypass authentication for clients in whitelisted IP subnets" turned on with 172.16.0.0/12 in the list.
That range is Docker's internal network. The cloudflared container lives on it too. So every request coming in from the public internet through Cloudflare looked like a trusted local client, and the web UI opened without asking for a password. Anyone who found the address could have added torrents, changed the save path or read my settings.
The fix was to change the whitelist to only my LAN, 192.168.0.0/24. Now the public address returns 403 until you log in, and nothing changes at home. If you run any web app behind Cloudflare Tunnel, check its "trusted network" settings for Docker ranges. It's an easy mistake, and I had no idea mine was open until I looked.
How to roll it back
I kept the old TrueNAS qBittorrent app installed but stopped, so going back takes a minute:
- In TrueNAS Apps, stop the new Gluetun app.
- Start the old qBittorrent app. It uses the same config folder, so your torrents and settings are still there.
- On the VM,
sudo systemctl disable --now wg-quick@wg0if you want the tunnel gone completely.
Remember that after rolling back, peers see your home IP again. Once you're happy with the new setup for a week or so, delete the old app so nobody starts it by mistake.
A few things I learned
- Radarr and Sonarr may need the password now. They used to slip through the Docker whitelist. After the fix, open Settings > Download Clients > qBittorrent, press Test, and add the username and password if it fails.
- Keep the VM busy. Oracle can reclaim an Always Free VM if CPU and network both stay under 20% for seven days. A VM that's carrying torrent traffic most days is unlikely to hit that, but an unused one will.
- 50 Mbps is the ceiling on the AMD VM. My qBittorrent limit was set higher than the tunnel can carry, so it never mattered. If you need more, keep trying for an A1 VM.
- Back up the WireGuard keys. I saved the client config on my Mac. If the VM is ever reclaimed, a new one with the same keys means only the endpoint IP changes in the TrueNAS YAML.
- The YAML editor in TrueNAS auto-indents. Typing YAML into it line by line mangled the spacing. Pasting the whole file in one go worked.
If you want the bigger picture with Sonarr, Radarr, Prowlarr and Jellyfin all behind Gluetun, I wrote that up in my VPN-isolated media stack on TrueNAS SCALE. This post is the free, self-hosted version of the VPN part. The rest of my setup lives in my TrueNAS home server notes and Homelab Intelligence. And if you'd rather have someone build this for you, or look over your home or office network, that's what my network services are for.
Frequently asked questions
Is Oracle Cloud Always Free really free after one year?
Yes, the Always Free resources don't expire. The 30 day trial credit ends, but VMs marked "Always Free eligible" keep running at no cost as long as you don't upgrade the account to Pay As You Go. Oracle can reclaim a VM that sits idle for seven days.
Does a self-hosted VPN hide my IP from torrent peers?
Yes. Peers and trackers see the VPN server's IP instead of your home IP, and your ISP only sees encrypted traffic to that server. It isn't anonymous, though. The cloud provider knows the account is yours, and complaints about the server's traffic go to them.
Do I need a separate kill switch with Gluetun?
No. When qBittorrent uses network_mode: service:gluetun, its only way out is Gluetun's tunnel, and Gluetun's firewall blocks everything else. If the VPN drops, qBittorrent loses its connection instead of falling back to your home internet.
How do I forward a torrent port through my own WireGuard VPN?
Open the port in the cloud firewall, then add an iptables DNAT rule on the VPN server that sends that port to the client's tunnel address, plus a FORWARD accept rule. In Gluetun, list the same port in FIREWALL_VPN_INPUT_PORTS and set it as qBittorrent's listening port.
How fast is the free Oracle VM as a VPN?
The free AMD VM.Standard.E2.1.Micro is limited to 50 Mbps to the internet, about 6 MB/s. That's fine for steady downloads but not for maximum speed. The free Ampere A1 shape is much faster, but it's often out of capacity in busy regions.
