Files
docker-compose-repo/audiobookshelf/README.md
T
2026-08-31 15:12:11 +02:00

162 lines
6.2 KiB
Markdown

# Audiobookshelf
Audiobook and podcast server. Tracks progress per user across devices, which is
the thing a plain file share can't do — pick up on your phone where the car
left off.
## Quick start
```bash
cp .env.example .env
$EDITOR .env # MEDIA_PATH is required
docker compose up -d
```
Open `http://<host>:13378` and create the admin account. Point the Audiobooks
library at `/audiobooks` and Podcasts at `/podcasts` — those are the paths
*inside* the container.
## Ports
| Port | Proto | Purpose |
|------|-------|---------|
| 13378 | http | Web UI and API (container listens on 80) |
## Why it looks like this
**The official image, not LinuxServer.** Audiobookshelf ships its own and it's
the one upstream actually tests. That's a different call from jellyfin, where I
stay on LinuxServer out of long habit — here there's no reason to add a layer.
**`user:` instead of `PUID`/`PGID`.** This is the part worth knowing, because
copying the pattern from the other services in this repo produces something
that *looks* right and silently isn't. The image's config:
```
User : '' <- empty, so root
Entrypoint: ['tini', '--']
Cmd : ['node', 'index.js']
```
There's no s6 layer and no init script — `tini` execs straight into Node. A
`PUID` environment variable is accepted and then read by nobody. Everything
gets written as root, and you find out when you try to move your library from
the host and can't.
Docker's own `user:` directive is the mechanism that actually works here, so
`PUID`/`PGID` in `.env` feed that instead. Same names as the rest of the repo,
different plumbing underneath.
**`/config` and `/metadata` are separate mounts** because they grow very
differently. `/config` is the SQLite database and settings — small, and the
thing to back up. `/metadata` is cover art, cached data and downloads, and
tracks the size of your library. Splitting them means a backup job can take the
first and skip the second.
**Two media mounts, not one.** Audiobookshelf wants each library rooted
separately, so `${MEDIA_PATH}` points at the parent and the compose file mounts
`Audiobooks/` and `Podcasts/` beneath it. Only `MEDIA_PATH` goes in `.env`.
## Gotchas
- **`PORT` is a container variable here.** The image reads `PORT` to decide
what it listens on internally. It's used in `compose.yaml` for the *host*
side of `13378:80` only — if you ever add it to the `environment:` block,
the container moves off port 80 and the mapping breaks with nothing in the
logs to explain it.
- **Switching to `user:` on an existing install needs a chown.** If you ran
this as root first, the files it created are root-owned and the container
now can't write them. `sudo chown -R 1000:1000 config metadata` once.
- **Back up `/config`.** It holds the database — accounts, libraries, and
everyone's listening progress. `/metadata` regenerates; `/config` doesn't.
- **Media can be mounted `:ro`** unless you turn on storing metadata alongside
the media files, which is off by default. Worth doing if you want the library
protected from the server.
## Exposing it
Publishes a plain HTTP port; nothing here is proxy-aware.
- [Reverse proxy with Caddy](../docs/reverse-proxy.md)
- [Cloudflare Tunnel](../cloudflare-tunnel/) — audio is far lighter than video,
but it's still media served through the proxy; read
[the limits](../docs/cloudflare-tunnel.md) before pointing a tunnel at it.
- [Single sign-on with Authentik](../docs/authentik-sso.md) — Audiobookshelf
speaks OIDC natively, so use that rather than forward auth: the mobile apps
can't render a forward-auth login page. See the section below.
## Single sign-on with Authentik
Worth doing here, because Audiobookshelf is one of the apps that speaks OIDC
itself — real accounts, real logout, and the mobile apps keep working. Forward
auth would break them.
**It needs a reverse proxy first.** The whole flow is built from absolute HTTPS
URLs, so there has to be a real hostname in front:
```caddy
audiobookshelf.example.com {
reverse_proxy <ip>:13378
}
```
Then follow
[Authentik's Audiobookshelf guide](https://integrations.goauthentik.io/media/audiobookshelf/):
create an OAuth2/OpenID Connect provider, note the application **slug**, and
put the issuer URL, client ID and client secret into
**Settings → Authentication** on the Audiobookshelf side. **Auto-populate**
fills in the OIDC endpoints for you.
### The redirect URIs are where this goes wrong
[Step 2 of the guide](https://integrations.goauthentik.io/media/audiobookshelf/#create-an-application-and-provider)
gives these three:
```
Strict Authorization https://audiobookshelf.company/auth/openid/callback
Strict Authorization https://audiobookshelf.company/auth/openid/mobile-redirect
Strict Post Logout https://audiobookshelf.company/login
```
Those did not work for me. Mine needed an extra `/audiobookshelf` path segment:
```
https://audiobookshelf.company.com/audiobookshelf/auth/openid/callback
https://audiobookshelf.company.com/audiobookshelf/auth/openid/mobile-redirect
```
**Don't guess at this — Audiobookshelf tells you the answer.** Its
**Settings → Authentication** page has a subfolder section that prints the exact
URIs to authorize:
> Authorize these URLs in your OAuth provider to allow redirection back to the
> web app after login:
>
> `https://<your.server.com>/audiobookshelf/auth/openid/callback`
> `https://<your.server.com>/audiobookshelf/auth/openid/mobile-redirect`
Copy those into Authentik verbatim. A mismatch surfaces as a generic error that
doesn't name the URI, which is why this is worth ten seconds of checking rather
than an evening of guessing.
### Mobile apps need their own redirect URIs
The phone clients don't come back over HTTPS — they hand off to a custom URL
scheme. These go in **Allowed Mobile Redirect URIs**:
```
audiobookshelf://oauth
https://authentik.company.com/auth/openid/mobile-redirect
plappa://oauth # Plappa, iOS
prologue://oauth # Prologue, iOS
```
One per app: a client you haven't listed fails at the last step of a login that
otherwise looked fine. Add the scheme for each third-party app you actually use.
## Links
- Upstream docs: <https://www.audiobookshelf.org/docs>
- Image: <https://github.com/advplyr/audiobookshelf/pkgs/container/audiobookshelf>