Omnibus is published as a ready-to-run image on Docker Hub:
sesloan/omnibus. It runs on
amd64 and arm64 and already contains everything the server needs, including
ffmpeg for audiobook streaming and kepubify for Kobo downloads. You do not need
a copy of this repository to run it. A folder and a compose file are enough.
-
Make a folder for Omnibus and open a terminal in it:
mkdir omnibus && cd omnibus
-
Save the following as
docker-compose.ymlin that folder:services: omnibus: image: sesloan/omnibus:latest container_name: omnibus restart: unless-stopped ports: - "3000:3000" # host:container — change the left side if 3000 is taken volumes: - ./config:/config # database, covers, journal images — back this up - ./cache:/cache # thumbnails and audio transcodes — safe to delete - /path/to/your/ebooks:/books # EDIT: your ebook folder - /path/to/your/audiobooks:/audiobooks # EDIT: your audiobook folder environment: PUID: "1000" # EDIT if `id -u` is not 1000 — files are written as this user PGID: "1000" # EDIT if `id -g` is not 1000 OMNIBUS_PUBLIC_ORIGIN: "http://localhost:3000" # EDIT: the exact address you open in the browser OMNIBUS_SECURE_COOKIES: "0" # 0 over plain http; set to 1 (or remove) behind HTTPS EBOOK_LIBRARY_PATH: "/books" AUDIOBOOK_LIBRARY_PATH: "/audiobooks"
-
Change the lines marked
EDIT:- The two library paths. Replace
/path/to/your/ebooksand/path/to/your/audiobookswith the folders on your machine. Leave the right-hand side (/books,/audiobooks) alone. If you only have one kind of library, point both at real folders anyway. An empty one is fine. OMNIBUS_PUBLIC_ORIGIN. The address you will actually type into the browser.http://localhost:3000is right if you open it on the same machine. If you will open it from another device on your network, use that address instead, for examplehttp://192.168.1.10:3000. You can list several, separated by commas. If this does not match, logging in fails with a 403.PUIDandPGID, if your user is not1000. Runid -uandid -gto check. Omnibus writes its database and cache as this user, so the files end up owned by you rather than root.
- The two library paths. Replace
-
Start it:
docker compose up -d
-
Open the address you set in a browser and register. The first account created is the admin. Omnibus scans both libraries on every start.
- Copy the
omnibus:block into yourservices:section. - Make the same
EDITchanges. ./configand./cacheare relative to your compose file. Use an absolute path if you prefer, e.g./srv/omnibus/config:/config.- Port 3000 taken? Change the left side of
ports, and changeOMNIBUS_PUBLIC_ORIGINto match.
| Setting | Meaning |
|---|---|
./config:/config |
Database, covers, journal images. Back this up. |
./cache:/cache |
Thumbnails and audio transcodes. Safe to delete. |
/books, /audiobooks |
Your libraries. Add :ro to make them read-only (disables in-app uploads). |
PUID, PGID |
Run as this user and group. Files land owned by you. |
OMNIBUS_PUBLIC_ORIGIN |
The address you open in the browser. Must match, or login fails. Comma-separate several. Kobo sync also reads it. A Kobo leaves the port off its requests, so its download and cover links take the port from the entry with the same scheme and host. |
OMNIBUS_SECURE_COOKIES |
0 on plain http. 1 or removed behind HTTPS. |
EBOOK_LIBRARY_PATH, AUDIOBOOK_LIBRARY_PATH |
Library folders inside the container. Leave as is. Remove both to set libraries in the app instead. |
More optional settings: .env.example.
- Back up
config. It cannot be rebuilt. - Skip
cache. Omnibus rebuilds it. - Your library folders are yours. Omnibus never moves or renames files in them.
-
Terminate TLS in nginx, Caddy or Traefik. Proxy to port 3000.
-
Set
OMNIBUS_PUBLIC_ORIGINto yourhttps://address. -
Set
OMNIBUS_SECURE_COOKIESto1, or remove it. -
Let large uploads through. A big audiobook can take minutes to send, and the server then scans it into the library before it answers. Allow request bodies up to
OMNIBUS_MAX_UPLOAD_BYTES(1 GiB by default) and don't time the transfer out:- nginx: raise
client_max_body_size(1 MB by default) andproxy_read_timeout(60 s). - Traefik: raise the entrypoint's
transport.respondingTimeouts.readTimeout(60 s by default in v3). - Caddy: the defaults already allow it.
- nginx: raise
-
Optional:
OMNIBUS_TRUST_FORWARDED_FOR: "1"so rate limiting sees real client IPs. Only if your proxy strips incomingX-Forwarded-For. -
Optional:
OMNIBUS_METRICS_TOKEN: "<random>"to open the Prometheus scrape endpoint. Without itGET /metricsanswers 404. Generate one withopenssl rand -hex 32and hand the same value to your scraper:scrape_configs: - job_name: omnibus bearer_token: "<the same value as OMNIBUS_METRICS_TOKEN>" static_configs: - targets: ["omnibus:3000"]
Keep
/metricsoff the public internet regardless — the token protects the payload, not the port.
docker compose pull
docker compose up -dlatestis the newest release.- Pin a version with a tag, e.g.
sesloan/omnibus:0.37.4. - Database migrations run on start.
- Add
OMNIBUS_INITIAL_ADMIN: "yourusername"toenvironment. Use an account that exists. - Restart once. That account is now admin.
- Remove the line. It re-promotes on every start while set.
- Clone the repo.
- In
docker-compose.yml, replaceimage:withbuild: .. - Run
docker compose up -d --build. The first build is slow.
- Login does nothing / 403.
OMNIBUS_PUBLIC_ORIGINdoes not match your browser address, orOMNIBUS_SECURE_COOKIESis not0on plain http. - Page will not load. The host port is taken, or you opened the container port instead of the host port.
- Library is empty. The host paths on the left of
/booksand/audiobooksdo not exist, or thePUIDuser cannot read them. - Audiobooks will not play. Check
docker compose logs omnibusfor transcode errors. Confirm the audiobook folder is not empty. - Files owned by root. Set
PUIDandPGIDto your IDs. Thenchownanything created before the change.
- Journal images used to live under
/cache. - First start after upgrading moves them to
/config/journal-images. - The log line
relocated journal images out of the data dir defaultreportsmovedandfound. Equal means done. movedlower thanfound? Afailed to relocate journal imagewarning names each file. Fix those before deletingcache.- Cache already cleared on an affected release? Those images are gone. Their entries show a broken image.