Implement Dockge structure with Traefik, Authelia, DuckDNS, and Gluetun VPN

- Update AI copilot instructions for /opt/stacks structure and automated config management
- Replace Nginx Proxy Manager with Traefik (file-based configuration for AI)
- Add Authelia for SSO with bypass rules for Jellyfin/Plex apps
- Add DuckDNS for dynamic DNS with Let's Encrypt integration
- Add Gluetun VPN with Surfshark (WireGuard) for secure downloads
- Update all services to use /opt/stacks paths instead of local directories
- Add Traefik labels to all services for automatic routing
- Configure qBittorrent to route through Gluetun VPN
- Update .env.example with all new required variables
- Create configuration templates for Traefik and Authelia
- Add comprehensive Dockge deployment guide

Co-authored-by: kelinfoxy <67766943+kelinfoxy@users.noreply.github.com>
This commit is contained in:
copilot-swe-agent[bot]
2026-01-12 00:13:55 +00:00
parent 6083da7036
commit f9a34fe9c7
13 changed files with 1082 additions and 112 deletions

View File

@@ -0,0 +1,324 @@
# Docker Compose Stacks - Dockge Structure
This directory contains Docker Compose files designed for use with Dockge. Each stack should be placed in `/opt/stacks/stack-name/` on your server.
## Structure
```
/opt/stacks/
├── traefik/
│ ├── docker-compose.yml # Copy from traefik.yml
│ ├── traefik.yml # Static configuration
│ ├── dynamic/ # Dynamic routes
│ ├── acme.json # SSL certificates (chmod 600)
│ └── .env
├── authelia/
│ ├── docker-compose.yml # Copy from authelia.yml
│ ├── configuration.yml # Authelia config
│ ├── users_database.yml # User definitions
│ └── .env
├── duckdns/
│ ├── docker-compose.yml # Copy from duckdns.yml
│ └── .env
├── gluetun/
│ ├── docker-compose.yml # Copy from gluetun.yml (includes qBittorrent)
│ └── .env
├── infrastructure/
│ ├── docker-compose.yml # Copy from infrastructure.yml
│ └── .env
├── media/
│ ├── docker-compose.yml # Copy from media.yml
│ └── .env
├── monitoring/
│ ├── docker-compose.yml # Copy from monitoring.yml
│ └── .env
└── development/
├── docker-compose.yml # Copy from development.yml
└── .env
```
## Core Infrastructure Stacks
### 1. Traefik (REQUIRED - Deploy First)
**File**: `traefik.yml`
**Location**: `/opt/stacks/traefik/`
Reverse proxy with automatic SSL certificates via Let's Encrypt.
**Features**:
- Automatic HTTPS with Let's Encrypt
- Docker service discovery via labels
- File-based configuration for AI management
- HTTP to HTTPS redirect
**Setup**:
```bash
mkdir -p /opt/stacks/traefik/dynamic
cd /opt/stacks/traefik
# Copy traefik.yml to docker-compose.yml
# Copy config templates from config-templates/traefik/
# Create acme.json and set permissions
touch acme.json && chmod 600 acme.json
# Edit .env with your domain and email
docker compose up -d
```
### 2. Authelia (REQUIRED - Deploy Second)
**File**: `authelia.yml`
**Location**: `/opt/stacks/authelia/`
Single Sign-On (SSO) authentication for all services.
**Features**:
- Protects services with authentication
- Bypass rules for apps (Jellyfin, Plex)
- Integrates with Traefik via middleware
- TOTP 2FA support
**Setup**:
```bash
mkdir -p /opt/stacks/authelia
cd /opt/stacks/authelia
# Copy authelia.yml to docker-compose.yml
# Copy config templates from config-templates/authelia/
# Generate secrets: openssl rand -hex 64
# Edit configuration.yml and users_database.yml
# Hash password: docker run authelia/authelia:latest authelia crypto hash generate argon2 --password 'yourpassword'
docker compose up -d
```
### 3. DuckDNS (RECOMMENDED)
**File**: `duckdns.yml`
**Location**: `/opt/stacks/duckdns/`
Dynamic DNS updater for your domain.
**Setup**:
```bash
mkdir -p /opt/stacks/duckdns
cd /opt/stacks/duckdns
# Copy duckdns.yml to docker-compose.yml
# Add DUCKDNS_TOKEN and DUCKDNS_SUBDOMAINS to .env
docker compose up -d
```
### 4. Gluetun VPN (REQUIRED for torrenting)
**File**: `gluetun.yml`
**Location**: `/opt/stacks/gluetun/`
VPN client (Surfshark) for routing download clients securely.
**Includes**: qBittorrent configured to route through VPN
**Setup**:
```bash
mkdir -p /opt/stacks/gluetun
mkdir -p /opt/stacks/qbittorrent
cd /opt/stacks/gluetun
# Copy gluetun.yml to docker-compose.yml
# Add Surfshark WireGuard credentials to .env
# Get WireGuard config from Surfshark dashboard
docker compose up -d
```
## Application Stacks
### Infrastructure
**File**: `infrastructure.yml`
**Location**: `/opt/stacks/infrastructure/`
- Pi-hole: Network-wide ad blocking
- Portainer: Docker management UI
- Watchtower: Automatic container updates
### Media
**File**: `media.yml`
**Location**: `/opt/stacks/media/`
- Plex: Media streaming (NO Authelia - app access)
- Jellyfin: Open-source streaming (NO Authelia - app access)
- Sonarr: TV show automation (WITH Authelia)
- Radarr: Movie automation (WITH Authelia)
- Prowlarr: Indexer manager (WITH Authelia)
**Note**: qBittorrent is in gluetun.yml (VPN routing)
### Monitoring
**File**: `monitoring.yml`
**Location**: `/opt/stacks/monitoring/`
- Prometheus: Metrics collection
- Grafana: Visualization
- Node Exporter: System metrics
- cAdvisor: Container metrics
- Uptime Kuma: Service monitoring
- Loki: Log aggregation
- Promtail: Log shipping
### Development
**File**: `development.yml`
**Location**: `/opt/stacks/development/`
- Code Server: VS Code in browser
- GitLab: Git repository manager
- PostgreSQL: Database
- Redis: In-memory store
- pgAdmin: Database UI
- Jupyter Lab: Data science notebooks
- Node-RED: Automation
## Networks
Create these networks before deploying stacks:
```bash
docker network create traefik-network
docker network create homelab-network
```
## Environment Variables
Each stack needs a `.env` file. Use `/home/runner/work/AI-Homelab/AI-Homelab/.env.example` as a template.
**Required variables**:
- `DOMAIN`: Your DuckDNS domain (e.g., `yourdomain.duckdns.org`)
- `DUCKDNS_TOKEN`: Your DuckDNS token
- `ACME_EMAIL`: Email for Let's Encrypt
- `AUTHELIA_JWT_SECRET`: Generate with `openssl rand -hex 64`
- `AUTHELIA_SESSION_SECRET`: Generate with `openssl rand -hex 64`
- `AUTHELIA_STORAGE_ENCRYPTION_KEY`: Generate with `openssl rand -hex 64`
- `SURFSHARK_PRIVATE_KEY`: From Surfshark WireGuard config
- `SURFSHARK_ADDRESSES`: From Surfshark WireGuard config
## Deployment Order
1. **Create networks**:
```bash
docker network create traefik-network
docker network create homelab-network
```
2. **Deploy Traefik** (reverse proxy):
```bash
cd /opt/stacks/traefik
docker compose up -d
```
3. **Deploy Authelia** (SSO):
```bash
cd /opt/stacks/authelia
docker compose up -d
```
4. **Deploy DuckDNS** (optional but recommended):
```bash
cd /opt/stacks/duckdns
docker compose up -d
```
5. **Deploy Gluetun** (VPN for downloads):
```bash
cd /opt/stacks/gluetun
docker compose up -d
```
6. **Deploy other stacks** as needed:
```bash
cd /opt/stacks/infrastructure
docker compose up -d
cd /opt/stacks/media
docker compose up -d
```
## Accessing Services
All services are accessible via your domain:
- **With Authelia (SSO required)**:
- `https://traefik.yourdomain.duckdns.org` - Traefik dashboard
- `https://portainer.yourdomain.duckdns.org` - Portainer
- `https://sonarr.yourdomain.duckdns.org` - Sonarr
- `https://radarr.yourdomain.duckdns.org` - Radarr
- `https://prowlarr.yourdomain.duckdns.org` - Prowlarr
- `https://qbit.yourdomain.duckdns.org` - qBittorrent
- `https://grafana.yourdomain.duckdns.org` - Grafana
- And more...
- **Without Authelia (direct app access)**:
- `https://plex.yourdomain.duckdns.org` - Plex
- `https://jellyfin.yourdomain.duckdns.org` - Jellyfin
- **Authentication page**:
- `https://auth.yourdomain.duckdns.org` - Authelia login
## AI Management
The AI assistant (GitHub Copilot) can:
1. **Add new services**: Creates compose files with proper Traefik labels and Authelia middleware
2. **Modify routes**: Updates Docker labels to change proxy routing
3. **Manage SSO**: Adds or removes Authelia middleware as needed
4. **Configure VPN**: Sets up services to route through Gluetun
5. **Update configurations**: Modifies config files in `/opt/stacks/*/config/`
All configuration is file-based, allowing the AI to manage everything without web UI dependencies.
## Storage Strategy
- **Config files**: `/opt/stacks/stack-name/config/` (on system drive)
- **Small data**: Docker named volumes
- **Large data**:
- Media: `/mnt/media` (separate drive)
- Downloads: `/mnt/downloads` (separate drive)
- Backups: `/mnt/backups` (separate drive)
## Troubleshooting
### Service won't start
```bash
cd /opt/stacks/stack-name
docker compose logs -f
```
### Check Traefik routing
```bash
docker logs traefik
# Or visit: https://traefik.yourdomain.duckdns.org
```
### Test VPN connection
```bash
docker exec gluetun sh -c "curl ifconfig.me"
# Should show VPN IP, not your home IP
```
### Authelia issues
```bash
cd /opt/stacks/authelia
docker compose logs -f authelia
# Check configuration.yml for syntax errors
```
## Backup Important Files
Regular backups of:
- `/opt/stacks/` (all compose files and configs)
- `/opt/stacks/traefik/acme.json` (SSL certificates)
- `/opt/stacks/authelia/users_database.yml` (user accounts)
- Environment files (`.env` - store securely, not in git!)
## Security Notes
1. **Secrets**: Never commit `.env` files or `acme.json` to git
2. **Authelia**: Use strong passwords, hash them properly
3. **VPN**: Always route download clients through Gluetun
4. **Updates**: Watchtower keeps containers updated automatically
5. **Firewall**: Only expose ports 80 and 443 to the internet
## Getting Help
- Check the main [README.md](../README.md)
- Review [Docker Guidelines](../docs/docker-guidelines.md)
- Use GitHub Copilot in VS Code for AI assistance
- Check service-specific logs

