📚 Booklore Review: My eBook Library with Self‑Hosting
For years, I’ve wanted a Jellyfin‑like experience for my eBooks—a clean, modern interface that lets me browse, organize, and actually enjoy my digital library without being locked into Amazon’s walled garden. Enter Booklore: a self‑hosted eBook server that feels like the missing piece in my home lab stack.
I’ve been running it via Docker Compose on my own server, and it’s quickly become one of my favorite deployments. Here’s why.
🚀 Why Booklore?
Booklore is more than just a file browser—it’s a full‑fledged eBook management platform. Think of it as the Plex or Jellyfin of books. Once deployed, it gives you a sleek web interface where you can:
- Organize your library by author, title, tags, or metadata
- Read directly in the browser with support for EPUB, PDF, and CBZ formats
- Auto‑import new books via the “Bookdrop” folder (just drop files in and they’re instantly added)
- Multi‑user support so family or colleagues can have their own accounts
- Metadata fetching for covers, descriptions, and clean cataloging
- Search and filter across your entire collection instantly
- Modern UI that feels fast, responsive, and intuitive
In short: it’s the eBook library I always wanted, but under my control.
🛠️ Deployment with Docker Compose
One of the best parts about Booklore is how easy it is to spin up. I run it in Docker Compose with persistent volumes for data, books, and the Bookdrop folder. Here’s the Compose snippet I use:
Reviewed 09-12-2025 - No need to update service stack - still compliant
# Docker Compose file for Booklore
# This setup includes a backend service using Gradle and a MariaDB database
# Based on the older docker compose file
# Environment file is a simple affair and references database only
# DONT ADD - cap_drop - all
# DONT ADD - User ID'S OR CGROUPS ATT
# https://github.com/booklore-app/booklore/tree/develop?tab=readme-ov-file
# Docker & Podman Compose ready
services:
booklore:
image: booklore/booklore:latest
container_name: booklore-app
hostname: booklore-app
restart: always
labels:
- com.docker.compose.project=booklore
- com.docker.compose.service=frontend
- homepage.group=Family Services
- homepage.name=Booklore
- homepage.href=http://booklore.baden.braedach.com
- io.containers.autoupdate=registry
- dockerflare.enable=false
ports:
- 6060:6060
depends_on:
mariadb:
condition: service_healthy
environment:
- TZ=Australia/Perth
- DATABASE_URL=jdbc:mariadb://mariadb:3306/${MYSQL_DATABASE}
# Map your existing env vars to what Booklore expects
- DATABASE_USERNAME=${MYSQL_USER}
- DATABASE_PASSWORD=${MYSQL_PASSWORD}
- BOOKLORE_PORT=6060
- SWAGGER_ENABLED=false
volumes:
- booklore_data:/app/data:u
- booklore_books:/home/books:U
- booklore_papers:/home/papers:U
- booklore_dummies:/home/dummies:U
- booklore_tradepub:/home/tradepub:U
- /srv/booklore/bookdrop:/home/bookdrop:U
- /etc/localtime:/etc/localtime:ro
- /etc/timezone:/etc/timezone:ro
# Add healthcode in here later - podman has issues with this
cap_add:
- SYS_TIME
security_opt:
- no-new-privileges:true
networks:
- booklore-net
- proxy-net
mariadb:
image: lscr.io/linuxserver/mariadb:11.4.5
container_name: booklore-mariadb
hostname: booklore-mariadb
restart: always
labels:
- com.docker.compose.project=booklore
- com.docker.compose.service=backend
- dockerflare.enable=false
environment:
- TZ=Australia/Perth
- MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}
- MYSQL_DATABASE=${MYSQL_DATABASE}
- MYSQL_USER=${MYSQL_USER}
- MYSQL_PASSWORD=${MYSQL_PASSWORD}
volumes:
- booklore_mariadb:/config:U
- /etc/localtime:/etc/localtime:ro
- /etc/timezone:/etc/timezone:ro
healthcheck:
test: ["CMD", "mariadb-admin", "ping", "-h", "localhost", "-u", "root", "-p${MYSQL_ROOT_PASSWORD}"]
interval: 5s
timeout: 5s
retries: 10
start_period: 30s
cap_add:
- SYS_TIME
security_opt:
- no-new-privileges:true
networks:
- booklore-net
volumes:
booklore_data:
booklore_books:
booklore_papers:
booklore_dummies:
booklore_tradepub:
booklore_mariadb:
networks:
booklore-net:
driver: bridge
proxy-net:
external: true
Environment file
# Database credentials
MYSQL_ROOT_PASSWORD=generateapassword
MYSQL_DATABASE=namethedatabase
MYSQL_USER=createauser
MYSQL_PASSWORD=generateanotherpasswordAfter running docker compose up -d, I just hit the web UI, create an admin account, and my library is live, or you can deploy it via Portainer CE (which is a better method in my humble opinion).
🔒 Why Self‑Host?
Owning your library matters. With Booklore:
- No DRM lock‑in
- No vendor deciding what you can or can’t access
- Full control over backups, metadata, and access
- A private, auditable system that integrates neatly into a home lab stack
For me, it’s about operational transparency and future‑proofing. My books are mine, and Booklore makes them accessible without compromise.

🎯 Final Thoughts
Booklore has become the centerpiece of my digital reading workflow. It’s lightweight, modern, and respects the principle of ownership. If you’ve ever wished for a self‑hosted alternative to Kindle or Calibre’s clunky web UI, this is it.
Project complete, now to upload the hundreds of eBooks and fix the metadata for those not in public databases
#enoughsaid