added audiobookshelf
This commit is contained in:
@@ -36,6 +36,7 @@ handled separately — see [Exposing services](#exposing-services).
|
|||||||
|
|
||||||
| Service | Port | Notes |
|
| Service | Port | Notes |
|
||||||
|---------|------|-------|
|
|---------|------|-------|
|
||||||
|
| [audiobookshelf](audiobookshelf/) | 13378 | Audiobooks and podcasts, with per-user progress sync |
|
||||||
| [cloudflare-tunnel](cloudflare-tunnel/) | — | Outbound connector. Exposes other services without opening a port |
|
| [cloudflare-tunnel](cloudflare-tunnel/) | — | Outbound connector. Exposes other services without opening a port |
|
||||||
| [jellyfin](jellyfin/) | 8096 | Media streaming. Also 7359/udp for auto-discovery |
|
| [jellyfin](jellyfin/) | 8096 | Media streaming. Also 7359/udp for auto-discovery |
|
||||||
| [openwebui](openwebui/) | 3033 | LLM chat UI, talks to an external model backend |
|
| [openwebui](openwebui/) | 3033 | LLM chat UI, talks to an external model backend |
|
||||||
|
|||||||
@@ -0,0 +1,29 @@
|
|||||||
|
# Copy to .env and adjust. .env is git-ignored; this file is not.
|
||||||
|
|
||||||
|
# ─── Identity ───────────────────────────────────────────────────────
|
||||||
|
# Defaulted to 1000/1000 in compose.yaml. Unlike the LinuxServer images in
|
||||||
|
# this repo, these are NOT passed to the container as PUID/PGID -- that image
|
||||||
|
# ignores them. They feed Docker's `user:` directive, which actually changes
|
||||||
|
# the uid the process runs as. Must own CONFIG_PATH, METADATA_PATH and be able
|
||||||
|
# to read the media.
|
||||||
|
#PUID=1000
|
||||||
|
#PGID=1000
|
||||||
|
|
||||||
|
#TZ=Europe/Paris
|
||||||
|
|
||||||
|
# ─── Paths ──────────────────────────────────────────────────────────
|
||||||
|
# Audiobookshelf's database and settings. Small; defaults to ./config.
|
||||||
|
#CONFIG_PATH=./config
|
||||||
|
|
||||||
|
# Cover art, cached metadata, downloads. Grows with your library.
|
||||||
|
#METADATA_PATH=./metadata
|
||||||
|
|
||||||
|
# REQUIRED. The parent folder holding Audiobooks/ and Podcasts/.
|
||||||
|
# compose.yaml mounts ${MEDIA_PATH}/Audiobooks and ${MEDIA_PATH}/Podcasts.
|
||||||
|
MEDIA_PATH=/srv/media
|
||||||
|
|
||||||
|
# ─── Ports ──────────────────────────────────────────────────────────
|
||||||
|
# Host port only. Do NOT add PORT to the container's environment -- the image
|
||||||
|
# reads PORT to decide what it listens on internally, which would break the
|
||||||
|
# 13378:80 mapping.
|
||||||
|
#PORT=13378
|
||||||
@@ -0,0 +1,90 @@
|
|||||||
|
# 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) — as with Jellyfin,
|
||||||
|
the mobile apps won't understand a forward-auth login page.
|
||||||
|
|
||||||
|
## Links
|
||||||
|
|
||||||
|
- Upstream docs: <https://www.audiobookshelf.org/docs>
|
||||||
|
- Image: <https://github.com/advplyr/audiobookshelf/pkgs/container/audiobookshelf>
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
services:
|
||||||
|
audiobookshelf:
|
||||||
|
image: ghcr.io/advplyr/audiobookshelf:latest
|
||||||
|
container_name: audiobookshelf
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
# NOT a LinuxServer image: no s6, no init script -- tini execs straight
|
||||||
|
# into node, as root. PUID/PGID would be silently ignored, so ownership is
|
||||||
|
# set with Docker's own `user:` instead. See the README.
|
||||||
|
user: "${PUID:-1000}:${PGID:-1000}"
|
||||||
|
|
||||||
|
environment:
|
||||||
|
- TZ=${TZ:-Etc/UTC}
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
- ${CONFIG_PATH:-./config}:/config
|
||||||
|
- ${METADATA_PATH:-./metadata}:/metadata
|
||||||
|
- "${MEDIA_PATH:?set MEDIA_PATH in .env to the parent of your Audiobooks/Podcasts folders}/Audiobooks:/audiobooks"
|
||||||
|
- ${MEDIA_PATH}/Podcasts:/podcasts
|
||||||
|
|
||||||
|
ports:
|
||||||
|
# 13378 is the conventional host port; the container always listens on 80.
|
||||||
|
- "${PORT:-13378}:80"
|
||||||
Reference in New Issue
Block a user