View File

@@ -0,0 +1,39 @@
# Authelia SSO Stack
# Single Sign-On authentication for all services
# Place in /opt/stacks/authelia/docker-compose.yml
services:
authelia:
image: authelia/authelia:4.37
container_name: authelia
restart: unless-stopped
networks:
- traefik-network
volumes:
- /opt/stacks/authelia/configuration.yml:/config/configuration.yml:ro
- /opt/stacks/authelia/users_database.yml:/config/users_database.yml
- authelia-data:/config
environment:
- TZ=${TZ}
- AUTHELIA_JWT_SECRET=${AUTHELIA_JWT_SECRET}
- AUTHELIA_SESSION_SECRET=${AUTHELIA_SESSION_SECRET}
- AUTHELIA_STORAGE_ENCRYPTION_KEY=${AUTHELIA_STORAGE_ENCRYPTION_KEY}
- AUTHELIA_NOTIFIER_SMTP_PASSWORD=${SMTP_PASSWORD} # If using email notifications
labels:
- "traefik.enable=true"
- "traefik.http.routers.authelia.rule=Host(`auth.${DOMAIN}`)"
- "traefik.http.routers.authelia.entrypoints=websecure"
- "traefik.http.routers.authelia.tls.certresolver=letsencrypt"
- "traefik.http.services.authelia.loadbalancer.server.port=9091"
# Authelia middleware for other services
- "traefik.http.middlewares.authelia.forwardauth.address=http://authelia:9091/api/verify?rd=https://auth.${DOMAIN}"
- "traefik.http.middlewares.authelia.forwardauth.trustForwardHeader=true"
- "traefik.http.middlewares.authelia.forwardauth.authResponseHeaders=Remote-User,Remote-Groups,Remote-Name,Remote-Email"
volumes:
authelia-data:
driver: local
networks:
traefik-network:
external: true

