Skip to main content
COSMICBYTEZLABS
NewsSecurityHOWTOsToolsStudyTraining
ProjectsChecklistsAI RankingsNewsletterStatusTagsAbout
Subscribe

Press Enter to search or Esc to close

News
Security
HOWTOs
Tools
Study
Training
Projects
Checklists
AI Rankings
Newsletter
Status
Tags
About
RSS Feed
Reading List
Subscribe

Stay in the Loop

Get the latest security alerts, tutorials, and tech insights delivered to your inbox.

Subscribe NowFree forever. No spam.
COSMICBYTEZLABS

Your trusted source for IT intelligence, cybersecurity insights, and hands-on technical guides.

429+ Articles
114+ Guides

CONTENT

  • Latest News
  • Security Alerts
  • HOWTOs
  • Projects
  • Exam Prep

RESOURCES

  • Search
  • Browse Tags
  • Newsletter Archive
  • Reading List
  • RSS Feed

COMPANY

  • About Us
  • Contact
  • Privacy Policy
  • Terms of Service

© 2026 CosmicBytez Labs. All rights reserved.

System Status: Operational
  1. Home
  2. Projects
  3. Homelab Media Server with Full ARR Stack
Homelab Media Server with Full ARR Stack
PROJECTAdvanced

Homelab Media Server with Full ARR Stack

Deploy a complete self-hosted media automation system with Plex, Sonarr, Radarr, Prowlarr, and more. Includes Traefik reverse proxy, Authentik SSO, and...

Dylan H.

Infrastructure Engineering

February 3, 2026
7 min read
6-8 hours

Overview

This project guides you through deploying a complete, production-grade media automation system using Docker Compose. By the end, you'll have automated TV show downloads, movie management, subtitle fetching, and a beautiful dashboard - all protected by SSO and reverse proxy.

What We're Building

┌───────────────────────────────────────────────────────────────────────┐
│                        HOMELAB MEDIA SERVER                           │
├───────────────────────────────────────────────────────────────────────┤
│                                                                       │
│   Internet ──► CloudFlare ──► Traefik ──► Services                    │
│                                   │                                   │
│                              Authentik (SSO)                          │
│                                                                       │
├───────────────────────────────────────────────────────────────────────┤
│  MEDIA AUTOMATION        │  CONSUMPTION       │  MONITORING          │
│  ────────────────        │  ───────────       │  ──────────          │
│  • Sonarr (TV)           │  • Plex            │  • Prometheus        │
│  • Radarr (Movies)       │  • AudioBookshelf  │  • Grafana           │
│  • Lidarr (Music)        │  • Calibre-Web     │  • Uptime Kuma       │
│  • Prowlarr (Indexers)   │  • Komga (Comics)  │  • Tautulli          │
│  • Bazarr (Subtitles)    │                    │                      │
│  • Overseerr (Requests)  │                    │                      │
└───────────────────────────────────────────────────────────────────────┘

Prerequisites

Before starting, you should be familiar with:

  • Docker Security Fundamentals - Container basics
  • Building a Secure Homelab - Network architecture
  • Basic Linux command line

Hardware Requirements

ComponentMinimumRecommended
CPU4 cores8+ cores
RAM16GB32GB+
Storage500GB SSD + HDD arrayNVMe + multiple HDDs
Network1Gbps2.5Gbps+

Architecture

Stack Composition

We deploy four independent stacks that can be managed separately:

# compose.yml - Master orchestration
include:
  - stack-core-infra.yml      # Traefik, Authentik, Homepage
  - stack-arr.yml             # Media automation
  - stack-media-books.yml     # Consumption services
  - stack-monitoring.yml      # Observability

Network Architecture

                    Public Internet
                          │
              ┌───────────▼───────────┐
              │   CloudFlare DNS      │
              │   *.yourdomain.com    │
              └───────────┬───────────┘
                          │
              ┌───────────▼───────────┐
              │   Traefik (Proxy)     │
              │   :80, :443           │
              └───────────┬───────────┘
                          │
              ┌───────────▼───────────┐
              │   Docker: proxy       │
              └─┬─────────────────────┘
                │
    ┌───────────┼───────────┬──────────────┐
    ▼           ▼           ▼              ▼
 Authentik   *arr Stack   Media Apps   Monitoring

Directory Structure

Create the base directory structure:

sudo mkdir -p /srv/docker-stack/{traefik,authentik,sonarr,radarr}
sudo mkdir -p /srv/docker-stack/{lidarr,bazarr,prowlarr,overseerr}
sudo mkdir -p /srv/docker-stack/{grafana,prometheus,loki,homepage}
sudo mkdir -p /mnt/dockerdata/{media,torrents}
sudo mkdir -p /mnt/dockerdata/media/{tv,movies,music,audiobooks}
 
