Audiobookshelf is a free, open-source server for your audiobooks and podcasts. It keeps your place in every book across devices, fetches covers and metadata, downloads new podcast episodes on its own, and has companion apps for Android and iOS with offline listening. It is like having your own Audible, minus the subscription.
In this guide we will run Audiobookshelf in Docker using the official image, point it at your audiobook and podcast folders, and get it ready to sit behind a reverse proxy.
ghcr.io/advplyr/audiobookshelf.✅ Before you start
- A Linux host with Docker and Docker Compose v2 installed (
docker compose versionshould work). - Your audiobooks (and podcasts, if you like) on a local disk or mounted share, e.g.
/path/to/data/media/audiobooks. - A local disk for the config folder. Audiobookshelf keeps its SQLite database there, and SQLite over a network share ends in corruption.
- Optional: a reverse proxy such as Traefik or Nginx Proxy Manager, so the mobile apps can reach it from anywhere.
STEP 1: Find your user and group IDs
Audiobookshelf should run as a normal user, not as root. Log in to your Docker host over SSH and run:
idYou will see something like uid=1000(you) gid=1000(you). Make a note of the two numbers; they become PUID and PGID below.
Audiobookshelf does not use PUID/PGID variables. Instead we use Docker's own user: setting in the compose file, which does the same job.
STEP 2: Create the folders
I like to keep every app's data under one parent folder so backups are a single job. Create the folders for Audiobookshelf, plus the library folders if you do not have them yet:
mkdir -p /path/to/appdata/audiobookshelf/{config,metadata}
mkdir -p /path/to/data/media/{audiobooks,podcasts}
sudo chown -R 1000:1000 /path/to/appdata/audiobookshelf /path/to/data/media/audiobooks /path/to/data/media/podcastsSwap 1000:1000 for your own IDs from STEP 1. When you are done, the layout should look like this:
/path/to/appdata/audiobookshelf/
docker-compose.yml
config/ # SQLite database (keep on a local disk)
metadata/ # covers, author images, cache, logs and backups
/path/to/data/media/
audiobooks/ # one folder per book, ideally Author/Title/
podcasts/Folder layout
Audiobookshelf works best with one folder per book, for example
audiobooks/Terry Pratchett/Guards! Guards!/. Multi-file books stay together and the scanner gets the author and title right.Finally, this guide puts the app on the shared media Docker network used by the rest of my media stack, so other containers can reach it by name. If you followed the Jellyfin guide you already have it; otherwise create it once:
docker network create mediaSTEP 3: The compose file
Create /path/to/appdata/audiobookshelf/docker-compose.yml and paste in the following. Use the copy button in the top right corner of the block.
services:
audiobookshelf:
image: ghcr.io/advplyr/audiobookshelf:latest
container_name: audiobookshelf
hostname: audiobookshelf
restart: unless-stopped
user: "1000:1000" # your user:group IDs from STEP 1
environment:
- TZ=Europe/London # your time zone
volumes:
- /path/to/appdata/audiobookshelf/config:/config
- /path/to/appdata/audiobookshelf/metadata:/metadata
- /path/to/data/media/audiobooks:/audiobooks
- /path/to/data/media/podcasts:/podcasts
ports:
- 13378:80 # web UI (the container listens on 80)
networks:
- media
networks:
media:
external: truedocker-compose.yml
STEP 4: The settings explained
| Setting | What it does |
|---|---|
image |
The official Audiobookshelf image. latest follows stable releases; edge follows every commit, so avoid it unless you are testing. |
user |
Runs the container as your user and group, so files it writes belong to you. This replaces PUID/PGID, which this image does not use. |
TZ |
Time zone, for scheduled backups, podcast checks and logs. List of zones. |
/config |
The SQLite database: users, libraries, progress and settings. Must be on a local disk. |
/metadata |
Covers, author images, cache, logs and backups. Back up this folder and /config. |
/audiobooks / /podcasts |
Your libraries. Add as many extra mounts as you like (for example /ebooks), but keep each one a separate folder, not nested inside another mount. |
13378:80 |
The web UI. Only ever change the left-hand number; the app listens on 80 inside the container. |
STEP 5: Start Audiobookshelf
From the folder containing your compose file:
cd /path/to/appdata/audiobookshelf
docker compose up -d
docker compose logs -fWait until the logs settle down (press Ctrl+C to stop following them; the container keeps running), then check it is up:
docker ps --filter name=audiobookshelfSTEP 6: First-run setup
Open http://192.168.1.20:13378 in your browser, replacing the IP with your Docker host's address.
- Create the root user. The first screen asks for a username and password for the root (admin) account. Use a strong password such as
CHANGE_ME_STRONG_PASSWORD(please do change it), and sign in. - Add a library. Click Libraries → Add Library (or the prompt on the home page), name it Audiobooks, set the media type to Books, and add the folder
/audiobooks. Pick your preferred metadata provider, then Create. - Add podcasts (optional). Create a second library with the media type Podcasts and the folder
/podcasts, then search for shows to subscribe to. - Add other users. Under Settings → Users, give each person their own account so progress is tracked per listener.
- Get the apps. Install Audiobookshelf from Google Play or the App Store and sign in with your server address.
Settings → Backups can back up the database and images on a schedule. They land in
/metadata/backups; copy that folder somewhere off the server too.STEP 7: Put Audiobookshelf behind a reverse proxy
The mobile apps are at their best when they can reach your server from anywhere. Do that through a reverse proxy with HTTPS, or a VPN such as WireGuard or Tailscale, never by forwarding port 13378 directly. Audiobookshelf uses WebSockets for live progress sync, so the proxy must allow them. Point the proxy at port 80 if it reaches the container over the media network, or 13378 if it goes through the host.
Option A: Traefik (Docker labels)
If Traefik runs on the same Docker host and is attached to the media network, add these labels to the audiobookshelf service. They assume your HTTPS entry point is called websecure and your certificate resolver is called cloudflare; change them to match your Traefik config.
labels:
- traefik.enable=true
- traefik.http.routers.audiobookshelf.rule=Host(`audiobooks.example.com`)
- traefik.http.routers.audiobookshelf.entrypoints=websecure
- traefik.http.routers.audiobookshelf.tls.certresolver=cloudflare
- traefik.http.services.audiobookshelf.loadbalancer.server.port=80docker-compose.yml (extra lines)
Option B: Traefik (file provider)
If Traefik runs on a different machine, add a router and service to your dynamic config file instead:
http:
routers:
audiobookshelf:
rule: Host(`audiobooks.example.com`)
entryPoints:
- websecure
tls:
certResolver: cloudflare
service: audiobookshelf
services:
audiobookshelf:
loadBalancer:
servers:
- url: http://192.168.1.20:13378dynamic.yml
Option C: Nginx Proxy Manager
Add a Proxy Host for audiobooks.example.com with scheme http, forward hostname audiobookshelf (if NPM is on the media network) or 192.168.1.20, and forward port 80 (or 13378 if you use the host IP). Request a certificate on the SSL tab and tick Force SSL. Tick Websockets Support, which Audiobookshelf needs.
Updating Audiobookshelf
The latest tag always follows the newest stable release. To update:
cd /path/to/appdata/audiobookshelf
docker compose pull
docker compose up -d
docker image prune -f./config and ./metadata and read the release notes. If a GUI tool such as Portainer or Synology Container Manager gives you Cannot find module '/index.js' after an update, recreate the container so it uses the new image.Troubleshooting
The library is empty after a scan. Check the container can see the files: docker exec -it audiobookshelf ls -l /audiobooks. If you get Permission denied, the user: IDs cannot read the folder; fix it on the host with chown/chmod.
Books are split up or have the wrong author. Use one folder per book (ideally Author/Title/), then use Match on the book to pull the right metadata.
Progress does not sync through the proxy. WebSockets are blocked. Turn on WebSocket support in your proxy.
"Database is locked" or corruption errors. /config is on a network share. Move it to a local disk and restore from your latest backup.
port is already allocated when starting. Something else is using 13378. Change the left-hand side of the port mapping, for example 13379:80.
That's it! Your own audiobook and podcast server, with progress synced everywhere. Pop your headphones on and enjoy the next chapter. 🎧