View File

@@ -0,0 +1,21 @@
# DuckDNS Dynamic DNS Stack
# Updates your DuckDNS domain with current public IP
# Place in /opt/stacks/duckdns/docker-compose.yml
services:
duckdns:
image: lscr.io/linuxserver/duckdns:latest
container_name: duckdns
restart: unless-stopped
environment:
- PUID=${PUID:-1000}
- PGID=${PGID:-1000}
- TZ=${TZ}
- SUBDOMAINS=${DUCKDNS_SUBDOMAINS} # Your subdomain(s), comma separated
- TOKEN=${DUCKDNS_TOKEN} # Your DuckDNS token
- UPDATE_IP=ipv4 # or ipv6, or both
volumes:
- /opt/stacks/duckdns/config:/config
labels:
- "homelab.category=infrastructure"
- "homelab.description=Dynamic DNS updater"

View File

@@ -0,0 +1,81 @@
# Gluetun VPN Stack
# VPN client for routing services through Surfshark (or other VPN providers)
# Place in /opt/stacks/gluetun/docker-compose.yml
# Services that need VPN use: network_mode: "service:gluetun"
services:
gluetun:
image: qmcgaw/gluetun:latest
container_name: gluetun
restart: unless-stopped
cap_add:
- NET_ADMIN
devices:
- /dev/net/tun:/dev/net/tun
networks:
- gluetun-network
- traefik-network
ports:
# qBittorrent ports (service runs through Gluetun)
- "8080:8080" # qBittorrent WebUI
- "6881:6881" # qBittorrent TCP
- "6881:6881/udp" # qBittorrent UDP
environment:
- VPN_SERVICE_PROVIDER=surfshark
- VPN_TYPE=wireguard # or openvpn
- WIREGUARD_PRIVATE_KEY=${SURFSHARK_PRIVATE_KEY}
- WIREGUARD_ADDRESSES=${SURFSHARK_ADDRESSES}
- SERVER_COUNTRIES=${VPN_COUNTRY:-Netherlands} # Preferred VPN server country
- TZ=${TZ}
# For OpenVPN instead of WireGuard:
# - OPENVPN_USER=${SURFSHARK_USERNAME}
# - OPENVPN_PASSWORD=${SURFSHARK_PASSWORD}
volumes:
- /opt/stacks/gluetun/config:/gluetun
labels:
- "homelab.category=infrastructure"
- "homelab.description=VPN client for secure routing (Surfshark)"
# qBittorrent - Torrent client routing through VPN
# Access at: https://qbit.yourdomain.duckdns.org
qbittorrent:
image: lscr.io/linuxserver/qbittorrent:4.6.2
container_name: qbittorrent
network_mode: "service:gluetun" # Routes all traffic through VPN
depends_on:
- gluetun
volumes:
- /opt/stacks/qbittorrent/config:/config
- /mnt/downloads:/downloads # Large downloads on separate drive
environment:
- PUID=${PUID:-1000}
- PGID=${PGID:-1000}
- TZ=${TZ}
- WEBUI_PORT=8080
labels:
- "homelab.category=media"
- "homelab.description=Torrent download client (via VPN)"
# Traefik labels (applied to Gluetun since qBittorrent uses its network)
# Configure these on the Gluetun container instead:
# Traefik routing for qBittorrent (via Gluetun)
# Since qBittorrent uses Gluetun's network, we add a sidecar label container
qbit-labels:
image: alpine:latest
container_name: qbit-labels
command: tail -f /dev/null
networks:
- traefik-network
labels:
- "traefik.enable=true"
- "traefik.http.routers.qbittorrent.rule=Host(`qbit.${DOMAIN}`)"
- "traefik.http.routers.qbittorrent.entrypoints=websecure"
- "traefik.http.routers.qbittorrent.tls.certresolver=letsencrypt"
- "traefik.http.routers.qbittorrent.middlewares=authelia@docker"
- "traefik.http.services.qbittorrent.loadbalancer.server.url=http://gluetun:8080"
networks:
gluetun-network:
driver: bridge
traefik-network:
external: true