# Set ownership
sudo chown -R 1000:1000 /srv/docker-stack
sudo chown -R 1000:1000 /mnt/dockerdata

Volume Mapping Pattern

All services follow a consistent pattern:

volumes:
  - /srv/docker-stack/<service>/config:/config  # Service config
  - /mnt/dockerdata/media:/mnt/media            # Media library
  - /mnt/dockerdata/torrents:/mnt/torrents      # Downloads

Step 1: Core Infrastructure

Create Docker Networks

docker network create proxy
docker network create monitoring

Traefik Configuration

File: /srv/docker-stack/traefik/traefik.yml

api:
  dashboard: true
  insecure: false
 
entryPoints:
  web:
    address: ":80"
    http:
      redirections:
        entryPoint:
          to: websecure
          scheme: https
  websecure:
    address: ":443"
 
providers:
  docker:
    endpoint: "unix:///var/run/docker.sock"
    exposedByDefault: false
    network: proxy
  file:
    directory: /etc/traefik/dynamic
    watch: true
 
certificatesResolvers:
  cloudflare:
    acme:
      email: your-email@example.com
      storage: /acme.json
      dnsChallenge:
        provider: cloudflare
        resolvers:
          - "1.1.1.1:53"
          - "8.8.8.8:53"

Core Infrastructure Stack

File: /srv/docker-stack/stack-core-infra.yml

services:
  traefik:
    image: traefik:latest
    container_name: traefik
    restart: unless-stopped
    security_opt:
      - no-new-privileges:true
    ports:
      - 80:80
      - 443:443
    environment:
      - CF_DNS_API_TOKEN=${CF_DNS_API_TOKEN}
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - /srv/docker-stack/traefik/traefik.yml:/traefik.yml:ro
      - /srv/docker-stack/traefik/acme.json:/acme.json
      - /srv/docker-stack/traefik/dynamic:/etc/traefik/dynamic:ro
    networks:
      - proxy
    labels:
      - traefik.enable=true
      - traefik.http.routers.traefik.rule=Host(`traefik.yourdomain.com`)
      - traefik.http.routers.traefik.entrypoints=websecure
      - traefik.http.routers.traefik.tls.certresolver=cloudflare
      - traefik.http.routers.traefik.service=api@internal
    deploy:
      resources:
        limits:
          memory: 512M
 
  homepage:
    image: ghcr.io/gethomepage/homepage:latest
    container_name: homepage
    restart: unless-stopped
    environment:
      - PUID=1000
      - PGID=1000
    volumes:
      - /srv/docker-stack/homepage/config:/app/config
      - /var/run/docker.sock:/var/run/docker.sock:ro
    networks:
      - proxy
    labels:
      - traefik.enable=true
      - traefik.http.routers.homepage.rule=Host(`home.yourdomain.com`)
      - traefik.http.routers.homepage.entrypoints=websecure
      - traefik.http.routers.homepage.tls.certresolver=cloudflare
      - traefik.http.services.homepage.loadbalancer.server.port=3000
 
networks:
  proxy:
    external: true

Deploy Core Infrastructure

cd /srv/docker-stack
docker compose -f stack-core-infra.yml up -d
 
# Verify services
docker compose -f stack-core-infra.yml ps

Step 2: Media Automation Stack

Environment Configuration

File: /srv/docker-stack/.env

PUID=1000
PGID=1000
TZ=America/Edmonton
CF_DNS_API_TOKEN=your-cloudflare-token

ARR Stack Deployment

File: /srv/docker-stack/stack-arr.yml

