← Back to Projects

RPi5 Home Server — Part 3: VPN, Remote Access & Private Downloads

Part 3 of the RPi5 home server series. Set up Gluetun as a Mullvad VPN gateway, route qBittorrent and MeTube through it with a kill switch, and install Tailscale for secure remote access behind CGNAT.

This is Part 3 of the Raspberry Pi 5 Home Server series. This part covers the privacy and remote access layer — a VPN gateway that protects download traffic, and a zero-config remote access solution that works behind CGNAT.


N
NOTE

This guide uses Mullvad as the VPN provider — it's what runs on this server and what every configuration here has been tested against. Gluetun supports many other providers including NordVPN, ExpressVPN, ProtonVPN, Surfshark, and more. The Docker Compose structure and kill switch behavior are identical regardless of provider — only the environment variables change. See the Gluetun wiki for your provider's specific configuration.

What We're Installing

ServicePurposePort
GluetunMullvad VPN gateway for containersInternal
qBittorrentTorrent client routed through Gluetun8090
MeTubeVideo downloader routed through Gluetun8081
TailscaleSecure remote access — bypasses CGNATNative

Understanding the Architecture

Before installing anything, it's worth understanding how these services relate to each other:

Internet
    |
    v
Mullvad VPN (via Gluetun)
    |
    +-- qBittorrent
    +-- MeTube
         |
         v
/mnt/data/storage/Downloads

Gluetun runs as a dedicated VPN client container. Instead of routing all Pi traffic through a VPN, Gluetun acts as a network gateway that only specific containers use. Everything else — Homepage, Filebrowser, Pi-hole — continues using your normal internet connection.

The kill switch — if the Mullvad connection drops, Gluetun immediately blocks all network traffic from containers using it. qBittorrent and MeTube cannot leak your real IP even during a VPN reconnect.

Tailscale is completely independent — it gives you remote access to your Pi from anywhere in the world, solving the CGNAT problem that prevents traditional port forwarding on mobile internet providers.


Gluetun — Mullvad VPN Gateway

1. Get your Mullvad WireGuard credentials

  1. Log into mullvad.net and go to Manage Account
  2. Navigate to WireGuard configuration
  3. Generate a new key pair — copy the Private Key
  4. Note the WireGuard address assigned to your key (looks like 10.x.x.x/32)

2. Create the directory structure

mkdir -p /mnt/data/docker-compose/appdata/gluetun
mkdir -p /mnt/data/storage/Downloads/torrents
mkdir -p /mnt/data/storage/Downloads/metube

3. Docker Compose configuration

Add this to your docker-compose.yml under services::

  gluetun:
    image: qmcgaw/gluetun:latest
    container_name: gluetun
    restart: unless-stopped
    cap_add:
      - NET_ADMIN
    devices:
      - /dev/net/tun:/dev/net/tun
    environment:
      - VPN_SERVICE_PROVIDER=mullvad
      - VPN_TYPE=wireguard
      - WIREGUARD_PRIVATE_KEY=your_mullvad_wireguard_private_key
      - WIREGUARD_ADDRESSES=10.x.x.x/32
      - SERVER_COUNTRIES=Netherlands
      - TZ=Etc/UTC
    volumes:
      - /mnt/data/docker-compose/appdata/gluetun:/gluetun
    ports:
      - "8090:8090"
      - "8081:8081"
W
WARN

Replace your_mullvad_wireguard_private_key with your actual private key and 10.x.x.x/32 with the address assigned to your key. Never share your private key or commit it to version control.

N
NOTE

SERVER_COUNTRIES=Netherlands sets the VPN exit location. Change this to any country Mullvad supports — Sweden, United States, Switzerland, etc. See the Gluetun wiki for supported values.

Why NET_ADMIN and /dev/net/tun? Gluetun creates a virtual TUN network interface to route traffic through the VPN tunnel. NET_ADMIN allows it to manage network interfaces and /dev/net/tun is the Linux kernel device it uses to create the tunnel. Both are required for VPN functionality.