View File

@@ -1,43 +1,44 @@
# Infrastructure Services
# Core services that other services depend on
# NOTE: Traefik, Authelia, DuckDNS, and Gluetun have their own compose files
# See traefik.yml, authelia.yml, duckdns.yml, and gluetun.yml
services:
# Nginx Proxy Manager - Web-based reverse proxy management
# Access at: http://server-ip:81
# Default credentials: admin@example.com / changeme
nginx-proxy-manager:
image: jc21/nginx-proxy-manager:2.10.4
container_name: nginx-proxy-manager
restart: unless-stopped
networks:
- homelab-network
ports:
- "80:80" # HTTP
- "443:443" # HTTPS
- "81:81" # Admin UI
volumes:
- ./config/nginx-proxy-manager/data:/data
- ./config/nginx-proxy-manager/letsencrypt:/etc/letsencrypt
environment:
- PUID=${PUID:-1000}
- PGID=${PGID:-1000}
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:81"]
interval: 30s
timeout: 10s
retries: 3
labels:
- "homelab.category=infrastructure"
- "homelab.description=Reverse proxy with Let's Encrypt support"
# Pi-hole - Network-wide ad blocker and DNS server
# Access at: http://server-ip:8080/admin
# Access at: http://server-ip:8080/admin or https://pihole.yourdomain.duckdns.org
pihole:
image: pihole/pihole:2024.01.0
container_name: pihole
restart: unless-stopped
networks:
- homelab-network
- traefik-network
ports:
- "53:53/tcp" # DNS TCP
- "53:53/udp" # DNS UDP
- "8082:80/tcp" # Web interface (changed from 8080 to avoid conflicts)
volumes:
- /opt/stacks/pihole/etc-pihole:/etc/pihole
- /opt/stacks/pihole/etc-dnsmasq.d:/etc/dnsmasq.d
environment:
- TZ=${TZ:-America/New_York}
- WEBPASSWORD=${PIHOLE_PASSWORD:-changeme}
- FTLCONF_LOCAL_IPV4=${SERVER_IP}
dns:
- 127.0.0.1
- 1.1.1.1
cap_add:
- NET_ADMIN
labels:
- "homelab.category=infrastructure"
- "homelab.description=Network-wide ad blocking and DNS"
# Traefik labels
- "traefik.enable=true"
- "traefik.http.routers.pihole.rule=Host(`pihole.${DOMAIN}`)"
- "traefik.http.routers.pihole.entrypoints=websecure"
- "traefik.http.routers.pihole.tls.certresolver=letsencrypt"
- "traefik.http.routers.pihole.middlewares=authelia@docker"
- "traefik.http.services.pihole.loadbalancer.server.port=80"
ports:
- "53:53/tcp" # DNS TCP
- "53:53/udp" # DNS UDP
@@ -59,16 +60,14 @@ services:
- "homelab.description=Network-wide ad blocking and DNS"
# Portainer - Docker management UI
# Access at: http://server-ip:9000
# Access at: https://portainer.yourdomain.duckdns.org
portainer:
image: portainer/portainer-ce:2.19.4
container_name: portainer
restart: unless-stopped
networks:
- homelab-network
ports:
- "9000:9000"
- "9443:9443"
- traefik-network
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- portainer-data:/data
@@ -77,6 +76,13 @@ services:
labels:
- "homelab.category=infrastructure"
- "homelab.description=Docker container management UI"
# Traefik labels
- "traefik.enable=true"
- "traefik.http.routers.portainer.rule=Host(`portainer.${DOMAIN}`)"
- "traefik.http.routers.portainer.entrypoints=websecure"
- "traefik.http.routers.portainer.tls.certresolver=letsencrypt"
- "traefik.http.routers.portainer.middlewares=authelia@docker"
- "traefik.http.services.portainer.loadbalancer.server.port=9000"
# Watchtower - Automatic container updates
# Runs silently in background, no UI
@@ -105,3 +111,5 @@ volumes:
networks:
homelab-network:
external: true
traefik-network:
external: true