services:
  sonarr:
    image: lscr.io/linuxserver/sonarr:latest
    container_name: sonarr
    restart: unless-stopped
    security_opt:
      - no-new-privileges:true
    environment:
      - PUID=${PUID}
      - PGID=${PGID}
      - TZ=${TZ}
    volumes:
      - /srv/docker-stack/sonarr/config:/config
      - /mnt/dockerdata/media:/mnt/media
      - /mnt/dockerdata/torrents:/mnt/torrents
    networks:
      - proxy
    labels:
      - traefik.enable=true
      - traefik.http.routers.sonarr.rule=Host(`sonarr.yourdomain.com`)
      - traefik.http.routers.sonarr.entrypoints=websecure
      - traefik.http.routers.sonarr.tls.certresolver=cloudflare
      - traefik.http.services.sonarr.loadbalancer.server.port=8989
      - homepage.group=Media Automation
      - homepage.name=Sonarr
      - homepage.icon=sonarr
      - homepage.href=https://sonarr.yourdomain.com
    deploy:
      resources:
        limits:
          memory: 512M
 
  radarr:
    image: lscr.io/linuxserver/radarr:latest
    container_name: radarr
    restart: unless-stopped
    security_opt:
      - no-new-privileges:true
    environment:
      - PUID=${PUID}
      - PGID=${PGID}
      - TZ=${TZ}
    volumes:
      - /srv/docker-stack/radarr/config:/config
      - /mnt/dockerdata/media:/mnt/media
      - /mnt/dockerdata/torrents:/mnt/torrents
    networks:
      - proxy
    labels:
      - traefik.enable=true
      - traefik.http.routers.radarr.rule=Host(`radarr.yourdomain.com`)
      - traefik.http.routers.radarr.entrypoints=websecure
      - traefik.http.routers.radarr.tls.certresolver=cloudflare
      - traefik.http.services.radarr.loadbalancer.server.port=7878
      - homepage.group=Media Automation
      - homepage.name=Radarr
      - homepage.icon=radarr
    deploy:
      resources:
        limits:
          memory: 512M
 
  prowlarr:
    image: lscr.io/linuxserver/prowlarr:latest
    container_name: prowlarr
    restart: unless-stopped
    security_opt:
      - no-new-privileges:true
    environment:
      - PUID=${PUID}
      - PGID=${PGID}
      - TZ=${TZ}
    volumes:
      - /srv/docker-stack/prowlarr/config:/config
    networks:
      - proxy
    labels:
      - traefik.enable=true
      - traefik.http.routers.prowlarr.rule=Host(`prowlarr.yourdomain.com`)
      - traefik.http.routers.prowlarr.entrypoints=websecure
      - traefik.http.routers.prowlarr.tls.certresolver=cloudflare
      - traefik.http.services.prowlarr.loadbalancer.server.port=9696
      - homepage.group=Media Automation
      - homepage.name=Prowlarr
      - homepage.icon=prowlarr
    deploy:
      resources:
        limits:
          memory: 256M
 
  bazarr:
    image: lscr.io/linuxserver/bazarr:latest
    container_name: bazarr
    restart: unless-stopped
    security_opt:
      - no-new-privileges:true
    environment:
      - PUID=${PUID}
      - PGID=${PGID}
      - TZ=${TZ}
    volumes:
      - /srv/docker-stack/bazarr/config:/config
      - /mnt/dockerdata/media:/mnt/media
    networks:
      - proxy
    labels:
      - traefik.enable=true
      - traefik.http.routers.bazarr.rule=Host(`bazarr.yourdomain.com`)
      - traefik.http.routers.bazarr.entrypoints=websecure
      - traefik.http.routers.bazarr.tls.certresolver=cloudflare
      - traefik.http.services.bazarr.loadbalancer.server.port=6767
      - homepage.group=Media Automation
      - homepage.name=Bazarr
      - homepage.icon=bazarr
    deploy:
      resources:
        limits:
          memory: 256M
 
  overseerr:
    image: sctx/overseerr:latest
    container_name: overseerr
    restart: unless-stopped
    security_opt:
      - no-new-privileges:true
    environment:
      - TZ=${TZ}
    volumes:
      - /srv/docker-stack/overseerr/config:/app/config
    networks:
      - proxy
    labels:
      - traefik.enable=true
      - traefik.http.routers.overseerr.rule=Host(`requests.yourdomain.com`)
      - traefik.http.routers.overseerr.entrypoints=websecure
      - traefik.http.routers.overseerr.tls.certresolver=cloudflare
      - traefik.http.services.overseerr.loadbalancer.server.port=5055
      - homepage.group=Media
      - homepage.name=Overseerr
      - homepage.icon=overseerr
    deploy:
      resources:
        limits:
          memory: 512M
 
networks:
  proxy:
    external: true

Deploy ARR Stack

docker compose -f stack-arr.yml up -d

Step 3: Initial Configuration

Prowlarr Setup (Do First)

  1. Access https://prowlarr.yourdomain.com
  2. Set authentication (Settings → General → Authentication)
  3. Add indexers (Indexers → Add Indexer)
  4. Configure Apps to sync with Sonarr/Radarr

Sonarr Configuration

  1. Access https://sonarr.yourdomain.com
  2. Add root folder: /mnt/media/tv
  3. Configure download client
  4. Add quality profiles
  5. Import existing library or add series