Why are ports declared on Gluetun? Containers using network_mode: service:gluetun have no network of their own — they share Gluetun's entirely. All ports for those containers must be declared in the Gluetun block.

4. Verify Gluetun is working

Deploy Gluetun first before adding dependent containers:

cd /mnt/data/docker-compose
docker compose up -d gluetun

Check the logs to confirm the VPN connected:

docker compose logs gluetun

Look for:

Connected to Mullvad with WireGuard
Your IP is: x.x.x.x

If you see this, the VPN tunnel is up and you're ready to proceed.


qBittorrent — Torrent Client via VPN

1. Docker Compose configuration

Add this after the Gluetun block in docker-compose.yml:

  qbittorrent:
    image: lscr.io/linuxserver/qbittorrent:latest
    container_name: qbittorrent
    restart: unless-stopped
    network_mode: "service:gluetun"
    environment:
      - PUID=1000
      - PGID=1000
      - TZ=Etc/UTC
      - WEBUI_PORT=8090
    volumes:
      - /mnt/data/docker-compose/appdata/qbittorrent:/config
      - /mnt/data/storage/Downloads/torrents:/downloads
    depends_on:
      - gluetun
N
NOTE

network_mode: "service:gluetun" is the kill switch mechanism. qBittorrent shares Gluetun's network stack entirely — if Gluetun stops for any reason, qBittorrent immediately loses all network access. There is no fallback to your home IP.

Deploy:

cd /mnt/data/docker-compose
docker compose up -d gluetun qbittorrent

Access the qBittorrent web UI at http://192.168.1.150:8090

Default credentials: admin / adminadmin

W
WARN

Change the default password immediately. Go to Tools → Options → Web UI and set a strong password.

2. Verify the kill switch

Confirm qBittorrent's traffic goes through Mullvad:

docker exec -it qbittorrent curl ifconfig.me

The returned IP must be a Mullvad IP — not your home IP. If it shows your home IP, the VPN routing is not working. Check Gluetun logs.

3. Configure qBittorrent

  • Downloads path — Go to Tools → Options → Downloads and set the default save path to /downloads
  • Connection limits — Go to Tools → Options → Connection. A maximum of 200 connections and 50 per torrent is a sensible starting point
  • Speed limits — Go to Tools → Options → Speed and set upload limits appropriate for your connection

4. Homepage integration

- Tools:
    - qBittorrent:
        icon: qbittorrent.png
        href: http://192.168.1.150:8090
        description: Torrent Client (via Mullvad)
        widget:
          type: qbittorrent
          url: http://192.168.1.150:8090
          username: admin
          password: your_password

MeTube — Video Downloader via VPN

MeTube is a web interface for yt-dlp — the most capable video downloader available. It supports YouTube and hundreds of other platforms, downloading directly to your NVMe drive without involving your main computer.

Routing MeTube through Gluetun means all downloads go through Mullvad — your home IP is never exposed to video platforms or their CDN infrastructure.

1. Docker Compose configuration

Add this after the qBittorrent block in docker-compose.yml:

  metube:
    image: ghcr.io/alexta69/metube:latest
    container_name: metube
    restart: unless-stopped
    network_mode: "service:gluetun"
    volumes:
      - /mnt/data/storage/Downloads/metube:/downloads
    environment:
      - PUID=1000
      - PGID=1000
      - DELETE_FILE_ON_TRASHCAN=true
    depends_on:
      - gluetun

Deploy all three Gluetun-dependent containers together:

cd /mnt/data/docker-compose
docker compose up -d gluetun qbittorrent metube

Access MeTube at http://192.168.1.150:8081

2. Verify the VPN is active

docker exec -it metube wget -qO- ifconfig.me

The returned IP should be a Mullvad IP — not your home IP.

3. Using MeTube

Paste any video URL into the input field and click Add. MeTube queues the download and shows real-time progress.

Useful options:

  • Format — video+audio, audio only, or specific quality levels. Audio-only downloads as MP3 or M4A
  • Subtitles — optionally download and embed subtitles
  • Auto-delete — with DELETE_FILE_ON_TRASHCAN=true, trashing a completed download in the UI permanently deletes it from disk