View File

@@ -1,9 +1,12 @@
# Media Services
# Services for media management and streaming
# Place in /opt/stacks/media/docker-compose.yml
# NOTE: qBittorrent is configured to use Gluetun VPN (see gluetun.yml)
services:
# Plex Media Server - Media streaming platform
# Access at: http://server-ip:32400/web
# Access at: https://plex.yourdomain.duckdns.org
# NOTE: No Authelia - allows app access from Roku, Fire TV, mobile, etc.
plex:
image: plexinc/pms-docker:1.40.0.7998-f68041501
container_name: plex
@@ -11,18 +14,16 @@ services:
networks:
- media-network
- homelab-network
ports:
- "32400:32400" # Plex web UI
- traefik-network
volumes:
- ./config/plex:/config
- ${MEDIADIR:-/media}:/media:ro
- /opt/stacks/plex/config:/config
- /mnt/media:/media:ro # Large media files on separate drive
- plex-transcode:/transcode
environment:
- PUID=${PUID:-1000}
- PGID=${PGID:-1000}
- TZ=${TZ:-America/New_York}
- PLEX_CLAIM=${PLEX_CLAIM}
- ADVERTISE_IP=http://${SERVER_IP}:32400/
# Hardware transcoding support
# Uncomment ONE of the following options:
@@ -44,9 +45,16 @@ services:
labels:
- "homelab.category=media"
- "homelab.description=Plex media streaming server"
# Traefik labels - NO Authelia for app access
- "traefik.enable=true"
- "traefik.http.routers.plex.rule=Host(`plex.${DOMAIN}`)"
- "traefik.http.routers.plex.entrypoints=websecure"
- "traefik.http.routers.plex.tls.certresolver=letsencrypt"
- "traefik.http.services.plex.loadbalancer.server.port=32400"
# Jellyfin - Free alternative to Plex
# Access at: http://server-ip:8096
# Access at: https://jellyfin.yourdomain.duckdns.org
# NOTE: No Authelia - allows app access from Roku, Fire TV, mobile, etc.
jellyfin:
image: jellyfin/jellyfin:10.8.13
container_name: jellyfin
@@ -54,12 +62,11 @@ services:
networks:
- media-network
- homelab-network
ports:
- "8096:8096"
- traefik-network
volumes:
- ./config/jellyfin:/config
- ./config/jellyfin/cache:/cache
- ${MEDIADIR:-/media}:/media:ro
- /opt/stacks/jellyfin/config:/config
- /opt/stacks/jellyfin/cache:/cache
- /mnt/media:/media:ro # Large media files on separate drive
environment:
- PUID=${PUID:-1000}
- PGID=${PGID:-1000}
@@ -70,9 +77,15 @@ services:
labels:
- "homelab.category=media"
- "homelab.description=Open-source media streaming server"
# Traefik labels - NO Authelia for app access
- "traefik.enable=true"
- "traefik.http.routers.jellyfin.rule=Host(`jellyfin.${DOMAIN}`)"
- "traefik.http.routers.jellyfin.entrypoints=websecure"
- "traefik.http.routers.jellyfin.tls.certresolver=letsencrypt"
- "traefik.http.services.jellyfin.loadbalancer.server.port=8096"
# Sonarr - TV show automation
# Access at: http://server-ip:8989
# Access at: https://sonarr.yourdomain.duckdns.org
sonarr:
image: lscr.io/linuxserver/sonarr:4.0.0
container_name: sonarr
@@ -80,12 +93,11 @@ services:
networks:
- media-network
- homelab-network
ports:
- "8989:8989"
- traefik-network
volumes:
- ./config/sonarr:/config
- ${MEDIADIR:-/media}:/media
- ${DOWNLOADDIR:-/downloads}:/downloads
- /opt/stacks/sonarr/config:/config
- /mnt/media:/media
- /mnt/downloads:/downloads # Large downloads on separate drive
environment:
- PUID=${PUID:-1000}
- PGID=${PGID:-1000}
@@ -93,9 +105,16 @@ services:
labels:
- "homelab.category=media"
- "homelab.description=TV show management and automation"
# Traefik labels with Authelia
- "traefik.enable=true"
- "traefik.http.routers.sonarr.rule=Host(`sonarr.${DOMAIN}`)"
- "traefik.http.routers.sonarr.entrypoints=websecure"
- "traefik.http.routers.sonarr.tls.certresolver=letsencrypt"
- "traefik.http.routers.sonarr.middlewares=authelia@docker"
- "traefik.http.services.sonarr.loadbalancer.server.port=8989"
# Radarr - Movie automation
# Access at: http://server-ip:7878
# Access at: https://radarr.yourdomain.duckdns.org
radarr:
image: lscr.io/linuxserver/radarr:5.2.6
container_name: radarr
@@ -103,12 +122,11 @@ services:
networks:
- media-network
- homelab-network
ports:
- "7878:7878"
- traefik-network
volumes:
- ./config/radarr:/config
- ${MEDIADIR:-/media}:/media
- ${DOWNLOADDIR:-/downloads}:/downloads
- /opt/stacks/radarr/config:/config
- /mnt/media:/media
- /mnt/downloads:/downloads # Large downloads on separate drive
environment:
- PUID=${PUID:-1000}
- PGID=${PGID:-1000}
@@ -116,9 +134,16 @@ services:
labels:
- "homelab.category=media"
- "homelab.description=Movie management and automation"
# Traefik labels with Authelia
- "traefik.enable=true"
- "traefik.http.routers.radarr.rule=Host(`radarr.${DOMAIN}`)"
- "traefik.http.routers.radarr.entrypoints=websecure"
- "traefik.http.routers.radarr.tls.certresolver=letsencrypt"
- "traefik.http.routers.radarr.middlewares=authelia@docker"
- "traefik.http.services.radarr.loadbalancer.server.port=7878"
# Prowlarr - Indexer manager
# Access at: http://server-ip:9696
# Access at: https://prowlarr.yourdomain.duckdns.org
prowlarr:
image: lscr.io/linuxserver/prowlarr:1.11.4
container_name: prowlarr
@@ -126,10 +151,9 @@ services:
networks:
- media-network
- homelab-network
ports:
- "9696:9696"
- traefik-network
volumes:
- ./config/prowlarr:/config
- /opt/stacks/prowlarr/config:/config
environment:
- PUID=${PUID:-1000}
- PGID=${PGID:-1000}
@@ -137,32 +161,19 @@ services:
labels:
- "homelab.category=media"
- "homelab.description=Indexer manager for Sonarr/Radarr"
# Traefik labels with Authelia
- "traefik.enable=true"
- "traefik.http.routers.prowlarr.rule=Host(`prowlarr.${DOMAIN}`)"
- "traefik.http.routers.prowlarr.entrypoints=websecure"
- "traefik.http.routers.prowlarr.tls.certresolver=letsencrypt"
- "traefik.http.routers.prowlarr.middlewares=authelia@docker"
- "traefik.http.services.prowlarr.loadbalancer.server.port=9696"
# qBittorrent - Torrent client
# Access at: http://server-ip:8081
# Default credentials: admin / adminadmin
qbittorrent:
image: lscr.io/linuxserver/qbittorrent:4.6.2
container_name: qbittorrent
restart: unless-stopped
networks:
- media-network
- homelab-network
ports:
- "8081:8081" # Web UI
- "6881:6881" # Torrent port TCP
- "6881:6881/udp" # Torrent port UDP
volumes:
- ./config/qbittorrent:/config
- ${DOWNLOADDIR:-/downloads}:/downloads
environment:
- PUID=${PUID:-1000}
- PGID=${PGID:-1000}
- TZ=${TZ:-America/New_York}
- WEBUI_PORT=8081
labels:
- "homelab.category=media"
- "homelab.description=Torrent download client"
# Access at: https://qbit.yourdomain.duckdns.org
# Routes through Gluetun VPN - configure in gluetun.yml
# NOTE: This is a placeholder. Configure qBittorrent in gluetun.yml with network_mode: "service:gluetun"
# See gluetun.yml for the actual qBittorrent configuration
volumes:
plex-transcode:
@@ -173,3 +184,5 @@ networks:
driver: bridge
homelab-network:
external: true
traefik-network:
external: true

