Major additions: - Web-based setup wizard (setup.php, setup_wizard.php, setup-wizard.js) - Production Docker configuration (docker-compose.prod.yml, .env.production) - Database initialization SQL files (deploy/init_settings.sql) - Template builder system with drag-and-drop UI - Advanced features (OAuth, CDN, enhanced analytics, monetization) - Comprehensive documentation (deployment guides, quick start, feature docs) - Design system with accessibility and responsive layout - Deployment automation scripts (deploy.ps1, generate-secrets.ps1) Setup wizard allows customization of: - Platform name and branding - Domain configuration - Membership tiers and pricing - Admin credentials - Feature toggles Database includes 270+ tables for complete video streaming platform with advanced features for analytics, moderation, template building, and monetization. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
366 lines
9.3 KiB
YAML
366 lines
9.3 KiB
YAML
version: "3.8"
|
|
|
|
# ============================================================================
|
|
# EasyStream - Production Docker Compose Configuration
|
|
# ============================================================================
|
|
# Usage: docker-compose -f docker-compose.prod.yml up -d
|
|
#
|
|
# IMPORTANT: Before deployment:
|
|
# 1. Copy .env.production to .env and fill in all values
|
|
# 2. Generate secure secrets for all services
|
|
# 3. Set up SSL/TLS certificates
|
|
# 4. Configure external volumes for data persistence
|
|
# 5. Set up monitoring and logging
|
|
# ============================================================================
|
|
|
|
services:
|
|
|
|
db:
|
|
image: mariadb:10.6
|
|
container_name: easystream-db-prod
|
|
restart: always
|
|
environment:
|
|
MYSQL_ROOT_PASSWORD_FILE: /run/secrets/db_root_password
|
|
MYSQL_DATABASE: ${DB_NAME:-easystream}
|
|
MYSQL_USER: ${DB_USER:-easystream}
|
|
MYSQL_PASSWORD_FILE: /run/secrets/db_password
|
|
ports:
|
|
- "127.0.0.1:3306:3306" # Only bind to localhost
|
|
volumes:
|
|
- db_data:/var/lib/mysql
|
|
- ./__install/easystream.sql:/docker-entrypoint-initdb.d/1-main_schema.sql:ro
|
|
- ./__install/add_advanced_features.sql:/docker-entrypoint-initdb.d/2-advanced_features.sql:ro
|
|
- ./deploy/init_settings.sql:/docker-entrypoint-initdb.d/3-init_settings.sql:ro
|
|
- ./deploy/backup:/backup # For database backups
|
|
secrets:
|
|
- db_root_password
|
|
- db_password
|
|
healthcheck:
|
|
test: ["CMD-SHELL", "mysqladmin ping -h 127.0.0.1 -u ${DB_USER:-easystream} --silent || exit 1"]
|
|
start_period: 120s
|
|
interval: 30s
|
|
timeout: 10s
|
|
retries: 5
|
|
networks:
|
|
- backend
|
|
logging:
|
|
driver: "json-file"
|
|
options:
|
|
max-size: "10m"
|
|
max-file: "3"
|
|
|
|
php:
|
|
build:
|
|
context: .
|
|
dockerfile: Dockerfile.php
|
|
args:
|
|
PHP_VERSION: 8.2
|
|
image: easystream-php:production
|
|
container_name: easystream-php-prod
|
|
restart: always
|
|
working_dir: /srv/easystream
|
|
environment:
|
|
TZ: ${TZ:-UTC}
|
|
DB_HOST: db
|
|
DB_NAME: ${DB_NAME:-easystream}
|
|
DB_USER: ${DB_USER:-easystream}
|
|
DB_PASS_FILE: /run/secrets/db_password
|
|
REDIS_HOST: redis
|
|
REDIS_PORT: 6379
|
|
REDIS_DB: 0
|
|
MAIN_URL: ${MAIN_URL}
|
|
DEBUG: "false"
|
|
APP_ENV: production
|
|
PHP_MEMORY_LIMIT: 512M
|
|
PHP_UPLOAD_MAX_FILESIZE: 256M
|
|
PHP_POST_MAX_SIZE: 256M
|
|
volumes:
|
|
- ./:/srv/easystream:ro # Read-only for security
|
|
- app_uploads:/srv/easystream/f_data/uploads
|
|
- app_cache:/srv/easystream/f_data/cache
|
|
- app_logs:/srv/easystream/f_data/logs
|
|
- rtmp_hls:/var/www/hls:ro
|
|
- rtmp_rec:/mnt/rec:ro
|
|
secrets:
|
|
- db_password
|
|
- api_key
|
|
- jwt_secret
|
|
- encryption_key
|
|
depends_on:
|
|
db:
|
|
condition: service_healthy
|
|
redis:
|
|
condition: service_healthy
|
|
networks:
|
|
- frontend
|
|
- backend
|
|
logging:
|
|
driver: "json-file"
|
|
options:
|
|
max-size: "10m"
|
|
max-file: "5"
|
|
|
|
caddy:
|
|
image: caddy:2-alpine
|
|
container_name: easystream-caddy-prod
|
|
restart: always
|
|
depends_on:
|
|
php:
|
|
condition: service_started
|
|
srs:
|
|
condition: service_started
|
|
ports:
|
|
- "80:80"
|
|
- "443:443"
|
|
- "443:443/udp" # HTTP/3
|
|
volumes:
|
|
- ./Caddyfile:/etc/caddy/Caddyfile:ro
|
|
- ./:/srv/easystream:ro
|
|
- rtmp_hls:/var/www/hls:ro
|
|
- caddy_data:/data
|
|
- caddy_config:/config
|
|
- ./deploy/ssl:/ssl:ro # For custom SSL certificates
|
|
networks:
|
|
- frontend
|
|
logging:
|
|
driver: "json-file"
|
|
options:
|
|
max-size: "10m"
|
|
max-file: "3"
|
|
healthcheck:
|
|
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:80/health"]
|
|
interval: 30s
|
|
timeout: 10s
|
|
retries: 3
|
|
|
|
srs:
|
|
image: ossrs/srs:5
|
|
container_name: easystream-srs-prod
|
|
restart: always
|
|
ports:
|
|
- "1935:1935" # RTMP ingest
|
|
- "1985:1985" # HTTP API
|
|
- "8080:8080" # HTTP Server
|
|
volumes:
|
|
- ./deploy/srs.conf:/usr/local/srs/conf/srs.conf:ro
|
|
- rtmp_hls:/srs/hls
|
|
- rtmp_rec:/srs/rec
|
|
- srs_logs:/usr/local/srs/objs/logs
|
|
command: ["/usr/local/srs/objs/srs", "-c", "/usr/local/srs/conf/srs.conf"]
|
|
networks:
|
|
- frontend
|
|
- backend
|
|
logging:
|
|
driver: "json-file"
|
|
options:
|
|
max-size: "10m"
|
|
max-file: "3"
|
|
|
|
redis:
|
|
image: redis:7-alpine
|
|
container_name: easystream-redis-prod
|
|
restart: always
|
|
ports:
|
|
- "127.0.0.1:6379:6379" # Only bind to localhost
|
|
volumes:
|
|
- redis_data:/data
|
|
command: >
|
|
redis-server
|
|
--appendonly yes
|
|
--maxmemory 512mb
|
|
--maxmemory-policy allkeys-lru
|
|
--requirepass ${REDIS_PASSWORD:-}
|
|
--save 900 1
|
|
--save 300 10
|
|
--save 60 10000
|
|
networks:
|
|
- backend
|
|
healthcheck:
|
|
test: ["CMD", "redis-cli", "ping"]
|
|
interval: 30s
|
|
timeout: 10s
|
|
retries: 5
|
|
logging:
|
|
driver: "json-file"
|
|
options:
|
|
max-size: "5m"
|
|
max-file: "3"
|
|
|
|
cron:
|
|
build:
|
|
context: .
|
|
dockerfile: Dockerfile.cron
|
|
image: easystream-cron:production
|
|
container_name: easystream-cron-prod
|
|
restart: always
|
|
depends_on:
|
|
php:
|
|
condition: service_started
|
|
environment:
|
|
TZ: ${TZ:-UTC}
|
|
DB_HOST: db
|
|
DB_NAME: ${DB_NAME:-easystream}
|
|
DB_USER: ${DB_USER:-easystream}
|
|
DB_PASS_FILE: /run/secrets/db_password
|
|
CRON_BASE_URL: ${MAIN_URL}
|
|
CRON_SSK_FILE: /run/secrets/cron_secret
|
|
VOD_REC_PATH: /mnt/rec
|
|
REDIS_HOST: redis
|
|
REDIS_PORT: 6379
|
|
REDIS_DB: 0
|
|
volumes:
|
|
- ./:/srv/easystream:ro
|
|
- rtmp_rec:/mnt/rec:ro
|
|
- cron_logs:/var/log/cron
|
|
secrets:
|
|
- db_password
|
|
- cron_secret
|
|
networks:
|
|
- backend
|
|
logging:
|
|
driver: "json-file"
|
|
options:
|
|
max-size: "5m"
|
|
max-file: "3"
|
|
|
|
queue-worker:
|
|
build:
|
|
context: .
|
|
dockerfile: Dockerfile.php
|
|
image: easystream-php:production
|
|
container_name: easystream-worker-prod
|
|
restart: always
|
|
depends_on:
|
|
db:
|
|
condition: service_healthy
|
|
redis:
|
|
condition: service_healthy
|
|
environment:
|
|
TZ: ${TZ:-UTC}
|
|
DB_HOST: db
|
|
DB_NAME: ${DB_NAME:-easystream}
|
|
DB_USER: ${DB_USER:-easystream}
|
|
DB_PASS_FILE: /run/secrets/db_password
|
|
REDIS_HOST: redis
|
|
REDIS_PORT: 6379
|
|
WORKER_QUEUES: ${WORKER_QUEUES:-default,video,email,notifications}
|
|
WORKER_SLEEP: ${WORKER_SLEEP:-3}
|
|
WORKER_TIMEOUT: ${WORKER_TIMEOUT:-300}
|
|
volumes:
|
|
- ./:/srv/easystream:ro
|
|
- app_uploads:/srv/easystream/f_data/uploads
|
|
- rtmp_hls:/var/www/hls
|
|
- rtmp_rec:/mnt/rec
|
|
secrets:
|
|
- db_password
|
|
command: php f_scripts/queue_worker.php
|
|
networks:
|
|
- backend
|
|
logging:
|
|
driver: "json-file"
|
|
options:
|
|
max-size: "10m"
|
|
max-file: "5"
|
|
deploy:
|
|
replicas: 2 # Run 2 workers for high availability
|
|
|
|
abr:
|
|
image: jrottenberg/ffmpeg:5.1-ubuntu
|
|
container_name: easystream-abr-prod
|
|
restart: always
|
|
entrypoint: ["/bin/bash"]
|
|
command: ["/abr.sh"]
|
|
depends_on:
|
|
srs:
|
|
condition: service_started
|
|
environment:
|
|
ABR_STREAM_KEY: ${ABR_STREAM_KEY:-}
|
|
volumes:
|
|
- rtmp_hls:/var/www/hls
|
|
- ./deploy/abr.sh:/abr.sh:ro
|
|
networks:
|
|
- backend
|
|
logging:
|
|
driver: "json-file"
|
|
options:
|
|
max-size: "5m"
|
|
max-file: "3"
|
|
|
|
# ============================================================================
|
|
# Docker Secrets (Production Security)
|
|
# ============================================================================
|
|
# Create these files before deployment:
|
|
# echo "your_secret" | docker secret create db_root_password -
|
|
# echo "your_secret" | docker secret create db_password -
|
|
# etc.
|
|
# ============================================================================
|
|
|
|
secrets:
|
|
db_root_password:
|
|
file: ./secrets/db_root_password.txt
|
|
db_password:
|
|
file: ./secrets/db_password.txt
|
|
api_key:
|
|
file: ./secrets/api_key.txt
|
|
jwt_secret:
|
|
file: ./secrets/jwt_secret.txt
|
|
encryption_key:
|
|
file: ./secrets/encryption_key.txt
|
|
cron_secret:
|
|
file: ./secrets/cron_secret.txt
|
|
|
|
# ============================================================================
|
|
# Persistent Volumes
|
|
# ============================================================================
|
|
|
|
volumes:
|
|
db_data:
|
|
driver: local
|
|
driver_opts:
|
|
type: none
|
|
o: bind
|
|
device: /var/lib/easystream/db
|
|
redis_data:
|
|
driver: local
|
|
app_uploads:
|
|
driver: local
|
|
driver_opts:
|
|
type: none
|
|
o: bind
|
|
device: /var/lib/easystream/uploads
|
|
app_cache:
|
|
driver: local
|
|
app_logs:
|
|
driver: local
|
|
driver_opts:
|
|
type: none
|
|
o: bind
|
|
device: /var/log/easystream
|
|
rtmp_hls:
|
|
driver: local
|
|
rtmp_rec:
|
|
driver: local
|
|
driver_opts:
|
|
type: none
|
|
o: bind
|
|
device: /var/lib/easystream/recordings
|
|
srs_logs:
|
|
driver: local
|
|
cron_logs:
|
|
driver: local
|
|
caddy_data:
|
|
driver: local
|
|
caddy_config:
|
|
driver: local
|
|
|
|
# ============================================================================
|
|
# Networks
|
|
# ============================================================================
|
|
|
|
networks:
|
|
frontend:
|
|
driver: bridge
|
|
backend:
|
|
driver: bridge
|
|
internal: true # Backend network not accessible from outside
|