Configuration
Override Lyra's settings with a configuration file.
Configuration is optional; most settings can be changed from the web interface.
Use a configuration file
Section titled “Use a configuration file”Create config.json beside compose.yaml before mounting it; otherwise Docker creates a directory in its place. For example, to refresh metadata from providers every hour:
{ "sync": { "interval_secs": 3600 }}Add this line under volumes in the lyra service:
- ./config.json:/config.json:roRun docker compose up -d to apply it. After editing the file later, run docker compose restart.
Settings in this file override saved settings. Remove a setting from the file to allow it to be changed from Lyra again.
Reset saved settings
Section titled “Reset saved settings”If Lyra cannot start because a saved setting is invalid, stop it and reset its settings:
docker compose stopdocker compose run --rm lyra settings resetThis clears all saved server settings. It does not remove values from config.json. Start Lyra again with docker compose up -d.
Create a library at startup
Section titled “Create a library at startup”To create and scan a library when Lyra starts, add a library block:
{ "library": { "path": "/music", "name": "Music", "language": "en", "country": "US" }}Use a path visible to the server. path is required. name defaults to Music. language and country are optional; language accepts ISO 639-1 or 639-3 codes or English names, and country accepts country codes or names.
Advanced reference
Section titled “Advanced reference”File loading and defaults
Section titled “File loading and defaults”- Lyra searches for
config.jsonin the working directory, beside the binary, and in the binary’s parent directory.LYRA_CONFIG_PATHselects an exact file; it must exist. - Unknown keys and invalid values prevent startup. The error identifies the problem.
portanddbare startup options. Other settings use the file value first, then the saved value, then the default.- In the file,
nullexplicitly unsetspublished_urlorhls.temp_disk_budget_bytes. Other settings rejectnull, except startup options, which treat it as omitted. - Most setting changes apply immediately.
rate_limit.*andhls.cleanup_startup_purgerequire a restart.
Environment variables
Section titled “Environment variables”| Variable | Default | Purpose |
|---|---|---|
LYRA_CONFIG_PATH |
searched | Explicit path to config.json; must exist when set |
LYRA_DATA_DIR |
./data |
Root for server-owned state; created when serving |
LYRA_DB_DIR |
data dir | Directory for relative db.path values; created when serving |
LYRA_PORT |
4746 |
Listening port; overrides port from the file |
LYRA_PLUGINS_DIR |
./plugins |
Directory plugins are loaded from; created when serving |
LYRA_STATIC_DIR |
searched | Directory for static web assets; must be a directory when set |
RUST_LOG |
lyra_server=info,tower_http=debug,harmony_core=info |
Log filter; request logs name query parameters without their values, which log at lyra::http::query=trace only when that target is named |
Docker uses /data and /plugins; update their mounts if you change these paths. For a frontend override, see custom web interface.
Full configuration example
Section titled “Full configuration example”Copy config.example.json to config.json, keeping only your overrides.
published_urlaccepts a public HTTP or HTTPS origin, such ashttps://music.example.com.covers_pathis relative to the data directory.db.pathis relative toLYRA_DB_DIR, or the data directory when unset.instance_statsshows users averages computed across all users, such as average ratings. When off, genre covers also follow only the user’s own listens.db.kindacceptsmmap,file, ormemory.memorynever writes the database to disk.- Durations are in seconds.
sync.interval_secssets how often provider metadata is refreshed;0disables periodic refreshes, but one still runs at startup. - The HLS disk budget is in bytes;
nullor0means no budget. plugins.auto_updateinstalls plugin updates the daily check finds unless they need approval; see automatic updates.- Transcoded audio is cached briefly in
transcodesunder the data directory, which is emptied at startup.transcoding.cache_max_bytesbounds its size (a larger transcode is still served, just not kept) andtranscoding.cache_ttl_secondsremoves transcodes not requested for that long. No new transcode starts while that disk has less than 1 GiB free; such requests get503 Service UnavailablewithRetry-After. - Resized or converted covers are kept in
cover-transformsunder the data directory;covers.transform_cache_max_bytesbounds its size (512 MiB by default), oldest evicted first. A cover’s entries go when the cover does. rate_limit.*limits requests per caller. A request with a session or API key, or a download with itsmedia_token, counts against that credential, and every credential of one user together gets four timesglobal_per_minute; any other request counts against its client address (each IPv6 /64), read fromX-Forwarded-For,ForwardedorX-Real-IPonly when the peer is one ofrate_limit.trusted_proxies. With authentication disabled every request counts against its address. Each caller getsglobal_per_minute, and a credential’s API calls, besides covers and downloads, alsoauthenticated_per_minute. Plugin routes authenticate their own way, so they are limited per client address./api/streamis not request-limited; transcoding limits bound it instead. Login attempts getlogin_per_minuteper client address. A request over a limit gets429 Too Many RequestswithRetry-After.transcoding.max_concurrentcaps encodes across HLS, streams and downloads, andtranscoding.max_concurrent_per_usercaps one user’s stream and download encodes;0means no limit. Anonymous requests get a per-user allowance for each client address (each IPv6 /64), and together at most half oftranscoding.max_concurrent, rounded down. A stream or download over a limit gets429 Too Many RequestswithRetry-After; HLS waits up to ten seconds for a free slot first. Serving an original file or a cached transcode is never limited.