4. Homepage integration

- Tools:
    - MeTube:
        icon: metube.png
        href: http://192.168.1.150:8081
        description: Video Downloader (via Mullvad)

Tailscale — Remote Access Behind CGNAT

CGNAT (Carrier-Grade NAT) is common with mobile internet providers like T-Mobile. It means your connection shares a public IP with many other customers — making traditional port forwarding impossible since you don't have a dedicated public IP.

Tailscale creates an encrypted mesh network between your devices using a relay infrastructure. Your Pi and your phone connect to each other through Tailscale's coordination servers without needing any inbound ports open on your router.

1. Install Tailscale natively

Tailscale is installed directly on the Pi — not as a Docker container. Native installation allows the Pi to act as a subnet router and exit node more reliably than the containerized version.

curl -fsSL https://tailscale.com/install.sh | sh

Authenticate:

sudo tailscale up

A login URL appears in the terminal. Copy it into your browser to link the Pi to your Tailscale account.

2. Verify the connection

tailscale status

Your Pi should appear as online with a Tailscale IP in the 100.x.x.x range.

3. Configure the admin console

Two settings in the Tailscale Admin Console are worth configuring immediately:

Disable key expiry — by default, Tailscale keys expire every 180 days. For a home server, click the three dots next to your Pi and select Disable key expiry so it never goes offline unexpectedly.

Enable MagicDNS — in the DNS tab, enable MagicDNS. This assigns your Pi a hostname on the Tailscale network so you can access it by name:

http://pi-server:3000    ← Homepage
http://pi-server:8080    ← Filebrowser
http://pi-server:5000    ← Kavita

4. Access your server remotely

  1. Install Tailscale on your phone, tablet, or laptop from tailscale.com/download
  2. Log in with the same account used on the Pi
  3. Access any service using the Pi's Tailscale IP (100.x.x.x) and the service port — from anywhere in the world
T
TIP

Tailscale only connects your enrolled devices to each other. Your other home devices remain invisible to the Tailscale network unless you specifically configure subnet routing. Your home network stays private.

5. Use the Pi as a VPN exit node (optional)

To route all traffic from your phone through your home connection when on public Wi-Fi:

sudo tailscale up --advertise-exit-node

Approve the exit node in the admin console, then enable it from the Tailscale app on your device.

N
NOTE

This is distinct from Gluetun/Mullvad. Gluetun routes specific containers through a commercial VPN provider. Tailscale exit node routes your device's traffic through your home internet connection. Both are useful — they serve different purposes.


Troubleshooting

Gluetun fails to connect

docker compose logs gluetun

Common causes:

  • Wrong private key — verify against your Mullvad account
  • Wrong WIREGUARD_ADDRESSES — must match the address assigned to your key
  • Server country unavailable — try a different SERVER_COUNTRIES value

qBittorrent or MeTube web UI is unreachable

Since both share Gluetun's network, if Gluetun is down neither is reachable. Always check Gluetun first:

docker compose logs gluetun
docker compose restart gluetun

qBittorrent or MeTube shows my real IP

Bring down all Gluetun-dependent containers and redeploy together:

docker compose down gluetun qbittorrent metube
docker compose up -d gluetun qbittorrent metube

MeTube download fails immediately

Pull a fresh image — MeTube updates frequently to keep pace with platform changes:

docker compose pull metube
docker compose up -d metube

Tailscale shows the Pi as offline

sudo systemctl status tailscaled
sudo systemctl restart tailscaled
sudo tailscale up

Can't reach Pi services via Tailscale

Confirm Tailscale is connected and note the IP:

tailscale status

Then verify your containers are running:

docker ps

Legal Notice

Gluetun, Mullvad, qBittorrent, MeTube, and Tailscale are legitimate tools with many lawful uses. This guide is provided for educational and personal use. You are responsible for ensuring your use complies with your local laws and the terms of service of any platforms you interact with.


Series Navigation