Configuration
Dubby can be configured in multiple ways. When the same setting is defined in multiple places, the highest-priority source wins:
Environment variables β YAML config file β Admin UI / database β Auto-detected values β Defaults
Most users only need environment variables. The YAML file is useful for managing many settings in one place, especially in Docker or Kubernetes.
Environment variables
Section titled βEnvironment variablesβRequired variables are validated at startup β the server will exit with a descriptive error if theyβre missing or invalid.
Required
Section titled βRequiredβ| Variable | Description |
|---|---|
BETTER_AUTH_SECRET | Secret for session signing and stream token HMAC. Min 32 characters. Generate with openssl rand -base64 32. |
DATABASE_URL | SQLite database path. Format: file:/path/to/dubby.db. Set automatically in Docker (file:/data/dubby.db). |
| Variable | Default | Description |
|---|---|---|
PORT | 3000 | HTTP server port |
HOST | 0.0.0.0 | HTTP server bind address |
NODE_ENV | development | production for JSON logs and strict CORS. development for pretty-printed logs and permissive CORS. test for unit tests. |
LOG_LEVEL | info | Log verbosity: debug, info, warn, error |
Storage
Section titled βStorageβ| Variable | Default | Description |
|---|---|---|
DUBBY_DATA_DIR | ./data | Base data directory (database, images, trickplay) |
DUBBY_CACHE_DIR | ./cache | Transcode cache directory (HLS segments) |
DUBBY_METADATA_CACHE_DIR | DUBBY_DATA_DIR/images | Image proxy cache for TMDB artwork |
DUBBY_TRICKPLAY_CACHE_DIR | DUBBY_DATA_DIR/trickplay | Trickplay thumbnail sprites |
DUBBY_TRANSCODES_DIR | ./transcodes | Ahead-of-time transcode output |
DUBBY_LOGS_DIR | ./logs | Log file directory |
DUBBY_STATIC_DIR | β | Web app static files (standalone mode SPA serving) |
For details on whatβs stored where, see Storage & Paths.
External services
Section titled βExternal servicesβ| Variable | Default | Description |
|---|---|---|
REDIS_URL | β | Valkey/Redis URL for background jobs and real-time events. Format: redis://host:port or redis://:password@host:port |
TMDB_API_KEY | β | TMDB API key for metadata. Free at themoviedb.org. Can also be set in the admin UI. |
SENTRY_DSN | β | Sentry DSN for error tracking (optional) |
DATABASE_AUTH_TOKEN | β | Auth token for Turso remote SQLite databases. Only needed if DATABASE_URL uses libsql://. |
Observability
Section titled βObservabilityβ| Variable | Default | Description |
|---|---|---|
DUBBY_METRICS_ENABLED | true | Enable Prometheus /metrics endpoint. Set false to disable. |
Log format is controlled by NODE_ENV β JSON in production, pretty-printed in development. See Monitoring for scrape configuration and available metrics.
Transcoding
Section titled βTranscodingβ| Variable | Default | Description |
|---|---|---|
DUBBY_GPU_ENABLED | true | Enable hardware transcoding when a GPU is available |
See Transcoding for the full list of transcoding environment variables.
Deployment mode
Section titled βDeployment modeβ| Variable | Default | Description |
|---|---|---|
DUBBY_MODE | standalone | standalone (HTTP + workers), api (HTTP only), worker (workers only) |
DUBBY_QUEUES | all | Comma-separated list of enabled queue names. Useful for partitioning work across specialized workers. |
Available queues: scan, ingest-prepare, ingest-enrich, ingest-enhance, analyze, metadata, subtitle, detect-intros, optimize, optimize-orchestrator, system, backup, migration
Security
Section titled βSecurityβ| Variable | Default | Description |
|---|---|---|
DUBBY_ENCRYPTION_KEY | auto-generated | Encryption key for sensitive config values (API keys stored in DB). Min 32 chars. Auto-generated and saved to DUBBY_DATA_DIR/.encryption-key if not set. |
Example .env file
Section titled βExample .env fileβ# RequiredBETTER_AUTH_SECRET=your-secret-here-at-least-32-chars
# Optional: metadata (can also be set in admin UI)TMDB_API_KEY=your-tmdb-api-key
# Optional: job queue (recommended)REDIS_URL=redis://valkey:6379
# Optional: loggingLOG_LEVEL=infoValkey/Redis behavior
Section titled βValkey/Redis behaviorβIf REDIS_URL is set but the connection fails, the server logs a warning and continues without the job system:
WARN Failed to connect to Redis/Valkey β job queue disabledPlayback and browsing continue working. Background tasks (scanning, metadata, subtitles) are paused until the connection is restored.
YAML configuration file
Section titled βYAML configuration fileβFor managing many settings at once, Dubby supports a YAML configuration file. This is especially useful in Docker or Kubernetes where you can mount a config file into the container.
File location
Section titled βFile locationβDubby looks for the config file in this order:
- Path specified by
DUBBY_CONFIG_FILEenvironment variable /config/dubby.yaml(Docker default)./dubby.yaml(current working directory)
In Docker Compose, mount a config file:
volumes: - ./dubby.yaml:/config/dubby.yaml:roIn Kubernetes, use a ConfigMap:
volumes: - name: config configMap: name: dubby-configcontainers: - volumeMounts: - name: config mountPath: /configSensitive values
Section titled βSensitive valuesβAPI keys and secrets cannot be set in the YAML file β use environment variables or the admin UI for these:
DUBBY_TMDB_API_KEYDUBBY_TVDB_API_KEYDUBBY_MDBLIST_API_KEYDUBBY_OPENSUBTITLES_API_KEYDUBBY_LICENSE_KEY
Reference
Section titled βReferenceβThe full config file with all available settings and their defaults. Uncomment and change as needed. Each key shows the corresponding DUBBY_* environment variable.
# ββ Session ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
session: # maxTranscodesPerUser: 1 # 1β10 DUBBY_MAX_TRANSCODES_PER_USER # maxTranscodesGlobal: # 1β32, auto-detected DUBBY_MAX_TRANSCODES_GLOBAL # idleTimeoutMs: 120000 # 10sβ10min DUBBY_SESSION_IDLE_TIMEOUT_MS # seekDebounceMs: 150 # 50β1000ms DUBBY_SESSION_SEEK_DEBOUNCE_MS # processGracePeriodMs: 5000 # 1sβ30s DUBBY_SESSION_PROCESS_GRACE_PERIOD_MS # reaperIntervalMs: 10000 # 5sβ60s DUBBY_SESSION_REAPER_INTERVAL_MS # tombstoneRetentionMs: 1800000 # 1minβ2hr DUBBY_SESSION_TOMBSTONE_RETENTION_MS # statsIntervalMs: 60000 # 10sβ5min DUBBY_SESSION_STATS_INTERVAL_MS # firstSegmentTimeoutMs: 90000 # 10sβ5min DUBBY_SESSION_FIRST_SEGMENT_TIMEOUT_MS # noProgressTimeoutMs: 120000 # 10sβ5min DUBBY_SESSION_NO_PROGRESS_TIMEOUT_MS
# ββ Transcoding ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
transcoding: # gpuEnabled: true # GPU hardware accel DUBBY_GPU_ENABLED # multiQualityEnabled: true # Multi-quality ABR DUBBY_MULTI_QUALITY # maxQualityTiers: 4 # 1β6 DUBBY_MAX_QUALITY_TIERS # defaultCrf: 23 # 0β51, lower=better DUBBY_TRANSCODING_DEFAULT_CRF # defaultPreset: fast # ultrafast..veryslow DUBBY_TRANSCODING_DEFAULT_PRESET # hlsSegmentDuration: 4 # 2β10 seconds DUBBY_TRANSCODING_HLS_SEGMENT_DURATION # diskWarningThresholdGB: 10 # 1β1000 GB DUBBY_TRANSCODING_DISK_WARNING_THRESHOLD_GB # diskCriticalThresholdGB: 2 # 1β100 GB DUBBY_TRANSCODING_DISK_CRITICAL_THRESHOLD_GB # maxCacheSizePerUserGB: 20 # 1β1000 GB DUBBY_TRANSCODING_MAX_CACHE_SIZE_PER_USER_GB # maxTotalCacheSizeGB: 100 # 1β10000 GB DUBBY_TRANSCODING_MAX_TOTAL_CACHE_SIZE_GB
# ββ Library ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
library: # ingestConcurrency: # 1β20, auto-detected DUBBY_INGEST_CONCURRENCY # watcherPollIntervalMs: 5000 # 1sβ30s DUBBY_LIBRARY_WATCHER_POLL_INTERVAL_MS # metadataRetryIntervalMs: 3600000 # 1minβ24hr DUBBY_LIBRARY_METADATA_RETRY_INTERVAL_MS # fileStableChecks: 3 # 1β10 DUBBY_LIBRARY_FILE_STABLE_CHECKS
# ββ Rate Limiting ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
rateLimit: # loginMaxAttempts: 5 # 1β100 DUBBY_RATE_LIMIT_LOGIN_MAX_ATTEMPTS # loginWindowMs: 900000 # 10sβ24hr (15min) DUBBY_RATE_LIMIT_LOGIN_WINDOW_MS # registerMaxAttempts: 3 # 1β100 DUBBY_RATE_LIMIT_REGISTER_MAX_ATTEMPTS # registerWindowMs: 3600000 # 10sβ24hr (1hr) DUBBY_RATE_LIMIT_REGISTER_WINDOW_MS # refreshMaxAttempts: 10 # 1β100 DUBBY_RATE_LIMIT_REFRESH_MAX_ATTEMPTS # refreshWindowMs: 60000 # 10sβ24hr (1min) DUBBY_RATE_LIMIT_REFRESH_WINDOW_MS # apiMaxRequests: 100 # 1β10000 DUBBY_RATE_LIMIT_API_MAX_REQUESTS # apiWindowMs: 60000 # 10sβ24hr (1min) DUBBY_RATE_LIMIT_API_WINDOW_MS
# ββ Server βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
server: # allowedOrigins: [] # CORS origins (JSON) DUBBY_SERVER_ALLOWED_ORIGINS # transcodeDir: /tmp/dubby/transcode DUBBY_SERVER_TRANSCODE_DIR # ssePingIntervalMs: 30000 # 5sβ120s DUBBY_SERVER_SSE_PING_INTERVAL_MS
# ββ UI βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
ui: # accentColor: sky # DUBBY_ACCENT_COLOR # titleDisplayMode: logo # logo|text|hidden DUBBY_TITLE_DISPLAY_MODE # allowUserAccentOverride: false # DUBBY_ALLOW_USER_ACCENT_OVERRIDE
# ββ Privacy ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
privacy: # level: private # maximum|private|balanced|open DUBBY_PRIVACY_LEVEL # allowExternalConnections: false # DUBBY_ALLOW_EXTERNAL # localAnalyticsEnabled: true # DUBBY_PRIVACY_LOCAL_ANALYTICS # anonymousSharingEnabled: false # DUBBY_PRIVACY_ANONYMOUS_SHARING # tmdbEnabled: false # DUBBY_PRIVACY_TMDB_ENABLED # tmdbProxyImages: true # DUBBY_PRIVACY_TMDB_PROXY_IMAGES # opensubtitlesEnabled: false # DUBBY_PRIVACY_OPENSUBTITLES_ENABLED # maskFilePaths: true # DUBBY_PRIVACY_MASK_FILE_PATHS # maskMediaTitles: true # DUBBY_PRIVACY_MASK_MEDIA_TITLES # maskUserInfo: true # DUBBY_PRIVACY_MASK_USER_INFO # maskIpAddresses: true # DUBBY_PRIVACY_MASK_IP_ADDRESSES # analyticsRetentionDays: null # days, null=indefinite DUBBY_PRIVACY_ANALYTICS_RETENTION_DAYS # auditRetentionDays: null # days, null=indefinite DUBBY_PRIVACY_AUDIT_RETENTION_DAYS
# ββ Optimization βββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
optimization: # enabled: false # DUBBY_OPTIMIZATION_ENABLED # maxResolution: 4k # 4k|1080p DUBBY_OPTIMIZATION_MAX_RESOLUTION # encodingPriority: balanced # quality|balanced|speed DUBBY_OPTIMIZATION_ENCODING_PRIORITY # hdrDisplays: false # DUBBY_OPTIMIZATION_HDR_DISPLAYS # remoteStreaming: false # DUBBY_OPTIMIZATION_REMOTE_STREAMING # uploadSpeedMbps: 0 # 0=not set DUBBY_OPTIMIZATION_UPLOAD_SPEED_MBPS # simultaneousStreams: 1 # 1β10 DUBBY_OPTIMIZATION_SIMULTANEOUS_STREAMS # storageMode: cache_dir # cache_dir|alongside DUBBY_OPTIMIZATION_STORAGE_MODE # storagePath: "" # DUBBY_OPTIMIZATION_STORAGE_PATH # storageBudgetGb: 0 # 0=unlimited DUBBY_OPTIMIZATION_STORAGE_BUDGET_GB # replaceOriginals: false # DUBBY_OPTIMIZATION_REPLACE_ORIGINALS # autoOptimizeOnIngest: false # DUBBY_OPTIMIZATION_AUTO_OPTIMIZE_ON_INGEST # retentionMode: keep_originals # keep_originals|archive_local|replace_originals # # DUBBY_OPTIMIZATION_RETENTION_MODE # archivePath: "" # DUBBY_OPTIMIZATION_ARCHIVE_PATH # primaryLanguage: en # DUBBY_OPTIMIZATION_PRIMARY_LANGUAGE # keepOriginalLanguage: true # DUBBY_OPTIMIZATION_KEEP_ORIGINAL_LANGUAGE # additionalLanguages: [] # DUBBY_OPTIMIZATION_ADDITIONAL_LANGUAGES # encodingProfile: "" # DUBBY_OPTIMIZATION_ENCODING_PROFILE # deviceCategories: [] # apple_tv|android_tv|roku|smart_tvs|ios_devices| # # android_mobile|web_browsers|playstation|xbox| # # mac|windows|fire_tv_vega # # DUBBY_OPTIMIZATION_DEVICE_CATEGORIES # audioEnvironments: {} # {"name": "home_theater"|"soundbar"|"tv_speakers"} # # DUBBY_OPTIMIZATION_AUDIO_ENVIRONMENTS # subtitleLanguages: [] # DUBBY_OPTIMIZATION_SUBTITLE_LANGUAGES
# ββ Providers ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
providers: # displayMovieProvider: tmdb # DUBBY_PROVIDERS_DISPLAY_MOVIE_PROVIDER # displayTvProvider: tmdb # DUBBY_PROVIDERS_DISPLAY_TV_PROVIDER # enabledRatingSources: [imdb, rt_critics] DUBBY_PROVIDERS_ENABLED_RATING_SOURCES # ratingSourceOrder: null # custom order or null DUBBY_PROVIDERS_RATING_SOURCE_ORDER