Skip to content

Latest commit

 

History

History
217 lines (145 loc) · 5.74 KB

File metadata and controls

217 lines (145 loc) · 5.74 KB

🏰 Proxmox Homelab Media Stack

Docker Traefik ProtonVPN Debian

A complete, production-ready Docker Compose stack designed specifically for Proxmox LXC. It features a VPN-gated torrent client, internal HTTPS via self-signed wildcard certificates, and the full media automation suite using Hardlinks for instant file moves.


🌟 Features

  • 🔒 VPN Kill-Switch: qBittorrent is routed through Gluetun. If the VPN tunnel drops, all traffic stops instantly.
  • 🏎️ Atomic Moves (Hardlinks): Media is not copied; it is hardlinked. A 50GB movie imports in 0.1 seconds and uses no extra storage.
  • 🛡️ Internal TLS: Traefik v3 handles HTTPS for all services using a generated local Wildcard Certificate.
  • 👻 LAN Only: No ports are exposed to the public internet. No Cloudflare Tunnels.
  • 📱 Jellyseerr: Integrated request management optimized for Jellyfin.

📐 Architecture

graph TD
    User((User Devices)) -->|HTTPS *.domain.com| Traefik
    Traefik -->|Internal Routing| Sonarr
    Traefik -->|Internal Routing| Radarr
    Traefik -->|Internal Routing| Jellyseerr
    Traefik -->|Internal Routing| Jellyfin
    Traefik -->|Internal Routing| qBittorrent

    subgraph VPN_Stack [VPN Namespace]
        Gluetun[Gluetun VPN] -->|WireGuard| Internet
        qBittorrent -->|Network: Service| Gluetun
    end

    subgraph Storage [Host Path /data]
        Torrents[(/torrents)]
        Media[(/media)]
    end

    qBittorrent -.->|Read/Write| Torrents
    Sonarr -.->|Hardlink| Media
    Radarr -.->|Hardlink| Media
    Jellyfin -.->|Read| Media

Loading

🛠️ Prerequisites

1. Proxmox LXC Configuration (Critical)

This stack requires specific permissions on the Proxmox Host to allow VPN tunneling and Docker nesting.

  1. Stop the container.
  2. On the Proxmox Host Shell, edit /etc/pve/lxc/YOUR-VM-ID.conf:
# Essential for Docker
features: nesting=1

# Essential for WireGuard/VPN (TUN Device)
lxc.cgroup2.devices.allow: c 10:200 rwm
lxc.mount.entry: /dev/net/tun dev/net/tun none bind,create=file

# Optional: GPU Passthrough (Intel QuickSync)
# lxc.cgroup2.devices.allow: c 226:* rwm
# lxc.mount.entry: /dev/dri/renderD128 dev/dri/renderD128 none bind,optional,create=file
  1. Start the container.

2. DNS Resolution

You must route your internal domain to the LXC IP (e.g., 192.168.1.100).

Option A: Cloudflare (Split Horizon)

  1. Create an A Record: media.yourdomain.com pointing to 192.168.1.100 (DNS Only / Gray Cloud).
  2. Create CNAME Records: sonarr, radarr, traefik, etc., pointing to media.yourdomain.com.

Option B: Local DNS (PiHole/AdGuard)

  1. Add a DNS rewrite: *.yourdomain.com -> 192.168.1.100.

🚀 Installation

1. Prepare Host Directories

Run these commands inside the LXC terminal:

# Create project structure
mkdir -p /opt/stack/traefik/certs
mkdir -p /opt/stack/traefik/config
mkdir -p /opt/stack/config

# Create data structure
mkdir -p /data/{torrents,media}/{tv,movies}

# Set permissions for PUID 1000 (Standard Docker User)
chown -R 1000:1000 /data
chmod -R 775 /data

2. Generate TLS Certificates

Generate a self-signed wildcard certificate for Traefik.

cd /opt/stack/traefik/certs
openssl req -x509 -nodes -days 3650 -newkey rsa:2048 \
  -keyout yourdomain.key \
  -out yourdomain.crt \
  -subj "/CN=*.yourdomain.com"

chmod 600 yourdomain.key

Note: Replace *.yourdomain.com with your actual domain.

3. Deploy the Stack

  1. Clone/Copy Files: Place docker-compose.yml and traefik/ configs in /opt/stack.
  2. Configure Environment:
cp .env.example .env
nano .env

Fill in your ProtonVPN Private Key and IP. 3. Start Services:

docker compose up -d

⚙️ Configuration Notes

Service URLs

Service URL Notes
Traefik https://traefik.domain.com Dashboard
Jellyseerr https://overseerr.domain.com Request Media
Jellyfin https://jellyfin.domain.com Media Player
Sonarr https://sonarr.domain.com TV Automation
Radarr https://radarr.domain.com Movie Automation
qBittorrent https://qbittorrent.domain.com VPN Download Client

Connecting Apps (Internal Networking)

Because qBittorrent runs inside the Gluetun network namespace, it does not have its own IP. When connecting Sonarr/Radarr to qBittorrent:

  • Host: gluetun (Do NOT use qbittorrent or localhost)
  • Port: 8080
  • No SSL

🧪 Verification

Verify VPN Kill-Switch

Ensure your real IP is not leaking.

  1. Check qBittorrent IP (Should be VPN):
docker exec -it qbittorrent curl ifconfig.me
  1. Check Sonarr IP (Should be LAN/Home):
docker exec -it sonarr curl ifconfig.me

Verify Hardware Transcoding (Optional)

If you enabled GPU passthrough:

docker exec -it jellyfin /usr/lib/jellyfin-ffmpeg/vainfo

📂 File Structure

/opt/stack/
├── .env                  # Secrets (Not in Git)
├── docker-compose.yml    # Main stack definition
├── traefik/
│   ├── certs/            # Stores .crt and .key
│   └── config/
│       ├── traefik.yml   # Static config
│       └── dynamic.yml   # TLS configuration
└── config/               # App configs (sonarr, radarr db, etc.)