Self-hosted personal PDF library: catalog, nested collections, cover thumbnails, reader & users
682
Self-hosted personal library to store, organize and read PDF files (manuals, notes, papers, scanned invoices…), with a library-card catalog instead of a generic dashboard. Runs as a single Docker container (backend serves the API and the built frontend) and is designed for a home server such as TrueNAS SCALE, with storage paths configurable via environment variables.
.pdf files (drag & drop or picker), one or many at once, with a
configurable size limit.tallon43/pdf-library:latest, tallon43/pdf-library:1.0.0Create a .env file:
PORT=3000
MAX_UPLOAD_MB=50
JWT_SECRET=change-me-to-a-long-random-secret # openssl rand -hex 32
ADMIN_USER=admin
ADMIN_PASSWORD= # empty => a random one is generated and printed once in the log
STORAGE_HOST_PATH=./storage
DB_HOST_PATH=./data
docker-compose.yml:
services:
pdf-library:
image: tallon43/pdf-library:latest
container_name: pdf-library
restart: unless-stopped
ports:
- "${PORT:-3000}:3000"
environment:
PORT: 3000
PDF_STORAGE_PATH: /data/storage
DB_PATH: /data/db/library.db
MAX_UPLOAD_MB: ${MAX_UPLOAD_MB:-50}
JWT_SECRET: ${JWT_SECRET:?Set JWT_SECRET in .env}
ADMIN_USER: ${ADMIN_USER:-admin}
ADMIN_PASSWORD: ${ADMIN_PASSWORD:-}
volumes:
- ${STORAGE_HOST_PATH:-./storage}:/data/storage
- ${DB_HOST_PATH:-./data}:/data/db
Then:
docker compose up -d
docker compose logs -f pdf-library # the generated admin password is shown here once
Open http://localhost:3000 and sign in.
Environment variables
┌──────────────────┬─────────────────────────────────────────────────────────────────────────────────┬─────────────────────┐
│ Variable │ Description │ Default │
├──────────────────┼─────────────────────────────────────────────────────────────────────────────────┼─────────────────────┤
│ PORT │ Server port │ 3000 │
├──────────────────┼─────────────────────────────────────────────────────────────────────────────────┼─────────────────────┤
│ PDF_STORAGE_PATH │ Path where the real .pdf files are stored │ /data/storage │
├──────────────────┼─────────────────────────────────────────────────────────────────────────────────┼─────────────────────┤
│ DB_PATH │ Path to the SQLite metadata file │ /data/db/library.db │
├──────────────────┼─────────────────────────────────────────────────────────────────────────────────┼─────────────────────┤
│ MAX_UPLOAD_MB │ Per-file upload size limit (MB) │ 50 │
├──────────────────┼─────────────────────────────────────────────────────────────────────────────────┼─────────────────────┤
│ JWT_SECRET │ Secret used to sign the session JWT (required) │ — │
├──────────────────┼─────────────────────────────────────────────────────────────────────────────────┼─────────────────────┤
│ ADMIN_USER │ Admin user created on first run │ admin │
├──────────────────┼─────────────────────────────────────────────────────────────────────────────────┼─────────────────────┤
│ ADMIN_PASSWORD │ Admin password. If empty, a random one is generated and printed once in the log │ (generated) │
└──────────────────┴─────────────────────────────────────────────────────────────────────────────────┴─────────────────────┘
Volumes
- /data/storage — stored PDF files (and generated thumbnails under thumbs/)
- /data/db — SQLite database
Mount both from the host (or your TrueNAS datasets) to persist data across restarts.
First login
On first run the admin user (ADMIN_USER) is created. If you didn't set
ADMIN_PASSWORD, check the container log — the generated password is printed once.
From the user menu you can switch language, and from Users (admin only) you can create
more accounts and choose which collections each one can see.
License / notes
No credentials are baked into the image: the admin is created at first run from
environment variables. Keep your JWT_SECRET private.
---
Content type
Image
Digest
sha256:2d165d858…
Size
88.4 MB
Last updated
19 days ago
docker pull tallon43/pdf-library