# SyncTV Production Compose Environment # # Copy to .env.synctv before running docker compose. The documentation includes # a browser-based generator that creates this file without cloning the project. # # Keep this file stable across restarts and upgrades. Losing these secrets can # break login, password authentication, provider credential decryption, or # database access. # # SECURITY WARNING: Never commit .env.synctv with real secrets. # For file-mounted secrets, prefer the *_file keys in synctv.yaml / synctv.example.yaml. # There is no generic automatic *_FILE rule for every environment variable, but # supported secret env vars do have explicit *_FILE variants. See # docs/reference/environment-variables for the complete list. # ============================================================================ # REQUIRED PRODUCTION COMPOSE CONFIGURATION # ============================================================================ # Database URL used by the synctv container. # The generator fills this from the PostgreSQL password in .env.postgres. SYNCTV_DATABASE_URL= # JWT secret used to sign access and refresh tokens. # Generate with: openssl rand -base64 32 SYNCTV_JWT_SECRET= # Shared cluster secret. Optional for single-node Compose, but generated here so # future cluster enablement can reuse a stable secret. # Generate with: openssl rand -hex 32 SYNCTV_CLUSTER_SECRET= # 64-character hex key used to encrypt provider credentials. # Generate with: openssl rand -hex 32 SYNCTV_SECURITY_CREDENTIAL_ENCRYPTION_KEY= # 64-character hex key used only to encrypt TOTP secrets. # Generate with: openssl rand -hex 32 SYNCTV_SECURITY_TOTP_ENCRYPTION_KEY= # 64-character hex key used only to encrypt durable email outbox payloads. # Generate with: openssl rand -hex 32 SYNCTV_SECURITY_EMAIL_OUTBOX_ENCRYPTION_KEY= # Stable secret used by OPAQUE password authentication. # Generate with: openssl rand -base64 48 SYNCTV_SECURITY_OPAQUE_SERVER_SETUP_SECRET= # Independent keys for proxy URLs, media swarm announcements, Provider login # sessions, login discovery, WebAuthn enumeration protection, and file tokens. # Generate each value separately with: openssl rand -base64 48 SYNCTV_SECURITY_PROXY_SIGNING_KEY= SYNCTV_SECURITY_MEDIA_SWARM_SIGNING_KEY= SYNCTV_SECURITY_PROVIDER_SESSION_ENCRYPTION_KEY= SYNCTV_SECURITY_LOGIN_DISCOVERY_KEY= SYNCTV_SECURITY_WEBAUTHN_ENUMERATION_KEY= SYNCTV_FILE_UPLOAD_TOKEN_SECRET= # Global SSRF policy. Disabled by default for self-hosted private media # providers. Enable it for public deployments and use allowlists for known # internal media endpoints. SYNCTV_SECURITY_SSRF_ENABLED=false SYNCTV_SECURITY_SSRF_ALLOW_PRIVATE_NETWORK_TARGETS=false # SYNCTV_SECURITY_SSRF_ALLOWED_HOSTS=nas.example.internal,alist.internal # SYNCTV_SECURITY_SSRF_ALLOWED_IP_RANGES=192.168.1.10/32,10.0.8.0/24 # Initial root password. Generate and store it with a password manager. SYNCTV_BOOTSTRAP_ROOT_PASSWORD= # Root user is created only on first startup when the database has no root user. SYNCTV_BOOTSTRAP_CREATE_ROOT_USER=true SYNCTV_BOOTSTRAP_ROOT_USERNAME=root # ============================================================================ # RECOMMENDED CONFIGURATION # ============================================================================ # The generator fills this with the Redis AUTH password from .env.redis. SYNCTV_REDIS_URL=redis://redis:6379 # PostgreSQL and Redis are reached through the Docker network by default. # docker-compose.yml binds their optional host ports to 127.0.0.1 only. SYNCTV_DATA_DIR=/data # ============================================================================ # SERVER CONFIGURATION # ============================================================================ SYNCTV_SERVER_HOST=0.0.0.0 SYNCTV_SERVER_PORT=8080 # Optional runtime Web UI directory for development or external asset deployment. # The server reads files on every request. Relative paths use the process working directory. # SYNCTV_SERVER_WEB_UI_DIRECTORY=/app/synctv-web-ui/dist # Dedicated health listener used by the container healthcheck. It stays inside # the Docker network and is not published to the host by docker-compose.yml. SYNCTV_HEALTH_ENABLED=true SYNCTV_HEALTH_HOST=0.0.0.0 SYNCTV_HEALTH_PORT=8081 # Prometheus metrics listener. It stays inside the Docker network unless an # operator publishes it explicitly for a trusted Prometheus collector. SYNCTV_METRICS_ENABLED=false SYNCTV_METRICS_HOST=0.0.0.0 SYNCTV_METRICS_PORT=9090 # Enable gRPC Reflection (for grpcurl) SYNCTV_SERVER_ENABLE_REFLECTION=false # Graceful Shutdown Timeout (seconds) SYNCTV_SERVER_SHUTDOWN_DRAIN_TIMEOUT_SECONDS=30 # ============================================================================ # TIME CONFIGURATION # ============================================================================ # Default IANA timezone for human-readable output and local datetime parsing. # Examples: UTC, Asia/Shanghai, America/New_York # Leave unset to fall back to TZ or system timezone. # SYNCTV_TIME_TIMEZONE=UTC # Standard timezone environment fallback used when SYNCTV_TIME_TIMEZONE # is not set. Prefer SYNCTV_TIME_TIMEZONE for application-specific control. # TZ=UTC # ============================================================================ # CLUSTER CONFIGURATION (Multi-Replica Deployments) # ============================================================================ # Prefer cluster.secret_file in synctv.yaml when using mounted secret files. # Dedicated internal gRPC listener used between replicas. SYNCTV_CLUSTER_ENABLED=false SYNCTV_CLUSTER_HOST=0.0.0.0 SYNCTV_CLUSTER_PORT=50051 # SYNCTV_CLUSTER_ADVERTISE_HOST= # SYNCTV_CLUSTER_ADVERTISE_PORT=50051 # Advertise Host (public hostname for this replica) # SYNCTV_SERVER_ADVERTISE_HOST= # ============================================================================ # DATABASE CONFIGURATION # ============================================================================ SYNCTV_DATABASE_MAX_CONNECTIONS=20 SYNCTV_DATABASE_MIN_CONNECTIONS=5 SYNCTV_DATABASE_CONNECT_TIMEOUT_SECONDS=10 SYNCTV_DATABASE_IDLE_TIMEOUT_SECONDS=600 SYNCTV_DATABASE_MAX_LIFETIME_SECONDS=1800 # ============================================================================ # REDIS CONFIGURATION # ============================================================================ SYNCTV_REDIS_KEY_PREFIX=synctv: # ============================================================================ # JWT CONFIGURATION # ============================================================================ SYNCTV_JWT_ACCESS_TOKEN_DURATION_HOURS=1 SYNCTV_JWT_REFRESH_TOKEN_DURATION_DAYS=30 SYNCTV_JWT_GUEST_TOKEN_DURATION_HOURS=4 SYNCTV_JWT_CLOCK_SKEW_LEEWAY_SECS=60 # ============================================================================ # LOGGING CONFIGURATION # ============================================================================ # File paths are resolved from SYNCTV_DATA_DIR. Setting OUTPUT_PATH selects # file output; rotation values apply to file output only. SYNCTV_LOGGING_LEVEL=info SYNCTV_LOGGING_FORMAT=text SYNCTV_LOGGING_OUTPUT=stdout SYNCTV_LOGGING_COLOR=auto # SYNCTV_LOGGING_OUTPUT_PATH=logs/global.log # SYNCTV_LOGGING_OUTPUT_ROTATION_STRATEGY=daily # SYNCTV_LOGGING_OUTPUT_ROTATION_MAX_FILES=30 SYNCTV_SERVER_LOGGING_LEVEL=info SYNCTV_SERVER_LOGGING_FORMAT=text SYNCTV_SERVER_LOGGING_OUTPUT=stdout SYNCTV_SERVER_LOGGING_COLOR=auto # SYNCTV_SERVER_LOGGING_OUTPUT_PATH=logs/server.log # SYNCTV_SERVER_LOGGING_OUTPUT_ROTATION_STRATEGY=daily # SYNCTV_SERVER_LOGGING_OUTPUT_ROTATION_MAX_FILES=30 SYNCTV_HEALTH_LOGGING_LEVEL=info SYNCTV_HEALTH_LOGGING_FORMAT=text SYNCTV_HEALTH_LOGGING_OUTPUT=stdout SYNCTV_HEALTH_LOGGING_COLOR=auto # SYNCTV_HEALTH_LOGGING_OUTPUT_PATH=logs/health.log # SYNCTV_HEALTH_LOGGING_OUTPUT_ROTATION_STRATEGY=daily # SYNCTV_HEALTH_LOGGING_OUTPUT_ROTATION_MAX_FILES=30 SYNCTV_METRICS_LOGGING_LEVEL=warn SYNCTV_METRICS_LOGGING_FORMAT=text SYNCTV_METRICS_LOGGING_OUTPUT=stdout SYNCTV_METRICS_LOGGING_COLOR=auto # SYNCTV_METRICS_LOGGING_OUTPUT_PATH=logs/metrics.log # SYNCTV_METRICS_LOGGING_OUTPUT_ROTATION_STRATEGY=daily # SYNCTV_METRICS_LOGGING_OUTPUT_ROTATION_MAX_FILES=30 SYNCTV_CLUSTER_LOGGING_LEVEL=warn SYNCTV_CLUSTER_LOGGING_FORMAT=text SYNCTV_CLUSTER_LOGGING_OUTPUT=stdout SYNCTV_CLUSTER_LOGGING_COLOR=auto # SYNCTV_CLUSTER_LOGGING_OUTPUT_PATH=logs/cluster.log # SYNCTV_CLUSTER_LOGGING_OUTPUT_ROTATION_STRATEGY=daily # SYNCTV_CLUSTER_LOGGING_OUTPUT_ROTATION_MAX_FILES=30 SYNCTV_MANAGEMENT_LOGGING_LEVEL=info SYNCTV_MANAGEMENT_LOGGING_FORMAT=text SYNCTV_MANAGEMENT_LOGGING_OUTPUT=stdout SYNCTV_MANAGEMENT_LOGGING_COLOR=auto # SYNCTV_MANAGEMENT_LOGGING_OUTPUT_PATH=logs/management.log # SYNCTV_MANAGEMENT_LOGGING_OUTPUT_ROTATION_STRATEGY=daily # SYNCTV_MANAGEMENT_LOGGING_OUTPUT_ROTATION_MAX_FILES=30 SYNCTV_LIVESTREAM_LOGGING_LEVEL=info SYNCTV_LIVESTREAM_LOGGING_FORMAT=text SYNCTV_LIVESTREAM_LOGGING_OUTPUT=stdout SYNCTV_LIVESTREAM_LOGGING_COLOR=auto # SYNCTV_LIVESTREAM_LOGGING_OUTPUT_PATH=logs/livestream.log # SYNCTV_LIVESTREAM_LOGGING_OUTPUT_ROTATION_STRATEGY=daily # SYNCTV_LIVESTREAM_LOGGING_OUTPUT_ROTATION_MAX_FILES=30 SYNCTV_WEBRTC_LOGGING_LEVEL=info SYNCTV_WEBRTC_LOGGING_FORMAT=text SYNCTV_WEBRTC_LOGGING_OUTPUT=stdout SYNCTV_WEBRTC_LOGGING_COLOR=auto # SYNCTV_WEBRTC_LOGGING_OUTPUT_PATH=logs/webrtc.log # SYNCTV_WEBRTC_LOGGING_OUTPUT_ROTATION_STRATEGY=daily # SYNCTV_WEBRTC_LOGGING_OUTPUT_ROTATION_MAX_FILES=30 # ============================================================================ # WEBRTC CONFIGURATION # ============================================================================ SYNCTV_WEBRTC_MODE=peer_to_peer SYNCTV_WEBRTC_STUN_PORT=3478 SYNCTV_WEBRTC_ENABLE_BUILTIN_STUN=false # Clients use Cloudflare and Google public STUN servers by default. Enable the # built-in server only when this deployment should provide STUN. # Built-in STUN needs a client-reachable public ip:port or DNS name:port. # Do not set this to a Pod IP or ClusterIP Service IP. # SYNCTV_WEBRTC_STUN_EXTERNAL_ADDR=stun.example.com:3478 # ============================================================================ # LIVESTREAM CONFIGURATION # ============================================================================ SYNCTV_LIVESTREAM_RTMP_PORT=1935 # Public host returned in RTMP publish URLs. Set this for production RTMP. # SYNCTV_LIVESTREAM_PUBLIC_RTMP_HOST=live.example.com SYNCTV_LIVESTREAM_GOP_CACHE_SIZE=2 SYNCTV_LIVESTREAM_STREAM_TIMEOUT_SECONDS=300 SYNCTV_LIVESTREAM_CLEANUP_CHECK_INTERVAL_SECONDS=60 SYNCTV_LIVESTREAM_PULL_MAX_RETRIES=10 SYNCTV_LIVESTREAM_PULL_INITIAL_BACKOFF_MS=1000 SYNCTV_LIVESTREAM_PULL_MAX_BACKOFF_MS=30000 # ============================================================================ # FILE STORAGE # ============================================================================ # File storage is a registry of named backends. Product features choose a # backend by name; reads use the storage_backend stored on each object. SYNCTV_FILE_STORAGE_DEFAULT_BACKEND=disabled SYNCTV_FILE_STORAGE_CHAT_ATTACHMENTS_BACKEND=disabled SYNCTV_FILE_STORAGE_USER_AVATARS_BACKEND=disabled SYNCTV_FILE_STORAGE_MEDIA_COVERS_BACKEND=disabled SYNCTV_FILE_STORAGE_ROOM_COVERS_BACKEND=disabled SYNCTV_FILE_STORAGE_PLAYLIST_COVERS_BACKEND=disabled SYNCTV_FILE_STORAGE_UNREFERENCED_OBJECT_RETENTION_SECONDS=86400 # JSON object keyed by backend name. YAML config is preferred when using # *_file secret references. # SYNCTV_FILE_STORAGE_BACKENDS='{"database":{"type":"database"}}' # Example: use PostgreSQL for all file-backed product features. # SYNCTV_FILE_STORAGE_DEFAULT_BACKEND=database # SYNCTV_FILE_STORAGE_CHAT_ATTACHMENTS_BACKEND=database # SYNCTV_FILE_STORAGE_USER_AVATARS_BACKEND=database # SYNCTV_FILE_STORAGE_MEDIA_COVERS_BACKEND=database # SYNCTV_FILE_STORAGE_ROOM_COVERS_BACKEND=database # SYNCTV_FILE_STORAGE_PLAYLIST_COVERS_BACKEND=database # SYNCTV_FILE_STORAGE_BACKENDS='{"database":{"type":"database"}}' # Example: store files in S3-compatible object storage. # SYNCTV_FILE_STORAGE_DEFAULT_BACKEND=s3_public # SYNCTV_FILE_STORAGE_CHAT_ATTACHMENTS_BACKEND=s3_public # SYNCTV_FILE_STORAGE_USER_AVATARS_BACKEND=s3_private # SYNCTV_FILE_STORAGE_MEDIA_COVERS_BACKEND=s3_public # SYNCTV_FILE_STORAGE_ROOM_COVERS_BACKEND=s3_public # SYNCTV_FILE_STORAGE_PLAYLIST_COVERS_BACKEND=s3_public # SYNCTV_FILE_STORAGE_BACKENDS='{"s3_public":{"type":"s3","s3":{"endpoint":"https://s3.example.com","access_key_id":"access-key","secret_access_key":"secret-key","bucket":"synctv-files","region":"auto","base_path":"files/","public_base_url":"https://cdn.example.com/files","upload_expires_seconds":900}},"s3_private":{"type":"s3","s3":{"endpoint":"https://s3.example.com","access_key_id":"access-key","secret_access_key":"secret-key","bucket":"synctv-private-files","region":"auto","base_path":"private-files/","public_base_url":null,"upload_expires_seconds":900}}}' # ============================================================================ # CACHE CONFIGURATION # ============================================================================ # Business L1/L2 caches. SYNCTV_CACHE_L1_CAPACITY=5000 SYNCTV_CACHE_L1_TTL_SECONDS=300 SYNCTV_CACHE_L2_TTL_SECONDS=300 SYNCTV_CACHE_USERNAME_CACHE_CAPACITY=10000 SYNCTV_CACHE_USERNAME_CACHE_TTL_SECONDS=3600 SYNCTV_CACHE_PERMISSION_CACHE_CAPACITY=20000 SYNCTV_CACHE_PERMISSION_CACHE_TTL_SECONDS=300 # Media proxy Range-slice cache. The file cache dir is resolved from data_dir # when it is relative. SYNCTV_PROXY_SLICE_CACHE_ENABLED=true SYNCTV_PROXY_SLICE_CACHE_SLICE_SIZE_BYTES=2097152 SYNCTV_PROXY_SLICE_CACHE_MAX_CACHE_SIZE_BYTES=536870912 SYNCTV_PROXY_SLICE_CACHE_SEGMENT_TTL_SECONDS=300 SYNCTV_PROXY_SLICE_CACHE_STALE_MAX_AGE_SECONDS=60 SYNCTV_PROXY_SLICE_CACHE_STALE_WHILE_REVALIDATE=true SYNCTV_PROXY_SLICE_CACHE_FILE_BACKEND_ENABLED=false # SYNCTV_PROXY_SLICE_CACHE_FILE_CACHE_DIR=cache/proxy-slice SYNCTV_PROXY_SLICE_CACHE_EVICTION_INTERVAL_SECONDS=60 SYNCTV_PROXY_SLICE_CACHE_WATERMARK_RATIO=0.875 # ============================================================================ # MANAGEMENT CONFIGURATION # ============================================================================ # SYNCTV_MANAGEMENT_ENABLED=true # SYNCTV_MANAGEMENT_TRANSPORT=unix # SYNCTV_MANAGEMENT_PORT=50052 # SYNCTV_MANAGEMENT_UNIX_SOCKET_PATH=/absolute/path/to/synctv.sock # SYNCTV_MANAGEMENT_AUTH_TOKEN=replace-with-a-random-secret # ============================================================================ # OAUTH2 CONFIGURATION # ============================================================================ # OAuth2 provider details (client_id, client_secret, redirect_url) are runtime # settings, not static environment variables. Configure them through the # management API or `synctv settings update oauth2`. # ============================================================================ # CONNECTION LIMITS # ============================================================================ SYNCTV_CONNECTION_LIMITS_MAX_PER_USER=20 SYNCTV_CONNECTION_LIMITS_MAX_PER_ROOM=2000 SYNCTV_CONNECTION_LIMITS_MAX_TOTAL=100000