ShelfarrDocs

Getting Started

Shelfarr is a self-hosted request and download system for ebooks and audiobooks — the books equivalent of Jellyseerr for your *arr stack. This guide takes you from an empty server to your first completed download.

What is Shelfarr? #

Users search for a book and request it. Shelfarr looks it up across your indexers and direct sources, picks a release, hands it to a download client, then organises the finished files into your library folders and tells Audiobookshelf to scan them. Admins can review requests, or let Shelfarr select and grab results automatically.

It sits between the tools you already run:

METADATAOpen Library / HardcoverSearch & cover art
YOU ARE HEREShelfarrRequests & orchestration
INDEXERSProwlarr / Jackett / NZBHydra2Find releases
DOWNLOADqBittorrent, SABnzbd, โ€ฆFetch the files
LIBRARYAudiobookshelfRead & listen
๐Ÿ’ก
Almost everything is optional. The only hard requirement is one way to find books (an indexer or a direct source) and somewhere to put them (your output paths).

How It Works #

Every request moves through the same lifecycle:

  1. Discover A user searches metadata (Open Library, or Hardcover if configured) and finds the title and format they want — ebook or audiobook.
  2. Request The request is created. Admin requests (and, optionally, everyone's) are queued for searching immediately; otherwise an admin approves them.
  3. Search Shelfarr queries your indexer (Prowlarr, Jackett or Newznab/NZBHydra2) and any enabled direct sources, then scores the results against your format preferences and language.
  4. Select The best result is chosen automatically (when auto-selection is on) or presented for an admin to pick.
  5. Download The release is sent to a matching download client — routed by type, priority and any per-indexer routing rules.
  6. Import When the download finishes, files are renamed and moved into your output folders using your path and filename templates.
  7. Library If Audiobookshelf is connected, a scan is triggered and the book appears in your library.

If a search comes up empty, Shelfarr retries later with a back-off, and flags the request for attention after the retry limit so nothing is silently lost.

Installation #

The core application image is ghcr.io/pedro-revez-silva/shelfarr. The standard Docker Compose stack also includes the internal, idle Audible Backup companion so the beta can be enabled later without a manual Libation installation.

1. Create a compose file

Download the complete current example rather than copying only the Shelfarr service from an older file:

mkdir shelfarr && cd shelfarr
curl -O https://raw.githubusercontent.com/Pedro-Revez-Silva/shelfarr/main/docker-compose.example.yml
mv docker-compose.example.yml docker-compose.yml

Edit the left side of the three media mounts: /path/to/audiobooks, /path/to/ebooks, and /path/to/downloads. Optionally set SHELFARR_VERSION to a concrete OCI image version in .env so the Shelfarr and companion images remain paired. Omit the GitHub release tag's leading v: for a release shown as vYYYY.MM.DD.N, use YYYY.MM.DD.N.

๐Ÿ“
The /downloads path should point at the same completed-downloads folder your download client writes to, mounted identically here and in the client. This is what lets Shelfarr find finished files. If the paths differ, see remote path mapping.

2. Start it

docker compose up -d

A secret key is generated on first run and saved to ./data — keep that folder. Compose also creates private Libation state, completed-backup, and bridge-token volumes. The companion remains idle and does not contact Audible unless an administrator enables Audible Backup.

3. Open the web UI

Visit http://<your-server-ip>:5056. The first account you register becomes the admin.

Environment variables

VariableDefaultDescription
PUID1000User ID for file permissions. Match the owner of your mounted volumes.
PGID1000Group ID for file permissions. Match the group of your mounted volumes.
CHOWN_ON_STARTautoStartup ownership policy for both standard containers. auto adjusts only when needed; always fails on adjustment errors; never skips chown for pre-permissioned/root-squashed mounts. The Audible companion still rejects group/world-accessible private state and credential/token files.
TRUST_NFS_UID_SQUASHfalseSet to true only on an NFS export using all_squash (remaps every client's UID to one shared identity — most NAS UIs expose this as something like "map all users") and that no untrusted client can mount. This does not prove a file was written by this container — it tells Shelfarr to trust that the export is effectively single-tenant so its ownership safety checks aren't defeated by the squash.
HTTP_PORT80Internal container port. Change if 80 clashes (e.g. behind gluetun), then update the port mapping.
RAILS_MASTER_KEY(auto)Encryption key for stored secrets. Auto-generated on first run if unset.
RAILS_RELATIVE_URL_ROOT/Base path when running behind a reverse proxy at a sub-path, e.g. /shelfarr.
SHELFARR_VERSIONlatestOCI image version used for both Shelfarr and its matching Libation companion. Use the numeric version without a leading v.
LIBATION_BOOKS_PATHlibation_booksOptional host path for Libation's retained Audible backup copies. Leave unset to use the Docker named volume.
๐Ÿ”
Updating a current Compose installation: pin a published numeric SHELFARR_VERSION, then run docker compose pull && docker compose up -d. Pull-request images are not published for normal installation. Before the first Audible-enabled upgrade of an older or customized installation, preserve its exact /rails/storage source and follow the one-time existing-install procedure; a separate Audible override must be included in every future Compose command.

First-Time Setup #

Once you're logged in as the admin, wire up the essentials. Each step links to its full field reference.

  1. Create your admin account Register the first user at http://<server>:5056. Add more users later from Admin → Users.
  2. Connect an indexer In Admin → Settings → Indexer, choose Prowlarr, Jackett or Newznab/NZBHydra2 and enter its URL and API key. See the indexer guide. (Skip if you'll only use direct sources.)
  3. Add a download client In Admin → Download Clients, add qBittorrent, Decypharr, Deluge, Transmission, SABnzbd or NZBGet. See the download client guide.
  4. Confirm your output paths In Admin → Settings → Output Paths, make sure /audiobooks and /ebooks match the volumes you mounted, and tune the path templates if you like.
  5. (Optional) Connect Audiobookshelf Add its URL, an API token and your library IDs in Admin → Settings → Audiobookshelf. See the Audiobookshelf guide.
  6. Request your first book Use the search bar, pick a title and format, and request it. Approve it (or enable auto-selection) and watch it move through the queue to your library.
โœ…
Check Admin → Health any time — it reports whether your indexer, download clients, paths and Audiobookshelf are reachable and configured.

Indexers #

Indexers are how Shelfarr finds downloadable releases. Pick one provider with the indexer_provider setting.

Prowlarr

  1. In Prowlarr, add the book indexers you want to use.
  2. Copy your API key from Prowlarr → Settings → General.
  3. In Shelfarr, set prowlarr_url (e.g. http://prowlarr:9696) and prowlarr_api_key. Optionally restrict to tagged indexers with prowlarr_tags.

Jackett

Prefer Jackett? Set indexer_provider to jackett, then fill jackett_url and jackett_api_key (from the Jackett dashboard). Use jackett_indexer_filter to limit which indexers are queried.

Newznab / NZBHydra2

Use NZBHydra2 or another Newznab-compatible provider by setting indexer_provider to newznab, then fill newznab_url and newznab_api_key. Shelfarr accepts either the application base URL or the direct /api endpoint.

Full field list: Settings reference → Indexers.

Download Clients #

Add one or more clients in Admin → Download Clients. Supported adapters:

  • Torrent — qBittorrent, Deluge, Transmission, and Decypharr (a qBittorrent-compatible variant).
  • Usenet — SABnzbd, NZBGet.

Give each client a name, its URL, and credentials (username/password, or an API key for SABnzbd). A few things worth knowing:

  • Priority decides which client wins when several handle the same type — lower is preferred.
  • Category tags downloads in the client so you can keep Shelfarr's grabs separate.
  • Routing — use Admin → Download Routing to force a specific indexer's torrent or usenet results to a specific client.
๐Ÿ“
Shelfarr imports files from the completed-downloads folder, so the client's finished path must be visible to Shelfarr at /downloads (or mapped — see Troubleshooting).

Full field list: Settings reference → Download Clients.

Audiobookshelf #

Optional, but recommended — it makes Shelfarr trigger a library scan as soon as a book lands, and enriches metadata such as series and narrator.

  1. In Audiobookshelf, create an API token from your user settings.
  2. In Shelfarr's Audiobookshelf settings, enter the server URL and the token.
  3. Set the audiobook and ebook library IDs so scans target the right libraries. (The library ID appears in the URL when you open a library in Audiobookshelf.)

Full field list: Settings reference → Audiobookshelf.

Direct Downloads #

Some books can be fetched directly, with no indexer or download client involved — ebooks and audiobooks from Anna's Archive, ebooks from Z-Library, and free public-domain audiobooks from LibriVox. Enable whichever sources you want; they run alongside your indexer.

Anna's Archive (ebooks and audiobooks)

Enable anna_archive_enabled. Fast (member) downloads need an anna_archive_api_key from a donation. If the site is behind anti-bot protection, point flaresolverr_url at a FlareSolverr instance.

For security, Anna's Archive audiobooks must arrive as direct HTTPS ZIP downloads. Shelfarr verifies the selected MD5, preflights archive expansion and paths, validates every audio file, and only retains sanitized JPEG, PNG, or WebP covers and non-empty printable UTF-8 TXT companions. Torrent or magnet audiobook artifacts, nested archives, and other file types are rejected. Run FlareSolverr with egress access to private, link-local, and cloud metadata networks blocked.

Z-Library (ebooks)

Enable zlibrary_enabled and provide your account zlibrary_email and zlibrary_password. This is an unofficial integration and may break if the service changes.

LibriVox (audiobooks)

Enable librivox_enabled for free, public-domain audiobooks read by volunteers — no account or API key required. Great for classics and out-of-copyright titles when no other audiobook source has them.

Full field list: Settings reference → Direct Downloads.

Third-Party Stores BETA #

Shelfarr can show legitimate DRM-free store offers without handling checkout. The first provider is eBooks.com. Offers appear in a separate Buy DRM-free section on an ebook request and never enter auto-selection or the download queue. When downloadable releases also exist, administrators see both sections; regular requesters see the store offers plus the existing Search Results Available banner while release selection remains with an administrator. Lookups run only with request searches, identical responses and displayed quotes expire after 24 hours, and seller rate-limit responses activate a shared cooldown.

  1. Open Admin → Settings → Search → eBooks.com Store (Beta).
  2. Enable it, enter the buyer's two-letter country code (for example US, GB, or PT), choose an offer limit, save, and test the catalog.
  3. Request an ebook normally. Follow an eligible offer to eBooks.com, complete payment there, and download the purchased file.
  4. Upload the file to its Shelfarr request. If normal users cannot upload, ask an administrator to import it.

New and existing installations need no extra service. An update adds a default-disabled table and settings; it does not replace existing settings or encryption keys. Prices and availability are market-specific, and DRM-free files can still have a social watermark.

โš ๏ธ
Shelfarr never receives payment details, store credentials, orders, or purchased files automatically. Confirm eBooks.com partner or affiliate permission before enabling catalog deep links for a production deployment.

Architecture, permissions, and limitations: Third-party stores (Beta).

Audible Backup BETA #

Audible Backup lets you browse and preserve audiobooks already attached to your Audible account. It uses a separately packaged, pinned, unmodified Libation CLI companion. It does not search or advertise Audible's store.

New Compose installation

Use the current Shelfarr Compose example and run docker compose up -d. The private companion is included but stays idle until Audible Backup is enabled; there is no separate Libation installer or public companion port.

Existing Compose installation

Wait for active work to finish, inspect the running container to identify its actual Compose file and /rails/storage source, then stop Shelfarr and back up that complete storage tree, Compose file, and .env. Merge the companion service, private volumes, read-only Shelfarr output and token mounts, and network configuration from the same published release without replacing existing data or media mounts. Validate with docker compose config -q, then pull and start both matching images. Set one matching PUID/PGID pair in .env; for a large library, set LIBATION_BOOKS_PATH to storage with enough capacity for Libation's retained copy. A separate docker-compose.audible.yml must be supplied to pull, up, logs, and exec commands. Never give Shelfarr access to the Docker socket.

Storage requirement

The configured audiobook output filesystem must support advisory file locks, hard links on the same mount, and Unix mode changes. Shelfarr probes these capabilities before a backup and keeps its private .shelfarr-staging directory inside the audiobook output root for an atomic handoff; do not mount that nested directory from another volume. Run the documented preflight before connecting Audible. NFS/SMB appliances that disable reliable flock or hard links are not compatible with Audible imports even if ordinary file copies work.

On mergerfs, a libfuse option such as umask=0002 forces reported file modes to 0775 even when the backing inode was changed to 0640, so Shelfarr fails closed. Do not change it to umask=0000 or bypass the check. Use a coordinated maintenance window to remove the reporting override and retest every pool consumer, or bind Shelfarr directly to one underlying POSIX branch only after verifying that branch contains the complete audiobook library and has sufficient capacity. See the mergerfs and filesystem preflight procedure.

Treat every process running as Shelfarr's PUID as trusted. A malicious same-UID process can modify any writable library file regardless of application-level race defenses; run untrusted download tools under another UID and share only the narrow exchange paths they require.

Connect and back up

  1. Open Admin → Audible Backup → Connection, enable and test the companion, then connect the Audible account from the account card on the same tab.
  2. Enter the Audible email and marketplace, start sign-in, and authenticate directly on Amazon/Audible. The validated sign-in link survives a page reload in encrypted, short-lived Shelfarr state until completion or expiry; start again if Shelfarr reports that it expired.
  3. Paste the final redirected browser URL into Shelfarr. The Audible password never reaches Shelfarr, and the response URL is not persisted or logged.
  4. Run the initial owned-library sync. When Overview asks whether to back up the eligible existing library, confirm the displayed count to start a durable background batch or choose Not now. The batch excludes subscriptions, local matches, identity conflicts, and prior backup/import attempts; Libation processes one admitted title at a time and progress is managed from Library. If you have not verified storage and import paths, choose Not now, test one title in Library, then use the reusable action under Automation.
  5. Optionally enable scheduled sync every hour, 6 hours, 12 hours, 24 hours, 3 days, or weekly. The default is still 24 hours. Automatic backup is a separate opt-in: the next successful manual or scheduled sync refreshes a no-download baseline, then purchased audiobooks first discovered by later syncs are queued automatically.

Automation is off by default and does not affect manual controls. Automatic future-purchase backup requires a completed initial sync and scheduled sync; turning scheduled sync off also turns automatic backup off. Re-enabling automatic backup requires a new no-download baseline refresh rather than downloading older cached titles. It never starts the separately confirmed existing-library batch.

โš ๏ธ
The first beta supports manual and scheduled sync, cached Library browsing, individual-title backup, a confirmed and conservatively filtered existing-library batch, future-purchase automatic backup, and job status. An unfiltered Back up all, retroactive automatic backup, pause/resume, and cancellation are not yet available. The integration is unofficial and upstream authentication or interfaces can change.

Deployment contract, storage, security, attribution, and limitations: Audible Backup, powered by Libation (Beta).

Notifications #

In-app notifications are always on. You can also forward request events (created, completed, failed, attention) to:

  • Discord — create an incoming webhook for a channel and paste the URL into discord_webhook_url.
  • Telegram — create a bot with BotFather, enter the token, and approve your group with the pairing code (or list chat IDs manually). The bot also accepts request commands.
  • Webhook — any endpoint that accepts JSON, including ntfy. Add a Bearer token and topic if your receiver needs them.

Full field list: Settings reference → Notifications.

Authentication & SSO #

Shelfarr uses local username/password accounts by default, with optional extras:

  • Two-factor auth — users can enable TOTP and download backup codes from their profile.
  • Lockout — repeated failed logins trigger a temporary lockout (configurable).
  • Disable auth — for a trusted network behind your own SSO/proxy, set auth_disabled (or the DISABLE_AUTH env var) for username-only login.

OIDC / SSO

To sign in with Authentik, Authelia, Keycloak and friends:

  1. Create an OIDC client in your provider with redirect URI http://<your-shelfarr-url>/auth/oidc/callback and scopes openid profile email.
  2. In Admin → Settings → OIDC/SSO, enable OIDC and enter the issuer URL, client ID and secret.
  3. Optionally turn on auto-creation of users (and a default role), or link OIDC logins to existing local accounts.

Full field list: Settings reference → OIDC / SSO.

API Access #

Shelfarr exposes a JSON API under /api/v1 for automation. Create a scoped token from Profile → API tokens (tokens are prefixed shf_) and send it as a Bearer header:

# Search metadata
curl -H "Authorization: Bearer shf_..." \
  "http://<server>:5056/api/v1/search?q=dune&limit=5"

# Create a request
curl -X POST -H "Authorization: Bearer shf_..." \
  -H "Content-Type: application/json" \
  -d '{"work_id":"openlibrary:OL893415W","book_type":"ebook","title":"Dune","author":"Frank Herbert"}' \
  "http://<server>:5056/api/v1/requests"

Token scopes: search:read, requests:read, requests:write, requests:admin, users:write. Self-service users can mint read and request-write tokens; admin scopes require an admin.

Troubleshooting #

Start with the Health page

Admin → Health shows the status of every integration. If something is down or not configured, it usually points straight at the problem.

Downloads finish but never import

Almost always a path mismatch: Shelfarr can't see the files where the download client reports them. Make sure the client's completed folder is mounted into Shelfarr at the same path. If the client runs on a different host or uses a different path, set download_remote_path (the client's path) and download_local_path (what Shelfarr sees) so the two can be mapped.

Permission denied writing to the library

Set PUID/PGID to match the owner of your mounted folders (run ls -n on them to check). The Compose example passes one CHOWN_ON_START policy to Shelfarr and its companion. On NFS shares that block chown, set it to never and pre-permission every mounted folder yourself.

Post-processing fails with "A safe filesystem operation failed" on NFS

Your NFS export likely uses all_squash, remapping every client's UID to one shared identity (on a NAS, usually a checkbox or dropdown like "map all users" in its NFS permissions), not just root's. Shelfarr's ownership safety checks can't tell that apart from a genuinely different owner and fail closed by default. If the export is only ever mounted by this container — no other client can reach it — set TRUST_NFS_UID_SQUASH=true. Otherwise, remove all_squash from the export (or its NAS UI equivalent) and use PUID/PGID to control ownership instead.

Anna's Archive returns nothing

The site may be behind anti-bot protection — configure flaresolverr_url. Member-speed downloads also require an anna_archive_api_key.

No eBooks.com offers appear

Confirm eBooks.com Store (Beta) is enabled, the buyer country is exactly two letters, and Test eBooks.com Catalog succeeds. Offers are checked only for ebook requests and only results explicitly reported as DRM-free EPUB or PDF are retained.

Audible Backup says the companion is unavailable

Confirm the current Compose file includes shelfarr-libation and all three Libation volumes, then run docker compose ps and docker compose logs shelfarr-libation. The companion must share Shelfarr's Compose network and token volume, but port 8080 must not be published publicly. For import failures, also verify matching PUID/PGID access to the shared completed-backup volume. Never include the token, Audible redirect URL, or private Libation state in a support log.

Audible Backup rejects the audiobook filesystem

Run the unprivileged filesystem preflight from the Audible Backup guide. It verifies locking, same-filesystem hard links, and mode 0640 without downloading a title. If the output is a mergerfs/FUSE mount with a persistent umask= option, follow the documented maintenance-window or complete underlying-bind resolution; do not run Shelfarr as root or disable the check.

Running behind a reverse proxy at a sub-path

Set RAILS_RELATIVE_URL_ROOT (e.g. /shelfarr) so generated links and assets resolve correctly.

๐Ÿ›
Still stuck? Open an issue on GitHub with your Health page status and the relevant container logs (docker compose logs shelfarr).