services: valkey: image: valkey/valkey:8 container_name: allstarr-valkey restart: unless-stopped # Valkey is only accessible internally - no external port exposure expose: - "6379" # Use a self-healing entrypoint to automatically handle Redis -> Valkey migration pitfalls (like RDB format 12 errors) # Only delete Valkey/Redis persistence artifacts so misconfigured REDIS_DATA_PATH values do not wipe app cache files. entrypoint: - "sh" - "-ec" - | log_file=/tmp/valkey-startup.log log_pipe=/tmp/valkey-startup.pipe server_pid= tee_pid= forward_signal() { if [ -n "$$server_pid" ]; then kill -TERM "$$server_pid" 2>/dev/null || true wait "$$server_pid" 2>/dev/null || true fi if [ -n "$$tee_pid" ]; then kill "$$tee_pid" 2>/dev/null || true wait "$$tee_pid" 2>/dev/null || true fi rm -f "$$log_pipe" exit 143 } trap forward_signal TERM INT start_valkey() { rm -f "$$log_file" "$$log_pipe" : > "$$log_file" mkfifo "$$log_pipe" tee -a "$$log_file" < "$$log_pipe" & tee_pid=$$! valkey-server --maxmemory 1gb --maxmemory-policy allkeys-lru --save 60 1 --appendonly yes > "$$log_pipe" 2>&1 & server_pid=$$! wait "$$server_pid" status=$$? wait "$$tee_pid" 2>/dev/null || true rm -f "$$log_pipe" server_pid= tee_pid= return "$$status" } is_incompatible_persistence_error() { grep -Eq "Can't handle RDB format version|Error reading the RDB base file|AOF loading aborted" "$$log_file" } cleanup_incompatible_persistence() { echo 'Valkey failed to start (likely incompatible Redis persistence files). Removing persisted RDB/AOF artifacts and retrying...' rm -f /data/*.rdb /data/*.aof /data/*.manifest rm -rf /data/appendonlydir /data/appendonlydir-* } if ! start_valkey; then if is_incompatible_persistence_error; then cleanup_incompatible_persistence exec valkey-server --maxmemory 1gb --maxmemory-policy allkeys-lru --save 60 1 --appendonly yes fi exit 1 fi healthcheck: # Use CMD-SHELL for broader compatibility in some environments test: ["CMD-SHELL", "valkey-cli ping || exit 1"] interval: 10s timeout: 3s retries: 5 start_period: 20s volumes: - ${REDIS_DATA_PATH:-./redis-data}:/data networks: - allstarr-network # Spotify Lyrics API sidecar service # Note: This image only supports AMD64. On ARM64 systems, Docker will use emulation. spotify-lyrics: image: akashrchandran/spotify-lyrics-api:latest platform: linux/amd64 container_name: allstarr-spotify-lyrics restart: unless-stopped ports: - "8365:8080" environment: - SP_DC=${SPOTIFY_API_SESSION_COOKIE:-} networks: - allstarr-network allstarr: # Use pre-built image from GitHub Container Registry # For latest stable: ghcr.io/sopat712/allstarr:latest # For beta/testing: ghcr.io/sopat712/allstarr:beta # To build locally instead, uncomment the build section below image: ghcr.io/sopat712/allstarr:latest # Uncomment to build locally instead of using GHCR image: # build: # context: . # dockerfile: Dockerfile # image: allstarr:local container_name: allstarr restart: unless-stopped ports: - "5274:8080" # Admin UI on port 5275 - for local/Tailscale access only # DO NOT expose through reverse proxy - contains sensitive config - "5275:5275" depends_on: valkey: condition: service_healthy spotify-lyrics: condition: service_started healthcheck: test: ["CMD", "curl", "-f", "http://localhost:8080/health"] interval: 30s timeout: 10s retries: 3 start_period: 40s networks: - allstarr-network environment: - ASPNETCORE_ENVIRONMENT=Production # Backend type: Subsonic or Jellyfin (default: Subsonic) - Backend__Type=${BACKEND_TYPE:-Subsonic} # Admin network controls (port 5275) - Admin__BindAnyIp=${ADMIN_BIND_ANY_IP:-false} - Admin__TrustedSubnets=${ADMIN_TRUSTED_SUBNETS:-} # ===== REDIS / VALKEY CACHE ===== - Redis__ConnectionString=valkey:6379 - Redis__Enabled=${REDIS_ENABLED:-true} # ===== CACHE TTL SETTINGS ===== - Cache__SearchResultsMinutes=${CACHE_SEARCH_RESULTS_MINUTES:-1} - Cache__PlaylistImagesHours=${CACHE_PLAYLIST_IMAGES_HOURS:-168} - Cache__SpotifyPlaylistItemsHours=${CACHE_SPOTIFY_PLAYLIST_ITEMS_HOURS:-168} - Cache__SpotifyMatchedTracksDays=${CACHE_SPOTIFY_MATCHED_TRACKS_DAYS:-30} - Cache__LyricsDays=${CACHE_LYRICS_DAYS:-14} - Cache__GenreDays=${CACHE_GENRE_DAYS:-30} - Cache__MetadataDays=${CACHE_METADATA_DAYS:-7} - Cache__OdesliLookupDays=${CACHE_ODESLI_LOOKUP_DAYS:-60} - Cache__ProxyImagesDays=${CACHE_PROXY_IMAGES_DAYS:-14} - Cache__TranscodeCacheMinutes=${CACHE_TRANSCODE_MINUTES:-60} # ===== SUBSONIC BACKEND ===== - Subsonic__Url=${SUBSONIC_URL:-http://localhost:4533} - Subsonic__ExplicitFilter=${EXPLICIT_FILTER:-ExplicitOnly} - Subsonic__DownloadMode=${DOWNLOAD_MODE:-Track} - Subsonic__MusicService=${MUSIC_SERVICE:-SquidWTF} - Subsonic__StorageMode=${STORAGE_MODE:-Permanent} - Subsonic__CacheDurationHours=${CACHE_DURATION_HOURS:-1} - Subsonic__EnableExternalPlaylists=${ENABLE_EXTERNAL_PLAYLISTS:-true} - Subsonic__PlaylistsDirectory=${PLAYLISTS_DIRECTORY:-playlists} # ===== JELLYFIN BACKEND ===== - Jellyfin__Url=${JELLYFIN_URL:-http://localhost:8096} - Jellyfin__ApiKey=${JELLYFIN_API_KEY:-} - Jellyfin__UserId=${JELLYFIN_USER_ID:-} - Jellyfin__LibraryId=${JELLYFIN_LIBRARY_ID:-} - Jellyfin__ClientUsername=${JELLYFIN_CLIENT_USERNAME:-} - Jellyfin__ExplicitFilter=${EXPLICIT_FILTER:-ExplicitOnly} - Jellyfin__DownloadMode=${DOWNLOAD_MODE:-Track} - Jellyfin__MusicService=${MUSIC_SERVICE:-SquidWTF} - Jellyfin__StorageMode=${STORAGE_MODE:-Permanent} - Jellyfin__CacheDurationHours=${CACHE_DURATION_HOURS:-1} - Jellyfin__EnableExternalPlaylists=${ENABLE_EXTERNAL_PLAYLISTS:-true} - Jellyfin__PlaylistsDirectory=${PLAYLISTS_DIRECTORY:-playlists} # ===== SPOTIFY PLAYLIST INJECTION (JELLYFIN ONLY) ===== - SpotifyImport__Enabled=${SPOTIFY_IMPORT_ENABLED:-false} - SpotifyImport__SyncStartHour=${SPOTIFY_IMPORT_SYNC_START_HOUR:-16} - SpotifyImport__SyncStartMinute=${SPOTIFY_IMPORT_SYNC_START_MINUTE:-15} - SpotifyImport__SyncWindowHours=${SPOTIFY_IMPORT_SYNC_WINDOW_HOURS:-2} - SpotifyImport__MatchingIntervalHours=${SPOTIFY_IMPORT_MATCHING_INTERVAL_HOURS:-24} - SpotifyImport__Playlists=${SPOTIFY_IMPORT_PLAYLISTS:-} - SpotifyImport__PlaylistIds=${SPOTIFY_IMPORT_PLAYLIST_IDS:-} - SpotifyImport__PlaylistNames=${SPOTIFY_IMPORT_PLAYLIST_NAMES:-} - SpotifyImport__PlaylistLocalTracksPositions=${SPOTIFY_IMPORT_PLAYLIST_LOCAL_TRACKS_POSITIONS:-} # ===== SPOTIFY DIRECT API (for lyrics, ISRC matching, track ordering) ===== - SpotifyApi__Enabled=${SPOTIFY_API_ENABLED:-false} - SpotifyApi__SessionCookie=${SPOTIFY_API_SESSION_COOKIE:-} - SpotifyApi__SessionCookieSetDate=${SPOTIFY_API_SESSION_COOKIE_SET_DATE:-} - SpotifyApi__CacheDurationMinutes=${SPOTIFY_API_CACHE_DURATION_MINUTES:-60} - SpotifyApi__RateLimitDelayMs=${SPOTIFY_API_RATE_LIMIT_DELAY_MS:-100} - SpotifyApi__PreferIsrcMatching=${SPOTIFY_API_PREFER_ISRC_MATCHING:-true} # Spotify Lyrics API sidecar service URL (internal) - SpotifyApi__LyricsApiUrl=${SPOTIFY_LYRICS_API_URL:-http://spotify-lyrics:8080} # ===== SCROBBLING (LAST.FM, LISTENBRAINZ) ===== - Scrobbling__Enabled=${SCROBBLING_ENABLED:-false} - Scrobbling__LocalTracksEnabled=${SCROBBLING_LOCAL_TRACKS_ENABLED:-false} - Scrobbling__SyntheticLocalPlayedSignalEnabled=${SCROBBLING_SYNTHETIC_LOCAL_PLAYED_SIGNAL_ENABLED:-false} - Scrobbling__LastFm__Enabled=${SCROBBLING_LASTFM_ENABLED:-false} - Scrobbling__LastFm__ApiKey=${SCROBBLING_LASTFM_API_KEY:-} - Scrobbling__LastFm__SharedSecret=${SCROBBLING_LASTFM_SHARED_SECRET:-} - Scrobbling__LastFm__SessionKey=${SCROBBLING_LASTFM_SESSION_KEY:-} - Scrobbling__LastFm__Username=${SCROBBLING_LASTFM_USERNAME:-} - Scrobbling__LastFm__Password=${SCROBBLING_LASTFM_PASSWORD:-} - Scrobbling__ListenBrainz__Enabled=${SCROBBLING_LISTENBRAINZ_ENABLED:-false} - Scrobbling__ListenBrainz__UserToken=${SCROBBLING_LISTENBRAINZ_USER_TOKEN:-} # ===== DEBUG SETTINGS ===== - Debug__LogAllRequests=${DEBUG_LOG_ALL_REQUESTS:-false} - Debug__RedactSensitiveRequestValues=${DEBUG_REDACT_SENSITIVE_REQUEST_VALUES:-false} # ===== SHARED ===== - Library__DownloadPath=/app/downloads - SquidWTF__Quality=${SQUIDWTF_QUALITY:-FLAC} - SquidWTF__MinRequestIntervalMs=${SQUIDWTF_MIN_REQUEST_INTERVAL_MS:-200} - Deezer__Arl=${DEEZER_ARL:-} - Deezer__ArlFallback=${DEEZER_ARL_FALLBACK:-} - Deezer__Quality=${DEEZER_QUALITY:-FLAC} - Deezer__MinRequestIntervalMs=${DEEZER_MIN_REQUEST_INTERVAL_MS:-200} - Qobuz__UserAuthToken=${QOBUZ_USER_AUTH_TOKEN:-} - Qobuz__UserId=${QOBUZ_USER_ID:-} - Qobuz__Quality=${QOBUZ_QUALITY:-FLAC} - Qobuz__MinRequestIntervalMs=${QOBUZ_MIN_REQUEST_INTERVAL_MS:-200} - MusicBrainz__Enabled=${MUSICBRAINZ_ENABLED:-true} - MusicBrainz__Username=${MUSICBRAINZ_USERNAME:-} - MusicBrainz__Password=${MUSICBRAINZ_PASSWORD:-} volumes: - ${DOWNLOAD_PATH:-./downloads}:/app/downloads - ${KEPT_PATH:-./kept}:/app/kept - ${CACHE_PATH:-./cache}:/app/cache # Mount .env file for runtime configuration updates from admin UI - ./.env:/app/.env # Docker socket for self-restart capability (admin UI only) - /var/run/docker.sock:/var/run/docker.sock:ro networks: allstarr-network: name: allstarr-network driver: bridge