Ebooks & audiobooks — Audiobookshelf + Calibre-Web-Automated¶
Two purpose-built stacks, split because no single self-hosted app does both media types well and syncs cleanly to Kobo + Kindle + Supernote:
| Stack | URL | Handles | |
|---|---|---|---|
| Audio | audiobookshelf (ghcr.io/advplyr/audiobookshelf) |
ab.fmm.house |
audiobooks + podcasts |
| Text | calibre-web-automated (ghcr.io/crocodilestick/calibre-web-automated) |
eb.fmm.house |
ebooks + all e-reader device sync |
Both are label-fronted through Traefik on the proxy network (no host port), pinned + Diun-watched
like the rest of the fleet. Runtime data (media, DBs, config) is gitignored under each stack dir.
Why two apps¶
Audiobookshelf is audiobook-first; its ebook support is basic and its only ebook→device path is email (Send-to-Kindle), which Kobo can't consume. Its own docs point you to a dedicated ebook server. Calibre-Web-Automated (the actively-developed CWA fork of Calibre-Web) owns the ebook side: native Kobo sync, Send-to-Kindle, OPDS, and a built-in KOReader progress-sync plugin. Kavita was evaluated and rejected (no audiobooks; .NET).
First-run¶
- Audiobookshelf (
ab.fmm.house): first visit creates the root/admin account in the browser. Add libraries pointing at/audiobooksand/podcasts. Runs as root (official image has no PUID/PGID); media dirs arestacks/audiobookshelf/{audiobooks,podcasts}. - Calibre-Web-Automated (
eb.fmm.house): default loginadmin/admin123— change it immediately (Admin → Edit Users). CWA auto-creates an empty Calibre library in/calibre-libraryon first boot. Runs as PUID/PGID1000:1000.
Adding books (CWA)¶
Drop any of ~28 formats into stacks/calibre-web-automated/ingest/ (/cwa-book-ingest). CWA
auto-converts to EPUB, imports into the library with metadata, and deletes the source file. Or
upload via the web UI. EPUB is required for Kobo sync and cleanest for Send-to-Kindle.
Device sync¶
Kobo — native OTA sync (best path)¶
CWA impersonates the Kobo store so the reader syncs books and reading position over the air.
1. In CWA: Admin → Edit User → OAuth & API Integrations → Kobo Sync Token → create; enable
Kobo sync and Proxy unknown requests to Kobo Store.
2. On the Kobo, point the sync API at the generated https://eb.fmm.house/kobo/<token> URL (via
the Kobo's .kobo/Kobo/Kobo eReader.conf api_endpoint, or the setup helper CWA prints).
3. EPUB only; CWA converts to kepub on the fly.
Reverse-proxy gotcha: if synced URLs come back as
http://or wrong host, Calibre-Web built them from bad proxy headers. Traefik forwardsX-Forwarded-Proto/Hostcorrectly by default; if it ever misbehaves, set the server external URL in CWA settings tohttps://eb.fmm.house.
Kindle — Send-to-Kindle (no live sync exists)¶
Kindle has no self-hosted sync protocol. CWA emails individual books to your @kindle.com address
(it cleans the EPUB for Amazon's converter first).
This needs a real external SMTP relay — Postmoogle can't do it. Postmoogle (
fmm.house:25) is an inbound email→Matrix sink with no outbound relay, and this box can't send to the public internet on :25 anyway (residential egress, ISP-blocked :25, no sending reputation — seedocs/runbooks/email-to-matrix.md). A book "sent to"@kindle.comthrough it would not deliver.
- Provision an authenticated submission relay (a transactional/email provider on :587 — e.g. SES, Postmark, Mailgun, SMTP2GO, Fastmail, or a Gmail app-password) with a verified From address.
- Configure SMTP in CWA (Admin → Edit Basic Configuration → Email server) pointing at that relay.
- Add the From address to Amazon's Approved Personal Document E-mail List.
- Per book: Send to Kindle. Recent Kindles accept EPUB directly.
If you'd rather not run a relay: Kobo native sync (above) needs no email at all, or use Amazon's own Send to Kindle web/app to push files manually.
Supernote — KOReader + OPDS¶
Supernote has no native OPDS, but sideload the KOReader APK (adb install over USB) and point it
at CWA:
1. KOReader → OPDS catalog → add https://eb.fmm.house/opds (basic-auth with your CWA user).
Browse + download the whole library.
2. KOReader → Progress sync: use CWA's built-in KOReader sync (install the CWA KOReader plugin,
disable KOReader's native Progress Sync, log in with your CWA server + account) so reading
position round-trips.
Komga/Kavita OPDS would also work here, but CWA keeps everything in one place.
Notifications → Matrix (Postmoogle)¶
Neither app has forgejo-style event-notification email; wiring is limited to what each can emit.
Both mailboxes (eb@fmm.house, ab@fmm.house) are claimed in Matrix with a shared SMTP password
stored in each stack's gitignored .env. AUTH verified against Postmoogle (235).
CWA → eb@fmm.house (wired + verified)¶
No extra_hosts pin needed (same as forgejo/ocis): the container resolves mail.fmm.house to the
routable LAN 192.168.86.49 A record — glibc sorts it ahead of the unroutable fd00:6176 ULA, so
smtplib connects to .49:25 in ~0.01s (verified from inside the container: STARTTLS + AUTH 235).
The old vaporware host-gateway pin was only needed under the pre-2026‑07‑19 Tailscale-IPv6 AAAA,
which didn't fail cleanly. Calibre-Web stores SMTP config encrypted in app.db, so it can't be
injected headlessly — enter once in the UI
(Admin → Edit E-mail Server Settings), values from stacks/calibre-web-automated/.env:
| Field | Value |
|---|---|
| SMTP hostname | mail.fmm.house |
| SMTP port | 25 |
| Encryption | STARTTLS |
| SMTP login | eb@fmm.house |
| SMTP password | (SMTP_PASSWORD in .env) |
| From e-mail | eb@fmm.house |
Set your CWA account's e-mail to a claimed mailbox (e.g. albert@fmm.house) so Save settings and
send Test E-Mail lands in that Matrix room. CWA only emits password-reset/test mail — no event stream.
ABS → ab@fmm.house (needs Apprise — not yet wired)¶
Audiobookshelf has no SMTP notification path (its SMTP is send-to-ereader only, being sunset).
Event notifications (podcast episode, backup done/failed) go through Apprise, which needs a small
Apprise-API container. Intended route: ABS → Apprise → Postmoogle (mailto as ab@fmm.house) →
Matrix, reusing the validated credential. Not built yet — an audiobook-first library fires little.
Notes / gotchas¶
- Both images are off Docker Hub (ghcr) per fleet convention; Diun watches
^\d+\.\d+\.\d+$(ABS) and^v\d+\.\d+\.\d+$(CWA). - Backups: neither stack's data is backed up yet — same deferred off-box backup gap as the rest of
the fleet (see
docs/runbooks/monitoring.md). The Calibre library (metadata.db+ books) and the ABSconfig/metadataSQLite DBs are the things worth capturing when that lands. - Whispersync-style read-along (audio highlighting ebook text) is out of scope here — that's a separate app (Storyteller), not wired up.