View File

@@ -0,0 +1,43 @@
# Traefik Reverse Proxy Stack
# Main reverse proxy with Let's Encrypt SSL automation
# Place in /opt/stacks/traefik/docker-compose.yml
services:
traefik:
image: traefik:v2.11
container_name: traefik
restart: unless-stopped
security_opt:
- no-new-privileges:true
networks:
- traefik-network
ports:
- "80:80" # HTTP
- "443:443" # HTTPS
- "8080:8080" # Dashboard (protect with Authelia)
volumes:
- /etc/localtime:/etc/localtime:ro
- /var/run/docker.sock:/var/run/docker.sock:ro
- /opt/stacks/traefik/traefik.yml:/traefik.yml:ro
- /opt/stacks/traefik/dynamic:/dynamic:ro
- /opt/stacks/traefik/acme.json:/acme.json
environment:
- CF_DNS_API_TOKEN=${CF_DNS_API_TOKEN} # If using Cloudflare DNS challenge
- DUCKDNS_TOKEN=${DUCKDNS_TOKEN} # If using DuckDNS
labels:
- "traefik.enable=true"
# Dashboard
- "traefik.http.routers.traefik.rule=Host(`traefik.${DOMAIN}`)"
- "traefik.http.routers.traefik.entrypoints=websecure"
- "traefik.http.routers.traefik.tls.certresolver=letsencrypt"
- "traefik.http.routers.traefik.middlewares=authelia@docker"
- "traefik.http.routers.traefik.service=api@internal"
# Global HTTP to HTTPS redirect
- "traefik.http.routers.http-catchall.rule=hostregexp(`{host:.+}`)"
- "traefik.http.routers.http-catchall.entrypoints=web"
- "traefik.http.routers.http-catchall.middlewares=redirect-to-https"
- "traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https"
networks:
traefik-network:
external: true