Skip to content

cyclopsgd/media-server-iac

Repository files navigation

media-server-iac

CI

Declarative deployment for a single-host media server: nine services in one Docker Compose file, with VPN-isolated downloads, pinned image versions, CI validation on every push, and automated update PRs via Renovate.

The entire stack is reproducible from this repository plus one .env file.

Topology

flowchart LR
    subgraph host["Docker host (Ubuntu 22.04)"]
        subgraph ms["mediastack network"]
            plex[Plex :32400]
            jellyseerr[Jellyseerr :5055]
            sonarr[Sonarr :8989]
            radarr[Radarr :7878]
            prowlarr[Prowlarr :9696]
            byparr[Byparr :8889]
            subgraph vpn["gluetun network namespace"]
                gluetun[Gluetun VPN]
                qbit[qBittorrent :8200]
            end
        end
        portainer[Portainer :9000]
    end
    jellyseerr -->|requests| sonarr & radarr
    prowlarr -->|indexers| sonarr & radarr
    prowlarr -->|CF solve| byparr
    sonarr & radarr -->|grabs| qbit
    qbit -.->|all traffic| gluetun
    gluetun ==>|WireGuard| internet((VPN provider))
    plex ---|library| media[(media drive)]
    qbit ---|downloads| media
Loading

qBittorrent has no network of its own. It runs inside Gluetun's network namespace (network_mode: service:gluetun), so if the VPN tunnel drops there is no route out: fail-closed by construction, not by firewall rule. Compose only starts it once Gluetun reports healthy.

Services

Service Image Role Port
Gluetun qmcgaw/gluetun WireGuard VPN client, egress for qBittorrent 8888 (proxy)
qBittorrent linuxserver/qbittorrent Downloads, VPN-isolated 8200
Prowlarr linuxserver/prowlarr Indexer management, syncs to Sonarr/Radarr 9696
Sonarr linuxserver/sonarr TV library automation 8989
Radarr linuxserver/radarr Film library automation 7878
Byparr thephaseless/byparr Cloudflare challenge solver for indexers 8889
Jellyseerr fallenbagel/jellyseerr Request front end 5055
Plex linuxserver/plex Media server, Intel iGPU transcoding 32400
Portainer portainer/portainer-ce Container management UI 9000

Quick start

git clone https://github.com/cyclopsgd/media-server-iac.git
cd media-server-iac
./scripts/bootstrap.sh   # first run creates .env and exits
nano .env                # VPN credentials, paths, LAN subnet
./scripts/bootstrap.sh   # validates, creates directories, deploys
make vpn-check           # confirm qBittorrent egress is the VPN IP

Day-to-day commands live in the Makefile (make help).

Automation

  • Pinned images. Every service is pinned to an exact version tag. Nothing changes on the host until a change is merged here.
  • Renovate raises a PR when a pinned image has a new release (configuration).
  • CI validates every push and PR: docker compose config against a generated env, yamllint, shellcheck, and gitleaks secret scanning (workflow).
  • Deploy is a manual, auditable step on the host: git pull && make update.

Repository layout

docker-compose.yaml     the whole stack
.env.example            every variable the stack consumes, documented
Makefile                operational entry points
scripts/bootstrap.sh    idempotent first-run setup
docs/architecture.md    design decisions and trade-offs
docs/runbook.md         operations, updates, migration notes

Documentation

Licence

MIT

About

Automated infrastructure-as-code deployment for a complete home media server stack with Plex, Sonarr, Radarr, Prowlarr, and qBittorrent. One-command setup with VPN protection and TRaSH Guide quality profiles.

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages