Shelfmark Book and audiobook search โ€” proxied via Netherlands seedbox

Shelfmark is a self-hosted book and audiobook search aggregator. It searches multiple sources simultaneously and returns results in a unified interface. All outbound traffic exits via the seedbox in the Netherlands through a persistent SOCKS5 tunnel.

Configuration
Setting Value
URL http://192.168.8.100:8084
Host CT 100 (192.168.8.100)
Image ghcr.io/calibrain/shelfmark:latest
Version v1.2.0 (build 2026-03-07)
Port 8084
Compose file /opt/shelfmark/docker-compose.yml (on CT 100)
Proxy mode SOCKS5 via 172.25.0.1:1080 (Docker bridge to CT 100 host)
Proxy exit ismene.usbx.me (Netherlands, UltraSeedbox)
Remote access Pangolin private resource only โ€” not publicly accessible
Metadata provider Hardcover

Docker volumes:

Container path Host path (CT 100) ZFS dataset Purpose
/books /mnt/seedbox/Books nvmepool/ingest Downloaded books โ€” shared with Readarr (Bookshelf)
/config /opt/shelfmark/config CT 100 rootfs Settings, users.db, cover cache

Previously /books pointed to /opt/shelfmark/books (isolated from Readarr). Changed 2026-03-31 to /mnt/seedbox/Books so Shelfmark downloads land directly in the seedbox Books folder where Readarr can see them.

Docker environment:

PROXY_MODE=socks5
SOCKS5_PROXY=socks5://172.25.0.1:1080
NO_PROXY=localhost,127.0.0.1,192.168.8.*,172.25.0.*
TZ=America/New_York
PUID=0
PGID=0

PUID/PGID set to 0 (root): The seedbox Books folder receives files via rsync with UID 1040, which Shelfmark’s default appuser (UID 1000) cannot write to. Running as root prevents “destination not writable” errors during post-processing. Changed 2026-04-02.

SOCKS5 Proxy Architecture

Shelfmark routes all search and download traffic through the seedbox to avoid region-based restrictions. The chain is:

Shelfmark (CT 100 Docker)
    โ†“ SOCKS5 to 172.25.0.1:1080 (Docker bridge โ†’ CT 100 host)
seedbox-socks.service (autossh, CT 100 systemd)
    โ†“ SSH tunnel to delgross@46.232.210.50
ismene.usbx.me (Netherlands exit, UltraSeedbox)
    โ†“
Book search sources (Anna's Archive, Libgen, etc.)

Check proxy tunnel status:

# SSH into CT 100 first
ssh root@192.168.8.221
pct exec 100 -- bash
# Then:
systemctl status seedbox-socks.service

Restart proxy tunnel:

systemctl restart seedbox-socks.service

If Shelfmark searches fail or time out: The SOCKS5 tunnel is almost always the culprit. Check the service status above. The tunnel reconnects automatically via autossh, but occasionally needs a manual restart after seedbox connectivity issues.

Prowlarr Integration

Prowlarr runs on CT100 as an indexer aggregator, providing Usenet-based book search as an additional release source alongside the direct download sources (Anna’s Archive, Libgen, etc.). Prowlarr routes all traffic through the same SOCKS5 seedbox tunnel as Shelfmark.

Setting Value
URL http://192.168.8.100:9696
Image lscr.io/linuxserver/prowlarr:latest
Compose file /opt/prowlarr/docker-compose.yml (on CT 100)
API Key 2adb6f9d248840bcadc0ab93222b78fd
Auth Forms (user: bee), disabled for local addresses
SOCKS5 proxy 172.26.0.1:1080 (Prowlarr Docker bridge gateway โ†’ CT 100 host tunnel)
Bypass 192.168.8.*,localhost,127.0.0.1,172.26.0.*

Indexers configured:

Indexer Type API Key Book categories
altHUB Newznab (Usenet) f0d9327bc1db3011025b40176ec6955a 7000 (Books), 107020 (Ebook), 107030 (Comics), 107010 (Mags)

Shelfmark connection: Enabled in Shelfmark Settings โ†’ Prowlarr with auto-expand search on. When Shelfmark searches for a book, it queries both direct_download and prowlarr sources simultaneously. Prowlarr found 115 additional books that direct download sources couldn’t locate.

Note: Prowlarr’s Docker network (prowlarr_default) uses gateway 172.26.0.1, which is different from Shelfmark’s network (shelfmark_default, gateway 172.25.0.1). Both reach the same SOCKS tunnel on 0.0.0.0:1080 on the CT100 host, just via different Docker bridge IPs.

Kindle Library Import

A Python script at ~/Sync/ED/homelab/book_library/kindle_to_shelfmark.py automates bulk importing from the Kindle library into Shelfmark. It reads the Kindle NZB results JSON (1,773 books with titles, authors, and ASINs) and for each book: searches Shelfmark’s Hardcover metadata provider, finds downloadable releases, and queues the best epub for download.

First full run (2026-03-31):

Metric Count
Total processed 1,773
Metadata found 1,732 (97.7%)
Metadata not found 41
Releases found 1,273 (73.5% of metadata matches)
Releases not found 459
Queued for download 1,349 (1,234 first run + 115 Prowlarr retry)
Queue failures 39 (mostly duplicates already in queue)

Usage:

cd ~/Sync/ED/homelab/book_library

# Dry run โ€” search only, don't download
python3 kindle_to_shelfmark.py --dry-run --skip-existing

# Full run โ€” queue all downloads
python3 kindle_to_shelfmark.py --skip-existing --delay 5

# Resume after interruption
python3 kindle_to_shelfmark.py --skip-existing --resume

# Process in batches
python3 kindle_to_shelfmark.py --skip-existing --limit 50

Files:

File Purpose
kindle_to_shelfmark.py Import script
kindle_nzb_results.json Source data โ€” 1,773 Kindle books with ASIN, title, author
shelfmark_state.json Resume state โ€” tracks which ASINs have been processed
shelfmark_import_*.log Timestamped log files for each run

How the script works:

  1. For each Kindle book, search Shelfmark metadata API (/api/metadata/search) using title + author
  2. Find best match by title word overlap (โ‰ฅ40% threshold)
  3. Search for downloadable releases (/api/releases) using the matched provider/book_id
  4. Score releases โ€” prefer epub format, reasonable file size (0.5โ€“100 MB)
  5. Queue the best release via /api/releases/download
  6. Save state after every 20 books for resume capability
Shelfmark API

Shelfmark has no authentication enabled (auth_mode: none). All API endpoints are accessible without credentials.

Endpoint Method Purpose
/api/health GET Health check
/api/metadata/search?query=...&limit=N GET Search book metadata (Hardcover)
/api/releases?provider=...&book_id=... GET Search downloadable releases for a book
/api/releases/download POST Queue a release for download
/api/localdownload GET List locally downloaded books
/api/downloads/active GET Active download queue
/api/config GET Current configuration
Download Sources

Shelfmark searches multiple sources in priority order until a download succeeds.

Fast sources (tried first):

Source Status Notes
AA Fast Downloads โœ… Active Requires donator key. Dedicated fast servers, typically 2-4 MB/s.
Library Genesis โœ… Active Default mirrors: libgen.gl, .li, .bz, .la, .vg

Slow sources (fallback):

Source Status Notes
AA Slow (No Waitlist) โœ… Active Partner servers, no countdown
AA Slow (Waitlist) โœ… Active Partner servers with countdown timer
Welib โœ… Active Alternative mirror, requires Cloudflare bypass
Zlib โœ… Active Z-Library mirror, requires Cloudflare bypass

Additional sources:

Source Status Notes
Prowlarr (altHUB) โœ… Active Usenet indexer, finds books not in direct download sources

Anna’s Archive donator key is configured in Settings โ†’ Download Sources. This unlocks the AA Fast Downloads tier with dedicated servers instead of the free mirrors that crawl at 3-10 KB/s.

DNS-over-HTTPS (DoH) is disabled in Shelfmark’s network config (/opt/shelfmark/config/plugins/network.json, USE_DOH: false). DoH via Quad9 was returning 400 errors for several domains when routed through the SOCKS tunnel, causing all post-processing to fail. System DNS resolution works correctly as a fallback.

Remote Access

Shelfmark is configured as a Pangolin private resource โ€” it’s reachable remotely without opening any public ports. Connect via the Pangolin VPN client and access it at http://192.168.8.100:8084 as if you’re on the home network.

It does not have a public subdomain โ€” intentionally kept private since it’s a search aggregation tool.