Self-hosting guide
From zero to listening
Bookmark ships as a single container (web app and API together) plus a Postgres database. Two containers, one small config file, and about five minutes if your audiobooks are already in a folder.
You will need Docker with Compose and a folder of audiobooks (M4B, MP3, M4A, or OGG). Ebooks (EPUB) and comics (CBZ, CBR, PDF) are optional and can join later.
Clone the repository
$ git clone https://github.com/RobinEdquist/bookmark.git $ cd bookmark
Configure it before the first start
Bookmark will start without any configuration, but you would be running an empty library on a default database password. Take the two minutes: copy the template and point it at your actual folders.
# cp example.env .env, then set the essentials: AUDIOBOOK_LIBRARY_PATH=/path/to/your/audiobooks EBOOK_LIBRARY_PATH=/path/to/your/ebooks # optional COMIC_LIBRARY_PATH=/path/to/your/comics # optional POSTGRES_PASSWORD=pick-something-strong
The library mounts are read-only: Bookmark scans your files and never rewrites them. Set POSTGRES_PASSWORD now rather than later; Postgres keeps the password it was initialized with, so changing it after the first start means recreating the database volume.
Start it and claim the admin account
This pulls the pre-built image. If you would rather build from source, run docker compose -f docker-compose.yml -f docker-compose.build.yml up -d --build instead.
$ docker compose up -dOpen http://localhost:3001 and sign up. The first account created becomes the admin; everyone after that is a regular listener with their own progress, lists, and preferences. An auth secret is generated and persisted for you on first start.
Let the wizard take it from here
Your first sign-in opens a short setup wizard where you confirm your library folders, and scanning starts automatically. Covers, chapters, and metadata fill in with live progress, and Bookmark keeps watching the folders for new files from then on; big libraries keep importing in the background while you start listening. Everything stays adjustable later under Settings → Libraries.
Take it beyond localhost
To reach Bookmark on your own domain, add one more value to .env and point your reverse proxy at port 3001:
PUBLIC_URL=https://bookmark.yourdomain.com
PUBLIC_URL is used for auth callbacks and CORS, so logins break without it. Re-run docker compose up -d after changing it.
Pair your phone
Install the Bookmark app on iPhone or Android (both currently in beta), open the Audiobook App page in the web sidebar, and scan the QR code. It carries the server address and a fresh API key in one scan; no passwords retyped on a phone keyboard. Manual entry works too if you prefer.
Optional extras
docker compose --profile tts up -d, then enter http://tts:8880 under Settings → Integrations → Text-to-speech. Any OpenAI-compatible text-to-speech server works as a drop-in replacement, self-hosted or cloud. Generated audiobooks land in your library under a generated folder.OIDC_ENABLED=true plus your issuer URL, client ID, and client secret in .env to slot Bookmark into an existing Authentik, Keycloak, or Authelia setup.DATA_PATH (default ./data): the database, covers, and generated audiobooks. Back up that one folder and you can rebuild anywhere; your media stays untouched where it always was.docker compose logs -f bookmark tells you most of the story. Login loops usually mean PUBLIC_URL does not match the address in your browser. The full configuration reference lives in the README.That is the whole setup. Tonight's chapter is waiting.