Trove Help Trove home

Installation

Trove runs either in Docker with PostgreSQL, or natively on an Ubuntu or Debian server with systemd. Both use port 6060.

Docker Compose

You need Docker (v20.10+) and Docker Compose (v2.0+). Allow 2 GB of RAM, 4 GB or more for large libraries.

Step 1: Create the folders

mkdir -p ~/trove/{data,books,bookdrop,postgres}
cd ~/trove
FolderPurpose
postgresDatabase files. Back this up.
dataCovers, thumbnails, uploaded fonts and icons, and other files Trove creates
booksYour book library
bookdropDrop books here to import them (see Bookdrop)

Step 2: Create .env

# Application
APP_USER_ID=1000
APP_GROUP_ID=1000
TZ=Etc/UTC

# Database
DATABASE_URL=jdbc:postgresql://postgres:5432/trove
DB_USER=trove
DB_PASSWORD=ChangeMe_TroveApp_2026!
POSTGRES_DB=trove

# Storage: LOCAL (default), or NETWORK to stop Trove ever modifying book files
DISK_TYPE=LOCAL

Change the password before you start. Set APP_USER_ID and APP_GROUP_ID to the owner of your folders (id -u, id -g).

Step 3: Create docker-compose.yml

services:
  trove:
    image: ghcr.io/x2-consult/trove:latest
    container_name: trove
    environment:
      - USER_ID=${APP_USER_ID}
      - GROUP_ID=${APP_GROUP_ID}
      - TZ=${TZ}
      - DATABASE_URL=${DATABASE_URL}
      - DATABASE_USERNAME=${DB_USER}
      - DATABASE_PASSWORD=${DB_PASSWORD}
      - DISK_TYPE=${DISK_TYPE}
    depends_on:
      postgres:
        condition: service_healthy
    ports:
      - "6060:6060"
    volumes:
      - ./data:/app/data
      - ./books:/books
      - ./bookdrop:/bookdrop
    restart: unless-stopped

  postgres:
    image: postgres:16-alpine
    container_name: postgres
    environment:
      - TZ=${TZ}
      - POSTGRES_DB=${POSTGRES_DB}
      - POSTGRES_USER=${DB_USER}
      - POSTGRES_PASSWORD=${DB_PASSWORD}
    volumes:
      - ./postgres:/var/lib/postgresql/data
    restart: unless-stopped
    healthcheck:
      test: [ "CMD", "pg_isready", "-U", "${DB_USER}", "-d", "${POSTGRES_DB}" ]
      interval: 5s
      timeout: 5s
      retries: 10

For production, pin a release tag instead of latest, for example ghcr.io/x2-consult/trove:v1.2.3. Podman Quadlet and Helm examples are in the example-podman and example-chart folders of the repository.

Step 4: Start it

docker compose up -d
docker compose logs -f trove

Open http://localhost:6060, or http://YOUR_SERVER_IP:6060 from another device, and create your admin account (see Admin account).

Native install

On an Ubuntu or Debian server with systemd:

git clone -b master https://github.com/X2-Consult/trove.git
cd trove
./install.sh

master is the released version; develop has the latest changes before they're released.

The installer asks whether this is a production or development machine, then sets up Java 25, PostgreSQL, a trove database and user, and the trove systemd service. It can also configure Caddy or nginx with a Let's Encrypt certificate if you give it a domain name.

WhatWhere
App/opt/trove
Data: config (covers and other files Trove creates), library and bookdrop/srv/trove
Settings file (database password, allowed origins, version)/etc/trove/trove.env
Servicesystemctl status trove, logs with journalctl -u trove -f

To update, run ./deploy.sh in /opt/trove, or use Update now in the app (admins only). Trove keeps running while the update builds, and is only unavailable while it restarts at the end, usually under a minute. Database changes are applied as it starts.

Books on a network share

Your book folders can be on a NAS. Mount the share on the host first (NFS or SMB/CIFS), then point Trove at it: in Docker, mount it into the container as a volume like ./books above; natively, add the mounted folder when you create the library. Trove recognises network filesystems and adjusts how it watches and writes to them. See Network storage for the details and the DISK_TYPE and NETWORK_POLL_SECONDS settings.

Moving from BookLore

Troubleshooting

Trove won't start

docker compose logs trove postgres     # Docker
journalctl -u trove -n 100             # native

Common causes: a wrong volume path, port 6060 already in use, a database password that doesn't match, or folder permissions.

Database connection errors

Check PostgreSQL is healthy with docker compose ps postgres, and that DATABASE_USERNAME and DATABASE_PASSWORD match POSTGRES_USER and POSTGRES_PASSWORD.

Permission errors

Set APP_USER_ID/APP_GROUP_ID to the folders' owner, or fix the ownership:

sudo chown -R $USER:$USER ~/trove/data ~/trove/books ~/trove/bookdrop

Port already in use

Find what's using it with sudo lsof -i :6060, or map another host port, for example "8080:6060". Natively, set TROVE_PORT in /etc/trove/trove.env.

Can't reach it from another device

sudo ufw allow 6060/tcp                                                       # UFW
sudo firewall-cmd --permanent --add-port=6060/tcp && sudo firewall-cmd --reload  # firewalld

The site refuses connections, but Trove is running

If curl http://localhost:6060/api/v1/healthcheck on the server answers but browsers get "connection refused" (a Trove tab may show a 504), something in front of Trove is blocking you. A common cause is fail2ban with a rule that bans addresses after many "not found" responses: everything in your home shares one public address, so a Kobo sync or a page of missing covers can ban the whole house. See Kobo troubleshooting for how to exempt your network.

Next steps