Self-hosting guide

Install Bookmark

One container, one file to paste, about five minutes. Nothing to clone, nothing to build.

You need Docker with Compose and a folder of audiobooks (M4B, MP3, M4A, OGG). Ebooks and comics are optional and can join later.

Create the compose file

Make a folder for Bookmark, then save the file below inside it as docker-compose.yml.

~ on your-server
$ mkdir bookmark
$ cd bookmark
docker-compose.yml
services:
  bookmark:
    image: ghcr.io/robinedquist/bookmark:latest
    container_name: bookmark
    restart: unless-stopped
    init: true
    # Time to shut the database down cleanly on stop.
    stop_grace_period: 2m
    environment:
      # The address you open Bookmark at. Both lines need it.
      BETTER_AUTH_URL: http://localhost:3001
      UI_URL: http://localhost:3001
      # Your timezone, so times match your clock.
      TZ: Europe/Stockholm # change this
    volumes:
      # Bookmark's own data. Keep this on local disk, not a NAS share.
      - ./data/app:/data
      # Your audiobooks. Read-only: Bookmark never writes here.
      - /path/to/your/audiobooks:/library/audiobooks:ro
      # Optional. Delete these two lines if you only have audiobooks.
      - /path/to/your/ebooks:/library/ebooks:ro
      - /path/to/your/comics:/library/comics:ro
    ports:
      - "3001:3001"

  # Optional, for AI-narrated audiobooks. Idle until you start it with:
  # docker compose --profile tts up -d
  tts:
    image: ghcr.io/remsky/kokoro-fastapi-cpu:latest
    container_name: bookmark-tts
    restart: unless-stopped
    profiles: ["tts"]

Edit three lines

Everything you need to change is marked in the file:

  • Your audiobook folder: replace /path/to/your/audiobooks. Leave the part after the colon alone.
  • Ebooks and comics: real paths, or delete both lines.
  • Your timezone: for example America/New_York. Find yours.

Your folders are read-only. Bookmark reads your files and never changes them.

Start it and sign up

~/bookmark
$ docker compose up -d

Open http://localhost:3001 and sign up. The first account is the admin. Everyone after that is a listener with their own progress and lists.

Let the wizard finish

A short wizard confirms your folders, then scanning starts on its own. Covers and chapters fill in while you browse, and new files are picked up automatically. Change anything later under Settings → Libraries.

Use your own domain

Point your reverse proxy at port 3001, then put your address on both lines:

docker-compose.yml
      BETTER_AUTH_URL: https://bookmark.yourdomain.com
      UI_URL: https://bookmark.yourdomain.com

They have to match the address in your browser, or logins fail. Run docker compose up -d again afterwards.

Pair your phone

The iPhone and Android apps reach public beta soon. When you have one, open Audiobook App in the sidebar and either scan the QR code or sign in with your usual account. No keys to type.

Optional extras

AI narration. Bookmark can narrate an ebook into a real audiobook. Make a folder for the results first, then add it to the file:

mkdir -p /path/to/your/audiobooks/generated

- ./data/generated-audiobooks:/library/audiobooks/generated

The folder has to exist before you add that line, or Bookmark will not start.

Then run docker compose --profile tts up -d and enter http://tts:8880 under Settings → Integrations → Text-to-speech.
Single sign-on. Add OIDC_ENABLED: "true" plus your issuer URL, client ID, and client secret to sign in through Authentik, Keycloak, or Authelia. The configuration reference lists the exact names.
Something not working? Run docker compose logs -f bookmark. Login problems almost always mean the two address lines do not match the address in your browser. Everything you can configure is listed in the README.

That is the whole setup.