No description
  • JavaScript 100%
Find a file
2026-07-31 14:25:03 +02:00
.env.example Lyrics using standard logging 2026-07-31 11:02:49 +02:00
.gitignore First Commit 2026-07-31 10:35:57 +02:00
ecosystem.config.js First Commit 2026-07-31 10:35:57 +02:00
index.js Lyrics using standard logging 2026-07-31 11:02:49 +02:00
package-lock.json First Commit 2026-07-31 10:35:57 +02:00
package.json First Commit 2026-07-31 10:35:57 +02:00
README.md changed 2026-07-31 14:25:03 +02:00
sqliteLyrics.js changed 2026-07-31 14:25:03 +02:00

lyrcisApi

Small local API wrapping the LRCLIB lyrics sqlite dump. See index.js/sqliteLyrics.js for what it does; this document only covers getting the code onto gitlab.loener.nl and then onto wherever it actually runs (its own Proxmox LXC).

Part 1 — Create the repository and push (this machine)

1.1 Create the repository on gitlab.loener.nl

Do:

  • Create it empty - no README, no .gitignore, no license auto-added by GitLab. This project already exists locally with its own files; an auto-initialized remote gives it a divergent commit history that just causes merge pain on the first push.
  • Match the existing naming convention (jellyfinPlayer, Standard) - use lyrcisApi as the project name, under the gerrit namespace/group, so the remote URL ends up https://gitlab.loener.nl/gerrit/lyrcisApi.git.
  • Set visibility to Private. This is personal infrastructure, not a public project.
  • Before the first commit, double check .gitignore actually excludes what it should:
    node_modules/
    .env
    *.log
    *sqlite3*
    
    (already in place here - git status should never show .env or a .sqlite3 file as untracked/staged. If it does, stop and fix .gitignore before committing.)

Don't:

  • Don't tick "Initialize repository with a README" when creating it in the GitLab UI.
  • Don't commit .env (real API_KEY, real LYRCLIB_DUMP_PATH) - only .env.example should ever be tracked.
  • Don't commit the LRCLIB sqlite dump or its .gz - it's ~30-120GB, and it doesn't belong in git history regardless of size (it's a downloaded artifact, not source).
  • Don't grant a token more scope than it needs when you get to Part 2 - write_repository is enough to push from here; the receiving end only ever needs to pull.

1.2 Push the existing local project

cd development/lyrcisApi

git init
git add .
git status   # verify: no .env, no node_modules/, no *.sqlite3* listed
git commit -m "Initial commit"
git branch -M main

git remote add origin https://gitlab.loener.nl/gerrit/lyrcisApi.git
git push -u origin main

If push prompts for credentials, use your GitLab username and a Personal Access Token (Settings → Access Tokens) with write_repository scope - not your account password.

Part 2 — Receiving end (e.g. the lyrcisApi LXC)

2.1 Set up global git authentication

The goal: authenticate against gitlab.loener.nl once, globally, so every future git clone/git pull on this machine (not just this one repo) just works - useful on a single-purpose LXC that isn't going to be logged into interactively very often.

  1. On gitlab.loener.nl, create a Personal Access Token for this machine (Settings → Access Tokens) with read_repository scope only - this box only needs to pull, never push.

  2. Set your git identity globally (needed for any commits made on this machine, e.g. local config changes):

    git config --global user.name "gerrit"
    git config --global user.email "gerrit.kuilder@gmail.com"
    
  3. Enable the credential store globally, then authenticate once:

    git config --global credential.helper store
    git clone https://gitlab.loener.nl/gerrit/lyrcisApi.git
    

    Git will prompt for a username/password on this first clone - enter your GitLab username and the Personal Access Token as the password. It's then cached in ~/.git-credentials for every future gitlab.loener.nl repo on this machine, with no further prompts.

    Note credential.helper store saves the token in plaintext in ~/.git-credentials. That's an acceptable tradeoff on a single-purpose LXC only you have access to; lock it down regardless:

    chmod 600 ~/.git-credentials
    

    Alternative: if you'd rather not have a token on disk at all, use an SSH key pair instead (ssh-keygen, add the public key under gitlab.loener.nl → Settings → SSH Keys) and clone via git@gitlab.loener.nl:gerrit/lyrcisApi.git. Skip step 3 above if you go this route.