Radarr Configuration

  1. Access https://radarr.yourdomain.com
  2. Add root folder: /mnt/media/movies
  3. Configure download client
  4. Set up quality profiles
  5. Add movies or import library

Bazarr Subtitle Setup

  1. Access https://bazarr.yourdomain.com
  2. Connect to Sonarr and Radarr
  3. Add subtitle providers (OpenSubtitles, etc.)
  4. Configure languages

Step 4: Monitoring Stack

See Network Monitoring Basics for detailed Prometheus/Grafana setup.

Quick deployment:

# stack-monitoring.yml (simplified)
services:
  prometheus:
    image: prom/prometheus:latest
    container_name: prometheus
    volumes:
      - /srv/docker-stack/prometheus/config:/etc/prometheus
      - /srv/docker-stack/prometheus/data:/prometheus
    networks:
      - proxy
      - monitoring
 
  grafana:
    image: grafana/grafana:latest
    container_name: grafana
    environment:
      - GF_SECURITY_ADMIN_PASSWORD=${GRAFANA_PASSWORD}
    volumes:
      - /srv/docker-stack/grafana/data:/var/lib/grafana
    networks:
      - proxy
      - monitoring
    labels:
      - traefik.enable=true
      - traefik.http.routers.grafana.rule=Host(`grafana.yourdomain.com`)
 
  uptime-kuma:
    image: louislam/uptime-kuma:latest
    container_name: uptime-kuma
    volumes:
      - /srv/docker-stack/uptime-kuma:/app/data
    networks:
      - proxy
    labels:
      - traefik.enable=true
      - traefik.http.routers.uptime.rule=Host(`uptime.yourdomain.com`)
 
networks:
  proxy:
    external: true
  monitoring:
    driver: bridge

Security Considerations

Authentication Options

  1. Authentik SSO - Enterprise-grade, supports SAML/OIDC
  2. Authelia - Lighter alternative
  3. App-native auth - Each app's built-in authentication

Network Isolation

# Add to services that shouldn't be public
networks:
  - internal  # No traefik access
 
networks:
  internal:
    internal: true  # No external access

Secrets Management

Never commit secrets to git:

# .gitignore
.env
*/config/
acme.json
*_token.txt

Maintenance

Update All Containers

#!/bin/bash
# /srv/docker-stack/update.sh
 
cd /srv/docker-stack
 
for stack in stack-*.yml; do
  echo "Updating $stack..."
  docker compose -f "$stack" pull
  docker compose -f "$stack" up -d
done
 
# Cleanup old images
docker image prune -f

Backup Strategy

# Backup configs (exclude media)
tar -czvf homelab-backup-$(date +%Y%m%d).tar.gz \
  --exclude='*/cache/*' \
  --exclude='*/logs/*' \
  /srv/docker-stack/

Related Guides

For detailed setup of individual components:

  • Docker Security Fundamentals - Container hardening
  • Building a Secure Homelab - Network architecture
  • Network Monitoring Basics - Prometheus/Grafana setup

Troubleshooting

Container Won't Start

# Check logs
docker logs <container_name>
 
# Check resource usage
docker stats

Traefik Certificate Issues

# Check ACME status
docker logs traefik 2>&1 | grep -i acme
 
# Verify DNS
dig +short sonarr.yourdomain.com

Permission Issues

# Reset ownership
sudo chown -R 1000:1000 /srv/docker-stack/<service>/config

Next Steps

  • Add Authentik for SSO across all services
  • Set up automated backups to cloud storage
  • Configure alerting in Grafana
  • Add Tautulli for Plex analytics

Related Reading

  • Kubernetes Homelab Cluster with K3s
  • Multi-Stack Docker Infrastructure with Traefik and
  • HashiCorp Vault: Secrets Management for Your Homelab and
#Docker#Homelab#Plex#Sonarr#Radarr#Traefik#Self-Hosted

Related Articles

Kubernetes Homelab Cluster with K3s

Build a production-grade K3s cluster on Proxmox/bare metal with Longhorn storage, Traefik ingress, cert-manager, and ArgoCD for GitOps.

5 min read

Keycloak SSO: Self-Hosted Identity Provider for Your Homelab

Deploy Keycloak with Docker Compose and PostgreSQL to build a centralised single sign-on platform for your homelab services, with OIDC integration for...

11 min read

HashiCorp Vault: Secrets Management for Your Homelab and

Deploy HashiCorp Vault to centrally manage secrets, certificates, and dynamic credentials — eliminating hardcoded passwords from your infrastructure with...

12 min read
Back to all Projects