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 / JackettFind 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 or Jackett) 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 #

Shelfarr ships as a single Docker image, ghcr.io/pedro-revez-silva/shelfarr. Docker Compose is the recommended way to run it.

1. Create a compose file

Make a folder and drop in a docker-compose.yml. Start from the example and edit the three media paths to match your system:

# docker-compose.yml
services:
  shelfarr:
    image: ghcr.io/pedro-revez-silva/shelfarr:latest
    container_name: shelfarr
    restart: unless-stopped
    ports:
      - "5056:80"
    volumes:
      # App data โ€” holds the database and auto-generated secret key (required)
      - ./data:/rails/storage
      # Your library + download folders โ€” edit the left side
      - /path/to/audiobooks:/audiobooks
      - /path/to/ebooks:/ebooks
      - /path/to/downloads:/downloads
    environment:
      - SOLID_QUEUE_IN_PUMA=1
      # - PUID=1000      # match the owner of your mounted folders
      # - PGID=1000
๐Ÿ“
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.

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 fixes for mounted storage. auto tries but continues on failure (e.g. NFS root-squash); always fails on errors; never skips it.
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.
๐Ÿ”
Updating: docker compose pull && docker compose up -d. Your data and settings live in ./data, so upgrades are non-destructive. Shelfarr also checks GitHub for new releases and shows a banner when one is available.

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 or Jackett 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.

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 from Anna's Archive and Z-Library, and free public-domain audiobooks from LibriVox. Enable whichever sources you want; they run alongside your indexer.

Anna's Archive (ebooks)

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.

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 — treat it as a fallback.

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.

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). On NFS shares that block chown, set CHOWN_ON_START=never and pre-permission the folders yourself.

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.

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).