media-rip/docker-compose.example.yml
xpltd c9ad4fc5d0 R021/R022/R026: Docker, CI/CD, deployment example
Dockerfile (multi-stage):
- Stage 1: Node 22 builds frontend (npm ci + npm run build)
- Stage 2: Python 3.12 installs backend deps
- Stage 3: Slim runtime with ffmpeg + deno (yt-dlp needs both)
- Non-root user (mediarip), healthcheck, PYTHONUNBUFFERED
- Volumes: /downloads (media), /data (SQLite DB)

docker-compose.example.yml:
- Caddy reverse proxy with automatic TLS via Let's Encrypt
- Separate Caddyfile.example for domain configuration
- Health-dependent startup ordering
- Environment variables for admin setup

CI/CD (.github/workflows/):
- ci.yml: backend lint+test, frontend typecheck+test, Docker smoke
  build. Runs on PRs and pushes to main.
- publish.yml: multi-platform build (amd64+arm64), pushes to
  ghcr.io/xpltd/media-rip on v*.*.* tags. Semantic version tags
  (v1.0.0 → latest + 1.0.0 + 1.0 + 1). Auto GitHub Release.

.dockerignore: excludes dev artifacts, .gsd/, node_modules/, .venv/
2026-03-19 06:57:25 -05:00

62 lines
1.7 KiB
YAML

# media.rip() — Docker Compose example with Caddy reverse proxy
#
# This is the recommended deployment configuration.
# Caddy automatically provisions TLS certificates via Let's Encrypt.
#
# Usage:
# 1. Replace YOUR_DOMAIN with your actual domain
# 2. Set a strong admin password hash (see below)
# 3. Run: docker compose up -d
#
# Generate a bcrypt password hash:
# docker run --rm python:3.12-slim python -c \
# "import bcrypt; print(bcrypt.hashpw(b'YOUR_PASSWORD', bcrypt.gensalt()).decode())"
services:
media-rip:
image: ghcr.io/xpltd/media-rip:latest
container_name: media-rip
restart: unless-stopped
volumes:
- downloads:/downloads
- data:/data
# Optional: custom themes
# - ./themes:/themes:ro
# Optional: config file
# - ./config.yaml:/app/config.yaml:ro
environment:
# Admin panel (optional — remove to disable)
MEDIARIP__ADMIN__ENABLED: "true"
MEDIARIP__ADMIN__USERNAME: "admin"
MEDIARIP__ADMIN__PASSWORD_HASH: "${ADMIN_PASSWORD_HASH}"
# Session mode: isolated (default), shared, or open
# MEDIARIP__SESSION__MODE: "isolated"
expose:
- "8000"
healthcheck:
test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://localhost:8000/api/health')"]
interval: 30s
timeout: 5s
retries: 3
start_period: 10s
caddy:
image: caddy:2-alpine
container_name: media-rip-caddy
restart: unless-stopped
ports:
- "80:80"
- "443:443"
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile:ro
- caddy_data:/data
- caddy_config:/config
depends_on:
media-rip:
condition: service_healthy
volumes:
downloads:
data:
caddy_data:
caddy_config: