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.
Requirements
Section titled “Requirements”| Requirement | Minimum |
|---|---|
| OS | Any Linux distro, macOS, or Windows with WSL2 |
| CPU | 1 core (2+ recommended) |
| RAM | 512 MB free (1 GB+ recommended) |
| Disk | Space for your book files + ~50 MB for the app |
| Docker | Latest stable (install guide) |
| Docker Compose | v2.0+ (included with Docker Desktop) |
Any modern browser works - Chrome, Firefox, Safari, Edge.
Install
Section titled “Install”Create the install folder
Section titled “Create the install folder”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.
mkdir bookorbit && cd bookorbitmkdir -p books data/app data/postgrescurl -fsSLo .env https://raw.githubusercontent.com/bookorbit/bookorbit/main/.env.examplecurl -fsSLo docker-compose.yml https://raw.githubusercontent.com/bookorbit/bookorbit/main/docker-compose.ymlEdit .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.comAPP_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-passwordJWT_SECRET=use-a-long-random-secretSETUP_BOOTSTRAP_TOKEN=use-a-random-setup-tokenStart BookOrbit
Section titled “Start BookOrbit”docker compose up -dDocker will pull the images and start both the database and app. Wait about 30 seconds on first startup.
Complete setup
Section titled “Complete setup”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.
Unraid Installation
Section titled “Unraid Installation”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
bridgenetwork. 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.
Install the database first
Section titled “Install the database first”Search for bookorbit-db in the Apps tab and install it first. Fill in:
- Port - host port used to reach the database,
5432by default. Note this value; you’ll need it for the app’s Postgres Port field - Postgres User / Postgres DB - defaults of
bookorbitare 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.
Install the app
Section titled “Install the app”Search for bookorbit and install it. Fill in:
- WebUI Port -
3000by 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-dbcontainer’s IP address (find it under Docker → Container IP), or the container namebookorbit-dbif 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.
Complete setup and updates
Section titled “Complete setup and updates”Once both containers are running, open your App URL and complete setup using your Setup Bootstrap Token, the same as any other install.
After Installation
Section titled “After Installation”You’re in. Next, set up your first library so BookOrbit knows where your books live.
File Permissions
Section titled “File Permissions”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=1000PGID=1000BOOKS_HOST_PATH=/mnt/media/booksYour 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:
ls -ldn /mnt/media/booksIf your media user is different, set PUID and PGID to that user:
id your-media-userThen restart:
docker compose up -dCommon 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, ornot writable
External Database
Section titled “External Database”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.
1. Requirements
Section titled “1. Requirements”- PostgreSQL 16 or newer
- Four extensions installed on your database:
uuid-ossp,pg_trgm,unaccent, andvector(pgvector) - A dedicated database and user for BookOrbit
2. Update your environment file
Section titled “2. Update your environment file”Add DATABASE_URL to your .env file, replacing it with your database details:
3. Modify docker-compose.yml
Section titled “3. Modify docker-compose.yml”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_healthyConfiguration
Section titled “Configuration”All configuration is done through the .env file. After changing any value, restart the stack:
docker compose up -dEnvironment variables
Section titled “Environment variables”| Variable | Required | Template/default | Description |
|---|---|---|---|
APP_IMAGE | Yes | ghcr.io/bookorbit/bookorbit:latest | Docker image to run |
APP_URL | Yes | - | Full URL where BookOrbit is accessible |
POSTGRES_USER | Yes | bookorbit | Database username |
POSTGRES_PASSWORD | Yes | - | Database password |
POSTGRES_DB | Yes | bookorbit | Database name |
JWT_SECRET | Yes | - | Secret for signing login tokens |
SETUP_BOOTSTRAP_TOKEN | Yes | - | One-time token for initial setup |
APP_PORT | No | 3000 | Host port mapped to the container |
PORT | No | 3000 | Internal container port. Only change if APP_PORT and PORT need to differ |
BOOKS_HOST_PATH | No | ./books | Host folder mounted as /books in the container |
PUID | No | 1000 | UID for files written by the app (useful on NAS) |
PGID | No | 1000 | GID for files written by the app (useful on NAS) |
BOOKORBIT_FIX_PERMISSIONS | No | true | Set to false if your platform manages /data ownership externally |
NODE_MAX_OLD_SPACE_SIZE | No | 2048 in .env | Node.js heap limit in MB. Use auto for container-aware detection or raise it for very large libraries |
LIBRARY_BROWSE_ROOT | No | / | Root shown by the library folder picker. Set to /books to hide other container folders |
BOOK_DOCK_PATH | No | /data/book-dock | Book Dock staging folder inside the container |
DATABASE_URL | No | Built from bundled Postgres settings | Full PostgreSQL connection string for an external database |
POSTGRES_HOST | No | postgres | Database hostname. Override when using an external DB |
POSTGRES_PORT | No | 5432 | Database port |
CLIENT_URL | No | Same as APP_URL | Frontend URL when the client is served from a different domain |
EMAIL_ENCRYPTION_KEY | No | - | Encrypts stored SMTP credentials at rest. Recommended if you configure email |
MIGRATION_ENCRYPTION_KEY | No | - | Encrypts stored migration source credentials. Recommended if you use migrations |
LOG_LEVEL | No | info | Log verbosity. Set to debug for detailed output |
OIDC_ALLOW_LOCAL_ISSUERS | No | false | Allows OIDC discovery on private addresses. Enable only on a trusted network |
CSP_ALLOW_CLOUDFLARE_INSIGHTS | No | false | Allows the Cloudflare Web Analytics beacon in the content security policy |
Reverse proxy
Section titled “Reverse proxy”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}SMTP and OIDC
Section titled “SMTP and OIDC”Both are configured inside the app - no environment variables needed. Log in as an administrator and go to Settings > Email or Settings > OIDC / SSO.
Updating
Section titled “Updating”docker compose pulldocker compose up -dThe app handles database migrations automatically on startup.