Lab · Self-hosting
Tap a component to see its step.
- Browser / app · step 5 HTTPS client
- Caddy · step 4 container :80 and :443
- Audiobookshelf · step 2 127.0.0.1:13378
- Library · step 1 bind-mounted directories
- RSS feeds · step 6 external podcasts
Deploy Audiobookshelf v2.37.1 with Docker Compose and Caddy 2.11.7 as an HTTPS reverse proxy, with users, podcast RSS subscriptions and scheduled backups.
What you will build and why
You will set up your own audiobook and podcast server with Audiobookshelf: a multi-user library with per-user progress synced across devices, automatic podcast episode downloads through RSS subscriptions, and scheduled backups. It is meant for legal content: your own audiobooks, podcasts and music you already have.
In front of it goes Caddy as a reverse proxy with automatic HTTPS. Audiobookshelf requires a websocket connection, so the proxy is something to verify, not decoration. Everything lives in a single compose.yaml with pinned versions, and the app listens only on 127.0.0.1: Caddy is the only way in from outside.
These are instructions, not a run report: the output blocks are illustrative and may differ on your machine.

Requirements
Step by step
Prepare the data directories
Keep the library separate from the configuration. That way you can copy or move each part independently, and the container can be recreated without losing anything. Audiobookshelf cares about folder structure, so it pays to use one directory per content type.
mkdir -p ~/abs/{audiobooks,podcasts,music,config,metadata,caddy-data,caddy-config} cd ~/absWrite the complete Compose file
The file defines both services with exact tags. Audiobookshelf is published only on
127.0.0.1:13378so nobody reaches it without going through Caddy. Caddy mounts./Caddyfileas a file, which is why that file must exist before Caddy starts: otherwise Docker would create a directory with that name and Caddy would fail. We create it in step 4, and until then we only bring up Audiobookshelf.Replace
CHANGE_ME_ZONAwith your time zone, for exampleEurope/Madrid. Inside the container, the app uses/configfor the database and/metadatafor covers, cache and backups.File
compose.yamlservices: audiobookshelf: image: ghcr.io/advplyr/audiobookshelf:2.37.1 restart: unless-stopped ports: - "127.0.0.1:13378:80" environment: - TZ=CHANGE_ME_ZONA volumes: - ./audiobooks:/audiobooks - ./podcasts:/podcasts - ./music:/music - ./config:/config - ./metadata:/metadata caddy: image: caddy:2.11.7 restart: unless-stopped ports: - "80:80" - "443:443" volumes: - ./Caddyfile:/etc/caddy/Caddyfile:ro - ./caddy-data:/data - ./caddy-config:/config depends_on: - audiobookshelfReplace every CHANGE_ME_… value with your own before starting: never keep example passwords or keys.
Start only Audiobookshelf and create the root user
We start only the application service because the Caddyfile does not exist yet. Pulling the image first shows right away whether the tag resolves, before anything gets created.
Open
http://127.0.0.1:13378from the machine itself (or through an SSH tunnel if it is remote). The first time, it asks you to create the administrator user: pick a long, unique password rather than a default one.docker compose pull audiobookshelf docker compose up -d audiobookshelf docker compose ps docker compose logs --tail 20 audiobookshelfExpected output
# Salida ilustrativa: el formato exacto puede variar NAME IMAGE SERVICE STATUS abs-audiobookshelf-1 ghcr.io/advplyr/audiobookshelf:2.37.1 audiobookshelf UpAdd Caddy with HTTPS
Caddy obtains and renews certificates automatically for a public domain name that points to your server, with ports 80 and 443 reachable from the Internet. Replace
CHANGE_ME_DOMINIOwith your real domain.The minimal Caddyfile uses
reverse_proxyto the service by its Compose name. Audiobookshelf needs websockets, so do not consider this step done until you pass the verification below (login and live progress depend on it). If your setup does not work with the minimal configuration, check the project's reverse proxy documentation, which is the reference for this point.With the file in place, start Caddy.
File
CaddyfileCHANGE_ME_DOMINIO { reverse_proxy audiobookshelf:80 }Replace every CHANGE_ME_… value with your own before starting: never keep example passwords or keys.
docker compose up -d docker compose ps docker compose logs --tail 30 caddyCreate the libraries and users
Go to
https://CHANGE_ME_DOMINIOand sign in as root. In the settings, create one library per content type, pointing to the paths inside the container (/audiobooks,/podcasts,/music), not the host paths.Then create one user per person with custom permissions. It is better not to use the root account for everyday listening: that way listening progress is kept per user and you limit the damage if a session is compromised.
Lay out your audiobooks as
audiobooks/Author/Title/*.m4b. The folder structure affects how metadata is detected; see the project's library documentation.Subscribe to podcasts via RSS
In the podcast-type library, use search to add a podcast or paste its RSS feed URL. Enable automatic episode downloads so the server fetches them without intervention. Downloading to the server means you no longer depend on the original feed staying available, and it lets you listen offline from the companion app.
Audiobookshelf can also open its own RSS feeds for audiobooks and episodes, which is handy for listening in a podcast player. Protect those feeds like any other access point: anyone with the URL can listen.
Set up backups
In the app settings, enable the scheduled backup: it stores the database and metadata in
/metadata/backups. Mind the scope: this protects the configuration, users and progress, not your audio library.A backup that lives on the same machine is not a complete backup. Copy
~/abs/metadata/backupsand your content folders to another disk or machine with whatever tool you already use.ls -lh ~/abs/metadata/backups
Check that it works
Containers are running
Both services should show as up.
docker compose psHTTPS responds
Check that the domain answers over HTTPS. The exact response depends on the version and session state: a 200 or a redirect (301/302) at the root is reasonable; what you must not see is a certificate or connection error.
curl -sI https://CHANGE_ME_DOMINIOThe app listens only locally
Verify that port 13378 is bound to 127.0.0.1 and not to all interfaces. The exact output varies by system; look for the 127.0.0.1 address.
ss -tln | grep 13378Websocket and playback
Sign in from the browser through your domain, play an audio file and check that progress is saved and updates in a second session. If login works but state does not sync, check the proxy.
If something fails
Caddy will not start or a directory named Caddyfile appears
Caddy was started before the file was created and Docker created a directory instead. Stop everything, remove that directory, create the Caddyfile and start again.
docker compose down
rm -rf ./Caddyfile
# re-create the Caddyfile from step 4
docker compose up -dCaddy cannot get the certificate
Check that the domain's DNS points to the server's public IP and that ports 80 and 443 reach the host (firewall and router forwarding). Read Caddy's logs to see the exact reason.
docker compose logs --tail 50 caddyLogin works but the interface does not update or live playback fails
Audiobookshelf requires a websocket connection. If you use a different proxy or an intermediate layer (CDN, another proxy in front), check that it allows websockets. See the project's reverse proxy documentation.
The library shows up empty
Check that the library paths are the container ones (/audiobooks, etc.), that the files exist on the host and that the container user can read them. Review the application logs.
docker compose logs --tail 50 audiobookshelfHarden the setup
Keep the app on loopback only
The 127.0.0.1:13378:80 mapping stops anyone from reaching the app and bypassing HTTPS. Do not change it to 0.0.0.0.
Least-privilege users
Use root only for administration. Create regular accounts with custom permissions and unique passwords (replace any example value with your own).
Update with pinned tags and read the notes
Upgrade by changing the tag in compose.yaml after reading the release notes: v2.26.0 introduced a new authentication system and v2.37.0 updated Node.js to 24. Take a backup before every change.
docker compose pull
docker compose up -dBackups off the machine
Replicate the backups in metadata/backups and your library to another disk or machine.
Clean-up: undo the lab
Remove the lab
This deletes the containers, and the last command also deletes your data and library. Copy anything you want to keep first.
cd ~/abs
docker compose down
cd ~
rm -rf ~/absWhat is verified
- compose.yaml syntax (YAML parser and Compose structure)
- Caddyfile: no automatic validator, review it by hand
- Syntax of 12 command block(s) (bash -n in an isolated container, not executed)
- Versions (4), options (1) and config keys (8) checked against 17 official documentation pages
- Running the whole lab end to end: not executed
Automatic checks run on 10 October 2026. Items marked "·" were not executed: check them in your own environment.
Sources
- Introducción a Audiobookshelf audiobookshelf.org
- Versiones de Audiobookshelf github.com
- Repositorio de Audiobookshelf github.com
- El Caddyfile caddyserver.com
- Versiones de Caddy github.com
- docker compose up docs.docker.com
Did this lab work for you?
Rate it from 1 to 5 stars. One vote per person; you can change it any time.
Produced with AI support and reviewed by the newsroom



Comentarios
Publicar un comentario