2.2 Pull the repository and configure it

index.js requires the shared logger from standard/controllers/logger.js (gitlab.loener.nl/gerrit/Standard), loaded via a relative path (../standard/...) - so standard must be cloned as a sibling of lyrcisApi, same as on this machine. If it's missing, the app fails immediately on startup with Cannot find module.

# both repos side by side, e.g. under the same parent directory:
git clone https://gitlab.loener.nl/gerrit/Standard.git standard
git clone https://gitlab.loener.nl/gerrit/lyrcisApi.git
cd lyrcisApi
npm install
cp .env.example .env
# then edit .env:
#  - PORT, LYRCLIB_DUMP_PATH (path to the extracted dump on this machine)
#  - API_KEY (required here - this box is LAN-exposed)
#  - APP, VHOST (used by the shared logger - APP=lyrcisApi, VHOST=exchange for prod)

The logger also expects RABBIT_HOST/RABBIT_USER/RABBIT_PASSWORD to be resolvable from standard's own env-loading chain (it walks up from standard/controllers/ looking for a shared root .env) - without RabbitMQ reachable, logging still works locally, it just can't forward to the central log stream (each log call prints a "Error publishing to Rabbit Stream" line and otherwise continues normally).

For subsequent updates, from inside the repo:

git pull
npm install   # only if package.json changed

Enhancement (not yet implemented): efficient dump updates

LRCLIB's dump grows over time and lyrcisApi currently runs off a single static snapshot (the local dump only has what was in the bulk export the day it was downloaded - see Track Moods page discrepancies where a track is found via the live LRCLIB API fallback but not via lyrcisApi's own dump). Refreshing periodically closes that gap. Not built yet - notes for when it is:

Check for a newer dump without downloading it:

  • curl -sI <lrclib-dump-url> and compare Content-Length/Last-Modified (or the filename's embedded timestamp, matching the lrclib-db-dump-YYYYMMDDTHHMMSSZ.sqlite3 pattern already in use) against the currently installed dump. Only proceed if newer.

Download + extract without doubling disk usage:

  • Stream the decompression instead of saving the .gz to disk first: curl -L <url> | gunzip > lrclib-db-dump-<new-timestamp>.sqlite3. This avoids ever storing the ~30GB compressed file alongside the ~125GB extracted one, roughly halving the peak disk footprint of a refresh compared to download-then-extract as two steps.
  • Keep the new file under its own timestamped name - don't overwrite the old one until it's verified working (see below).

Switch between old and new dump quickly, with instant rollback:

  • Never point LYRCLIB_DUMP_PATH at a versioned filename directly. Point it at a stable symlink instead, e.g. LYRCLIB_DUMP_PATH=/mnt/lyrics-nas/current.sqlite3 where current.sqlite3 is a symlink to the real, timestamped file (see NAS plan below - this symlink lives on the NAS mount, not on the LXC's own disk).
  • To switch: ln -sfn lrclib-db-dump-<new-timestamp>.sqlite3 current.sqlite3 (atomic - the symlink flips in one step, no window where the path is missing), then pm2 restart lyrcisApi - node:sqlite holds the file open by inode, so a running process won't notice the symlink changed underneath it without a restart.
  • Rollback is just as fast if the new dump turns out bad: repoint the symlink back to the old file and restart again.
  • Only delete the old dump once the new one's been spot-checked (a few /health + /lyrics requests that should hit) - it's your rollback safety net until then.

Storage plan: NAS-backed instead of local LXC disk. Rather than sizing the LXC's own disk for the dump (see the math below - it's tight), the plan is to keep the dump on the UGREEN NAS (effectively no size limit there) and mount it through: NAS share → mounted on the Proxmox host → bind-mounted into the LXC. This means old+new dumps can coexist during a swap for free, and the LXC's own disk only needs to cover the OS, Node, and logs - a modest 20-30GB is plenty.

Do:

  • Prefer NFS over SMB/CIFS for the NAS share if the UGREEN supports it - it's the more natural fit for a Linux Proxmox host and a Linux LXC, with less protocol overhead than SMB for this kind of large-sequential-read workload.
  • Mount the share on the Proxmox host first (e.g. via /etc/fstab with the _netdev option, so the boot sequence waits for networking before attempting the mount - a NAS mount attempted too early just fails silently otherwise), then expose it into the LXC as a proper Proxmox mount point (pct set <vmid> -mp0 /mnt/nas-share,mp=/mnt/lyrics-nas or the equivalent block in /etc/pve/lxc/<vmid>.conf) rather than bind-mounting inside the container by hand - this way Proxmox tracks it and remounts it correctly on container restart.
  • After mounting, verify the LXC can actually read the share before relying on it - for an unprivileged LXC (Proxmox's default), the UID/GID the container sees a file as depends on its user namespace mapping, and a share mounted as root on the host can end up looking like nobody/unreadable inside the container. Test with a plain cat/ls from inside the LXC, not just from the host.
  • Lean on the existing checkDatabase() startup check (see index.js) as a cheap canary: if the NAS mount isn't up yet when lyrcisApi starts, it logs Database NOT found at ... clearly instead of crashing - useful signal if the mount and the app start racing each other on boot.

Don't:

  • Don't treat this as a read-write database over the network. SQLite's own docs warn that file locking on network filesystems (NFS in particular) can be unreliable, which matters for concurrent writers. This is opened readOnly: true in sqliteLyrics.js, which sidesteps most of that risk (no write-lock coordination needed) - keep it that way. Never point a writer (e.g. a future dump-rebuild job) at the same path concurrently with the running API without locking that's actually verified safe on this NAS/NFS combination.
  • Don't skip _netdev (or the LXC-boot equivalent) - a mount that isn't there yet at boot is a much easier problem to diagnose via checkDatabase()'s log line than a container that silently starts with a stale or empty directory at the mount point.
  • Don't forget the mount is a new dependency for uptime: if the NAS reboots or the network path to it drops, lyrics lookups fail even though the LXC itself is fine. Not necessarily a reason not to do this (the "basically no size limit" tradeoff is worth it here), just worth knowing that's now part of the failure surface.

Disk sizing: With the dump living on the NAS mount, the LXC's own disk no longer needs to hold it at all - 20-30GB covers the OS, Node, node_modules, and logs comfortably, with no need to plan around dump growth on that volume ever again. The NAS share itself just needs enough free space for old+new dumps to coexist during a swap (~250GB at today's sizes, growing over time) - trivial against "basically no size limit," but still worth a periodic sanity check that old, superseded dump versions actually get cleaned up rather than accumulating indefinitely.

Improving search

Api details (so for when calling their api) Attempt to find the best match of lyrics for the track. You must provide the exact signature of the track, including the track title, artist name, album name, and the track's duration in seconds.

Each time you request a new track's signature, this API will attempt to access external sources in case the lyrics are not found in the internal database. Therefore, the response time will vary significantly.

Running on baremetal:

LRCLIB_LOG=info \
LRCLIB_MMAP_SIZE=23622320128 \
LRCLIB_CACHE_SIZE=-2097152 \
cargo run --release -- serve --database db.sqlite3 --workers-count <TOTAL_CPU_CORES>
  1. The Bare Metal Optimization ScriptYou should scale down the default 30GB MMAP size slightly to strictly respect the system's "75% of total RAM" safety limit. Use these exact environment parameters:

AI Mode conversation: LRCLIBLRCLIBQuick results from the web:LRCLIB — Free & Open Lyrics LibraryDownload LRCGET API Documentation Database Dumps Source Code. Support LRCLIBHelp keep this free lyrics library running. Lyricsfile formatNewAn open, YAML-based lyrics format with word-sync support.LRCLIB·https://lrclib.netGitHub - dinoosauro/lrclib-get: A simple website that is able to ...A simple website that is able to download synced and plain lyrics of your local songs from LRCLib. Try it: https://dinoosauro.github.io/lrclib-get/ · Screenshot of the website ...GitHub·https://github.comLRCLIB is a completely free, open-source, and community-driven database focused on collecting and sharing both plain (unsynced) and synchronized (.lrc) song lyrics.Because it operates with an entirely public API that requires no registration or API keys, it has quickly become a popular, lightweight backend for third-party music players, self-hosted media managers, and open-source plugins.🌟 Key FeaturesDual Mode Lyrics: Provides standard plain text lyrics alongside perfectly timed, synchronized lyrics.No Authentication Required: Developers can utilize the database instantly without registering for tokens or hitting restrictive paywalls.Zero Rate-Limiting: The public beta API is open to all applications with no strict rate restrictions in place.Instrumental Support: Gracefully marks and handles audio files that lack vocals entirely.Crowdsourced Database: Anyone can anonymously publish or update existing timed lyrics to improve accuracy.🛠️ Official & Popular IntegrationsLRCLIB is natively supported or heavily integrated into many media workflows:LRCGET: The official desktop companion utility designed to mass-download .lrc files directly into your local music directories.MusicBee (LRCLIBee Plugin): Automatically fetches and aligns synchronized scrolling text inside the MusicBee media player.MusicBrainz Picard: Features a dedicated LRCLIB Lyrics Plugin to embed lyrics directly into audio metadata tags during music management.Foobar2000: Supported via the OpenLyrics component to pull live timed text as tracks play.Home Assistant: Used by self-hosted smart home setups to display scrolling text on dashboard media cards.💻 Developer ResourcesIf you are a developer looking to use LRCLIB or host your own variant, you can use the following open-source packages:Official API Docs: Read the full formatting specifications via the LRCLIB API Documentation.Rust Backend: Host your own clone with the Rust + SQLite3 LRCLIB Server Source Code.Language Wrappers: Use type-safe ecosystems like the TypeScript API Wrapper or the Haskell Client Library.Are you looking to integrate LRCLIB into a specific app, or are you searching for a tool to download lyrics for your offline music library? Let me know so I can point you to the exact setup guide!AI responses may include mistakes. Learn moreLRCLIBAPI Documentation - LRCLIBPublish a new lyrics ... Note: This API is experimental and subject to potential changes in the future. Publish a new lyrics to LR...LRCLIBLRCLIB — Free & Open Lyrics LibraryDownload LRCGET API Documentation Database Dumps Source Code. Support LRCLIBHelp keep this free lyrics library running. Lyricsfile...Reddit·r/LearnJapaneseLRCLIB is an open-source collection of synchronized song lyrics4 Dec 2025 — LRCLIB is an open-source collection of synchronized song lyrics. ... This site is only a couple of years old, and I haven't seen m...Show allI have copied the database and qurey it locally and see a lot of misses for certain tracks/artists example: "Around 'n' Around" - Jazzamor and I wonder if this has to do with the search terms or that the lyrics are not availableThe misses you are experiencing are a combination of strict search parameters and database availability gaps.Because the LRCLIB database is community-driven, smaller or niche artists—such as Jazzamor—often have lower coverage compared to mainstream acts. Additionally, the way you format your query inside the SQLite3 local clone can completely hide existing records.Understanding how formatting issues hide your data and how to adjust local queries can help uncover missed tracks.🔍 1. Common Query ObstaclesWhen querying the SQLite database directly, minor formatting mismatches can cause a track to register as a "miss," even if the data is present:Punctuation & Character Variance: For the track you mentioned, it is often stylized across various metadata sources as:Around 'n' AroundAround 'N' AroundAround'n'aroundAround N' AroundAround & AroundStrict LIKE Queries: If your local query relies on an exact WHERE track_name = 'Around 'n' Around', any of the variations above will fail to match.Duration Enforcement: The official LRCLIB search logic heavily weights track durations. If your local logic enforces a strict duration check, a difference of just 2 seconds between your local media file and the database entry will cause a "miss".🛠️ 2. Optimizing Your Local QueriesTo rule out search formatting as the culprit, write more forgiving queries against your SQLite clone. Instead of strict matching, use string sanitization and flexible patterns:A. The Sanitized LIKE ApproachStrip out specialized quotation marks, apostrophes, and spaces to see if the track appears:sqlSELECT * FROM lyrics WHERE LOWER(artist_name) LIKE '%jazzamor%' AND (LOWER(track_name) LIKE '%around%around%' OR LOWER(track_name) LIKE '%around%n%around%'); Use code with caution.B. Mimicking the Official API LogicThe official LRCLIB Search API accepts a broad q parameter that checks across all text fields (title, artist, and album) combined. You can replicate this generalized lookup locally:sqlSELECT * FROM lyrics WHERE (track_name || ' ' || artist_name || ' ' || album_name) LIKE '%jazzamor around%'; Use code with caution.📊 3. Verifying Database GapsIf you execute loose LIKE queries against your database clone and still return zero records, the lyrics do not exist in that specific database dump.Because LRCLIB is fully crowdsourced, its library is built entirely on what users manually sync and submit. Niche lounge, bossa nova, or electronic artists like Jazzamor have very fragmented coverage across community databases compared to platforms like Genius or Musixmatch.💡 What to do next?If you find the track is truly missing from your database, you can use the official desktop client LRCGET. It includes a creator interface that allows you to easily paste text lyrics (e.g., from Genius), time-sync them with your local audio file, and upload them back to the central LRCLIB repository. Your next database sync will then include the fresh entry.Are you running these queries through a custom script (Python, Node.js), or are you looking for a way to automatically fall back to online APIs when your local DB misses? Tell me your stack so we can patch the gaps!AI responses may include mistakes. Learn moreLRCLIBAPI Documentation - LRCLIBSearch for lyrics records. GET. /api/search. Search for lyrics records using keywords. This API returns an array of lyrics records...GeniusJazzamor – Around N' Around Lyrics - GeniusNight is wrapped around us. Moonlight shining bright. Stars are in the darkness. Nothing seems alive. You make my heart sing. Like...GitHub[FEATURE REQUEST] Integrate lrclib.net as a lyric source · Issue #14615 Jul 2024 — Description. ... lrclib.net is open-source and has a free API to get music lyrics from it. It powers lrcget which is great for loc...Show allAre there docker images that can be set up?Yes, there are lightweight Docker solutions available for both hosting your own LRCLIB instance and mass-downloading lyrics using its tools.🌐 1. Hosting an LRCLIB Server (Official)The official LRCLIB server backend is written in Rust and provides an official Docker image to host your own instance locally.Docker CLI Setupbashdocker run -d
--name lrclib-server
-p 8080:8080
-v ./lrclib-data:/data
-e DATABASE_URL=sqlite:///data/lrclib.db
tranxuanthang/lrclib:latest Use code with caution.Docker Compose Setup (docker-compose.yml)yamlservices: lrclib: image: tranxuanthang/lrclib:latest container_name: lrclib-server ports: - "8080:8080" volumes: - ./data:/data environment: - DATABASE_URL=sqlite:///data/lrclib.db - PORT=8080 restart: unless-stopped Use code with caution.📥 2. Mass-Downloading Lyrics (LRCGET via Docker)If your goal is to have a container continuously scan your local music folders and automatically pull .lrc files from the public LRCLIB database, you can use the headless Docker version of LRCGET.Docker Compose Setup (docker-compose.yml)yamlservices: lrcget: image: ghcr.io/tranxuanthang/lrcget:latest container_name: lrcget ports: - "8000:8000" volumes: - /path/to/your/music:/music - ./lrcget-config:/config restart: unless-stopped Use code with caution.How to use it: Once running, open http://localhost:8000 in your web browser. It gives you a clean web GUI where you can map your /music folder, batch-scan your library, and fix any "misses" or incorrect entries manually.🛠️ 3. Importing Your Local Database DumpIf you want your self-hosted server to use the database dump you already copied:Stop your running container.Replace the automatically generated lrclib.db file inside your mapped ./data directory with your existing database file.Rename your file to lrclib.db.Start the container again.Are you looking to hook this setup into a specific media server like Jellyfin, Plex, or Navidrome? Let me know so I can give you the exact integration steps!AI responses may include mistakes. Learn moreTechTargetUse Docker and Alpine Linux to build lightweight containers28 Oct 2020 — Use Docker and Alpine Linux to build lightweight containers Alpine Linux won't always be the right OS choice for IT teams, but it'groundcoverTop 12 Docker Alternatives in 2026: Features & Comparisons12 Feb 2026 — Lightweight tooling Some Docker alternatives are distinguished by their focus on being lightweight and consuming fewer resources t...DEV CommunityContainerizing a Three-Tier Application with Docker: A Hands-On Guide25 Dec 2024 — Setting Up the Environment Before we begin, make sure you have the following prerequisites installed: Docker Docker Compose The Ma...Show allYou sent: 1 tab and said: So I downloaded and installed this repo: https://github.com/tranxuanthang/lrclibI was expecting a web interface on that port and of the serverGitHub - tranxuanthang/lrclib: LRCLIB server written in Rust with Axum and SQLite3 database · GitHubSo I downloaded and installed this repo: https://github.com/tranxuanthang/lrclibI was expecting a web interface on that port and of the serverThe official repository you downloaded serves strictly as the headless backend API server for LRCLIB. It is designed to process database lookups, ingest new lyrics, and provide raw data to external media players, which is why navigating to that port displays raw JSON data or an error message instead of a web page.To interact with your local server through a graphical user interface (GUI), you can point a compatible frontend tool or media application directly at your local port.🌐 How to Connect a Web FrontendIf you want a dedicated web panel to browse, search, and manage your lyrics, you can run the web-based version of LRCGET alongside your server.You can configure LRCGET to use your newly deployed local container as its primary provider rather than the public internet version by adding an environment variable to its setup:yamlversion: '3.8' services: lrcget: image: ghcr.io/tranxuanthang/lrcget:latest container_name: lrcget ports: - "8000:8000" environment: # Change this to match your host machine's IP address if running across separate machines - LRCLIB_API_URL=http://localhost:3300 volumes: - /path/to/your/music:/music - ./lrcget-config:/config restart: unless-stopped Use code with caution.Once initialized, navigate to http://localhost:8000 to find a complete visual workspace where you can search through your local SQLite database tracks and attach them to files.🧪 Verifying the API LocallyYou can verify your backend is functional by testing a direct endpoint through your web browser or command-line terminal.Replace the values below with a known artist or track name existing inside your current database file to verify the response:In your browser URL bar:http://localhost:3300/api/search?q=JazzamorUsing your terminal CLI:bashcurl -G "http://localhost:3300/api/search" --data-urlencode "q=Jazzamor" Use code with caution.If your server setup is correct, this port will return a structured JSON response containing the text arrays and timestamps of the matched tracks.Would you like help creating a single Docker Compose file that bundles your Rust server, your current database asset, and the web GUI together? Let me know your setup details!AI responses may include mistakes. Learn moregithub.comGitHub - tranxuanthang/lrclib: LRCLIB server written in Rust with Axum and SQLite3 database · GitHubLRCLIB server written in Rust with Axum and SQLite3 database · GitHub Skip to content Navigation Menu Toggle navigation Sign in Ap...What about other flags, workers etc: LRCLIB_MMAP_SIZE (default 30000000000 - 30GB): set SQLite's mmap_size parameter. This should be less than 75% of the available RAM. Using an excessive value might cause memory swapping, decreasing performance. LRCLIB_CACHE_SIZE (default -1000000 - 1GB): set SQLite's cache_size parameter. Negative values are kilobytes.The LRCLIB Rust backend relies on CLI flags and environment variables to manage its asynchronous workers, networking parameters, and logging format.The primary configuration elements are broken down into categories below.🛠️ 1. Core CLI Flags (serve command)When initializing the server via the serve command, you can pass several runtime flags directly to the binary:--database: Dictates the path to your SQLite database file (e.g., --database db.sqlite3).--port: Sets the internal port binding for the Axum server engine (default is 3300).--workers-count: Defines the number of internal async worker instances spawned to process tasks. Increasing this values scales throughput across high-concurrency systems.📦 2. Global Environment VariablesBeyond the SQLite configurations, the underlying framework reads environment parameters to govern telemetry and system bindings:LRCLIB_LOG: Controls logging verbosity handled by the internal tracing pipeline. Setting LRCLIB_LOG=info records server initializations and incoming REST updates, whereas debug or trace will track low-level database operations.PORT: Alternative mapping option evaluated inside multi-stage Docker deployment configurations to cleanly expose your routing path.⏱️ 3. Background Tasks & Worker ArchitectureThe application runs automated tasks decoupled from the main request stream. These tasks are governed by internal architecture configurations rather than external flags:Queue Supervisor: Manages background asynchronous message sequences.Request Metrics Reporter: Calculates incoming load metrics and writes them to stdout.Recent Lyrics Counter: Re-evaluates metadata syncs submitted during the previous 10 minutes.💾 4. Optimizing memory for your local setupBecause your setup handles local lookups rather than a high-traffic production environment, the default memory footprints can be lowered safely:bash# Example optimized run command for local hardware LRCLIB_LOG=info
LRCLIB_MMAP_SIZE=2147483648
LRCLIB_CACHE_SIZE=-262144
cargo run --release -- serve --database db.sqlite3 --workers-count 2 Use code with caution.Memory Map (LRCLIB_MMAP_SIZE): Drop this value down to 2147483648 (2GB) to allow the OS to cache critical sections without consuming excessive host system resources.Cache (LRCLIB_CACHE_SIZE): Setting this to -262144 restricts SQLite's memory cache limits strictly to 256MB.Are you deploying this inside a low-powered home server (like a Raspberry Pi) or trying to resolve high CPU/memory overhead during your data queries? Let me know so we can tune your configuration further!AI responses may include mistakes. Learn moreGitHubLRCLIB server written in Rust with Axum and SQLite3 databaseBuild the project: cargo build --release. Run the server: LRCLIB_LOG=info cargo run --release -- serve --database db.sqlite3. Serv...github.comlrclib/ARCHITECTURE.md at main · tranxuanthang/lrclib · GitHub24 Jun 2026 — Workspace Layout · src/main.rs : parses serve --port --database --workers-count , then calls server::serve(...) or server::serve_w...github.comActivity · tranxuanthang/lrclib · GitHubAdd multiple queue workers feature. tranxuanthangpushed 1 commit to main ... Update queue message and README. tranxuanthangpushed ...it is an lxc/proxmox i allocated 4gb of memory and 4 coresGiven your Proxmox LXC setup with 4GB of RAM and 4 cores, you must change the default settings. Leaving the default production environment variables intact will immediately destabilize your container. The default LRCLIB_MMAP_SIZE is configured for 30GB, which exceeds your assigned RAM limit and will trigger the Linux Out-Of-Memory (OOM) killer to crash your server process.🚀 1. The Ideal Optimization Flag ScriptTo optimize the SQLite database engine within your hardware restrictions, launch your local binary using these exact environment variables and CLI arguments:bashLRCLIB_LOG=info
LRCLIB_MMAP_SIZE=2147483648
LRCLIB_CACHE_SIZE=-524288
cargo run --release -- serve --database db.sqlite3 --workers-count 4 Use code with caution.📊 2. Settings Breakdown for Proxmox LXCMemory Map (LRCLIB_MMAP_SIZE=2147483648)Value: 2GB (2147483648 bytes).Why: The official guidelines recommend keeping this configuration under 75% of total system memory to avoid host-level swapping. Allocating 2GB out of your 4GB pool grants SQLite lightning-fast memory-mapped read access to half of your dataset while preserving a safe cushion for OS activities and caching.Cache Size (LRCLIB_CACHE_SIZE=-524288)Value: 512MB (-524288 kilobytes).Why: Setting a negative integer instructs SQLite to enforce an exact limit measured in kilobytes. Allocating 512MB provides an ample layout window to track index tables for lightning-fast queries without ballooning the hardware allocations.Concurrent Processes (--workers-count 4)Value: 4 Workers.Why: This maps one internal asynchronous worker thread to each of your 4 allocated CPU cores. Because Rust handles multi-threaded operations natively via its Axum engine, matching this to your container's core limit ensures you run fast database lookups during simultaneous background scraping cycles.📦 3. Systemd / Deployment AdaptationIf you plan to run this in the background as a Linux background service rather than executing it manually via terminal command sessions, make sure your deployment configuration matches your hardware layout:Proxmox Podman/Docker VariantIf you used the repository's podman run workflow outlined in the documentation:bashpodman run --rm -it -d
-v lrclib-data:/data
-p 3300:3300
-e LRCLIB_LOG=info
-e LRCLIB_MMAP_SIZE=2147483648
-e LRCLIB_CACHE_SIZE=-524288
--name lrclib-rs
lrclib-rs:latest
serve --database /data/db.sqlite3 --workers-count 4 Use code with caution.Would you like assistance setting up an automated cron task inside the LXC container to regularly back up your SQLite file, or do you need help tracking down any remaining Proxmox CPU bottleneck spikes? Tell me what you need!AI responses may include mistakes. Learn moreGitHubLRCLIB server written in Rust with Axum and SQLite3 databaseDatabase configuration. You have two environment variables available to tweak the database connection: LRCLIB_MMAP_SIZE (default 3...Reddit·r/ProxmoxProper RAM, Disk, and Storage Allocation for LXC Containers ...25 Jun 2026 — For an LXC the RAM limit is just that a limit. The actual usage is whatever the programs running allocate. for example if you allo...Proxmox Support ForumLXC Container in Proxmox using 90% of memory with all processed killed16 Mar 2024 — You might be experiencing an issue where your LXC container in Proxmox is running out of memory. Here are some things you can try:Show allIf I woul host it on bare metal and 32 GB of memory ?If you host the server on bare metal with 32 GB of total memory, you are perfectly aligned to run LRCLIB's out-of-the-box, heavy-duty production defaults.Because the entire LRCLIB SQLite database dump is roughly ~20GB to ~25GB, your hardware lets you map the entire database directly into RAM for near-instant, zero-I/O searches.🚀 1. The Bare Metal Optimization ScriptYou should scale down the default 30GB MMAP size slightly to strictly respect the system's "75% of total RAM" safety limit. Use these exact environment parameters:bashLRCLIB_LOG=info
LRCLIB_MMAP_SIZE=23622320128
LRCLIB_CACHE_SIZE=-2097152
cargo run --release -- serve --database db.sqlite3 --workers-count <TOTAL_CPU_CORES> Use code with caution.📊 2. Production Settings Explained for 32GB RAM

Memory Map (LRCLIB_MMAP_SIZE=23622320128)Value: 22 GB (23622320128 bytes).Why: The official LRCLIB documentation warns that memory mapping allocations must remain under 75% of your total RAM to prevent OS swapping. By designating 22 GB, you safely capture the complete database table structure in RAM while leaving 10 GB completely free for your Linux kernel, background network I/O, and file system processes.Cache Size (LRCLIB_CACHE_SIZE=-2097152)Value: 2 GB (-2097152 kilobytes).Why: Setting a negative number forces SQLite to use an exact memory limit in kilobytes instead of calculating page counts. A 2 GB index cache guarantees that highly repetitive index scans (like tracking common search strings) are answered instantly without touching your storage drives.Concurrent Processes (--workers-count)Value: Match the exact physical/logical core count of your bare-metal CPU.Why: If your host machine uses a 6-core/12-thread or an 8-core/16-thread processor, pass --workers-count 12 or --workers-count 16. Since bare metal removes the virtualization overhead found in Proxmox, mapping a worker to every logical core ensures your system can digest hundreds of incoming API scraping queries without breaking a sweat.

🏁 Why Bare Metal Shines for Local Databases On an LXC or VM setup, the OS layer must constantly intercept and translate disk I/O requests. By moving to bare metal and implementing the 22 GB RAM map configuration above, your disk drives will remain completely idle after the server boots up. The application will serve thousands of media player requests out of physical RAM chips, giving you the fastest possible query speeds.Are you thinking about creating a systemd service file to make this run as a background daemon on boot, or are you setting up a reverse proxy like Caddy or Nginx to expose it safely across your home network? Let me know where you want to go next!