Skip to content

Installation

BookOrbit runs in Docker. The only host dependency is Docker itself. The bundled Compose stack starts BookOrbit and PostgreSQL with persistent storage on your server.

RequirementMinimum
OSAny Linux distro, macOS, or Windows with WSL2
CPU1 core (2+ recommended)
RAM512 MB free (1 GB+ recommended)
DiskSpace for your book files + ~50 MB for the app
DockerLatest stable (install guide)
Docker Composev2.0+ (included with Docker Desktop)

Any modern browser works - Chrome, Firefox, Safari, Edge.

Pick a location on your server for BookOrbit to live. The Compose file and default persistent data paths stay inside this folder. You can point BOOKS_HOST_PATH elsewhere if your library already exists in another location.

Terminal window
mkdir bookorbit && cd bookorbit
mkdir -p books data/app data/postgres
curl -fsSLo .env https://raw.githubusercontent.com/bookorbit/bookorbit/main/.env.example
curl -fsSLo docker-compose.yml https://raw.githubusercontent.com/bookorbit/bookorbit/main/docker-compose.yml

Edit .env before starting. At minimum, set these values:

# Docker image to run. The default in the downloaded template is fine for most installs.
APP_IMAGE=ghcr.io/bookorbit/bookorbit:latest
# The address you will use to open BookOrbit.
# Direct LAN access: http://your-server-ip:3000
# Behind a reverse proxy with a domain: https://books.example.com
APP_URL=http://your-server-ip:3000
# The folder on your server where your book files live.
# This folder appears as /books inside BookOrbit.
BOOKS_HOST_PATH=./books
# POSTGRES_USER and POSTGRES_DB default to "bookorbit" in the downloaded template.
# Change POSTGRES_PASSWORD to something strong.
POSTGRES_PASSWORD=use-a-strong-random-password
JWT_SECRET=use-a-long-random-secret
SETUP_BOOTSTRAP_TOKEN=use-a-random-setup-token
Terminal window
docker compose up -d

Docker will pull the images and start both the database and app. Wait about 30 seconds on first startup.

Open your browser and go to http://your-server-ip:3000.

You’ll be redirected to a setup page - create your administrator account here. You’ll need your SETUP_BOOTSTRAP_TOKEN from .env.

BookOrbit is available on Unraid through Community Applications as two templates: bookorbit and bookorbit-db (PostgreSQL + pgvector). Search BookOrbit in the Apps tab to install both.

The two containers need to be able to reach each other. There are two ways to set that up:

  • Host IP and Port (default, simplest) - both templates use Unraid’s default bridge network. Point the app at the database’s container IP and its exposed port.
  • Custom Docker Network - attach both containers to a shared custom network and reach the database by container name instead of by IP.

Search for bookorbit-db in the Apps tab and install it first. Fill in:

  • Port - host port used to reach the database, 5432 by default. Note this value; you’ll need it for the app’s Postgres Port field
  • Postgres User / Postgres DB - defaults of bookorbit are fine
  • Postgres Password - generate a strong value (see Generating secrets above)
  • Database Storage - defaults to /mnt/user/appdata/bookorbit-db

Apply, and wait about 20-30 seconds for Postgres to finish initializing before starting the app container.

Search for bookorbit and install it. Fill in:

  • WebUI Port - 3000 by default
  • Books Folder - point at your existing books share, e.g. /mnt/user/data/media/books
  • App URL - http://your-server-ip:3000, or your reverse-proxy domain
  • Postgres User / Password / DB - must exactly match what you set on bookorbit-db
  • Postgres Host - the bookorbit-db container’s IP address (find it under Docker → Container IP), or the container name bookorbit-db if you’re using a custom network
  • Postgres Port - must match the Port value you set on bookorbit-db
  • JWT Secret and Setup Bootstrap Token - generate your own random values
  • PUID / PGID - match the user/group that owns your Books Folder

Less commonly changed variables (Book Dock path, fix-permissions toggle, Node heap size, log level) are available under the template’s Show more settings… section.

Once both containers are running, open your App URL and complete setup using your Setup Bootstrap Token, the same as any other install.


You’re in. Next, set up your first library so BookOrbit knows where your books live.

Creating a Library

On Linux and NAS installs, Docker uses numeric user and group IDs when it reads or writes mounted folders.

BookOrbit runs as PUID:PGID from your .env file. The default is 1000:1000.

PUID=1000
PGID=1000
BOOKS_HOST_PATH=/mnt/media/books

Your BOOKS_HOST_PATH must be readable by that user. It must also be writable if you want BookOrbit to upload books, finalize Book Dock files, or write metadata back to files.

To check who owns your book folder:

Terminal window
ls -ldn /mnt/media/books

If your media user is different, set PUID and PGID to that user:

Terminal window
id your-media-user

Then restart:

Terminal window
docker compose up -d

Common signs of a permission issue:

  • A scan finishes but finds no books
  • Uploads fail when saving into /books
  • Book Dock cannot finalize files
  • Logs mention EACCES, permission denied, or not writable

If you already have a PostgreSQL server running (like on a NAS or a managed service), you can use it instead of the built-in Docker container.

  • PostgreSQL 16 or newer
  • Four extensions installed on your database: uuid-ossp, pg_trgm, unaccent, and vector (pgvector)
  • A dedicated database and user for BookOrbit

Add DATABASE_URL to your .env file, replacing it with your database details:

DATABASE_URL=postgres://bookorbit:[email protected]:5432/bookorbit

Remove the postgres: service block entirely. Also remove this block from the app: service because the app no longer waits for the bundled database:

depends_on:
postgres:
condition: service_healthy

All configuration is done through the .env file. After changing any value, restart the stack:

Terminal window
docker compose up -d
VariableRequiredTemplate/defaultDescription
APP_IMAGEYesghcr.io/bookorbit/bookorbit:latestDocker image to run
APP_URLYes-Full URL where BookOrbit is accessible
POSTGRES_USERYesbookorbitDatabase username
POSTGRES_PASSWORDYes-Database password
POSTGRES_DBYesbookorbitDatabase name
JWT_SECRETYes-Secret for signing login tokens
SETUP_BOOTSTRAP_TOKENYes-One-time token for initial setup
APP_PORTNo3000Host port mapped to the container
PORTNo3000Internal container port. Only change if APP_PORT and PORT need to differ
BOOKS_HOST_PATHNo./booksHost folder mounted as /books in the container
PUIDNo1000UID for files written by the app (useful on NAS)
PGIDNo1000GID for files written by the app (useful on NAS)
BOOKORBIT_FIX_PERMISSIONSNotrueSet to false if your platform manages /data ownership externally
NODE_MAX_OLD_SPACE_SIZENo2048 in .envNode.js heap limit in MB. Use auto for container-aware detection or raise it for very large libraries
LIBRARY_BROWSE_ROOTNo/Root shown by the library folder picker. Set to /books to hide other container folders
BOOK_DOCK_PATHNo/data/book-dockBook Dock staging folder inside the container
DATABASE_URLNoBuilt from bundled Postgres settingsFull PostgreSQL connection string for an external database
POSTGRES_HOSTNopostgresDatabase hostname. Override when using an external DB
POSTGRES_PORTNo5432Database port
CLIENT_URLNoSame as APP_URLFrontend URL when the client is served from a different domain
EMAIL_ENCRYPTION_KEYNo-Encrypts stored SMTP credentials at rest. Recommended if you configure email
MIGRATION_ENCRYPTION_KEYNo-Encrypts stored migration source credentials. Recommended if you use migrations
LOG_LEVELNoinfoLog verbosity. Set to debug for detailed output
OIDC_ALLOW_LOCAL_ISSUERSNofalseAllows OIDC discovery on private addresses. Enable only on a trusted network
CSP_ALLOW_CLOUDFLARE_INSIGHTSNofalseAllows the Cloudflare Web Analytics beacon in the content security policy

If you’re using Nginx, Caddy, or Traefik, point it at localhost:3000 and set APP_URL to your public domain with HTTPS.

Caddy example:

books.example.com {
reverse_proxy localhost:3000
}

Both are configured inside the app - no environment variables needed. Log in as an administrator and go to Settings > Email or Settings > OIDC / SSO.

Terminal window
docker compose pull
docker compose up -d

The app handles database migrations automatically on startup.