Installing Audiobookshelf with Docker and Caddy

Cet article est aussi disponible en français

Audiobookshelf (ABS to its friends) is a self-hosted audiobook and podcast server. You point it at a folder and it turns it into a clean library, with covers, chapters and listening progress synced across all your devices. For podcasts, it subscribes to the feeds and downloads new episodes on its own. It's a bit like Plex for audiobooks, and it has been running on my server for quite a while.

It supports multiple users, so your friends and family can enjoy it too.

1. What you need before starting

  • a server with Docker and the docker compose plugin;
  • a domain name with a DNS record pointing to that server (in the examples: abs.example.com);
  • ports 80 and 443 open to the server: Caddy needs them to get its Let's Encrypt certificate.

2. A shared Docker network

Rather than publishing Audiobookshelf's port on the host and pointing Caddy at it, I put both containers on the same Docker network. Caddy then reaches ABS by its container name, and nothing is exposed apart from Caddy's ports 80 and 443. This network is created once and for all, by hand:

docker network create front_network

It is declared external in each compose.yml: it must therefore exist before the first up, otherwise the stack refuses to start.

3. The Audiobookshelf compose file

In a dedicated folder, for example ~/docker/audiobookshelf/, a compose.yml file:

services:
  audiobookshelf:
    image: ghcr.io/advplyr/audiobookshelf:latest
    container_name: audiobookshelf
    restart: unless-stopped
    # No privilege escalation inside the container
    security_opt:
      - no-new-privileges:true
    # "The service answers", not just "the container is running"
    healthcheck:
      test: ["CMD-SHELL", "wget -q -O /dev/null http://127.0.0.1:$${PORT:-80}/healthcheck"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 30s
    volumes:
      - /media/library/Audiobooks:/audiobooks
      - /media/library/Podcasts:/podcasts
      - ./config:/config
      - ./metadata:/metadata
    environment:
      - TZ=Europe/Paris
    networks:
      - front_network

networks:
  front_network:
    external: true

A few explanations:

  • /audiobooks and /podcasts: your media. The path inside the container is up to you; it's the one you'll pick when creating the libraries. ABS must be able to write to the podcasts folder, since it downloads episodes there.
  • /config: the database (an SQLite file) and the configuration. This is the folder you really don't want to lose.
  • /metadata: covers, cache, logs and ABS's built-in backups.
  • No ports section: that's on purpose, Caddy goes through the shared network. If you also want to reach it directly from your LAN (an app that doesn't go through the domain name, for instance), add ports: ["13378:80"].

Also avoid putting /config on a network share (NFS, SMB): SQLite copes very badly with network file systems. Your media, on the other hand, can live there just fine.

4. First start: create the root account BEFORE opening access

This is the most important pitfall in this article. On first launch, Audiobookshelf shows a setup page asking you to choose the password of the root account. This page is available to anyone as long as nobody has filled it in. If you put the site on the Internet before doing so, the first visitor to come along (or a bot scanning newly issued certificates, and they are quick) becomes the administrator of your instance.

So we first start the container without any Caddy route:

docker compose -f ~/docker/audiobookshelf/compose.yml up -d

and set up the instance locally. With no published port, the simplest way is to get the container's IP and open an SSH tunnel from your computer:

# on the server
docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' audiobookshelf

# on your computer (replace the IP with the one you got)
ssh -L 13378:172.18.0.5:80 me@my-server

Then browse to http://localhost:13378, choose the root password, and only then move on to Caddy. You can check at any time whether the instance has been set up: the /status route returns "isInit": true once the root account exists.

5. The Caddy block

Caddy's compose file must join front_network too. Then, in the Caddyfile, three lines are enough:

abs.example.com {
	reverse_proxy audiobookshelf:80
}

And that's it. Caddy takes care of the HTTPS certificate on its own (issuing and renewal) as well as redirecting HTTP to HTTPS.

Restart Caddy:

docker compose -f ~/docker/caddy/compose.yml restart caddy

It may take a few dozen seconds, while the SSL certificate is being issued.

6. Creating your libraries

Once logged in as root on https://abs.example.com: Settings / Libraries / New library. Choose the type (Books or Podcasts) and select the folder as seen from the container: /audiobooks or /podcasts, not the host path.

For audiobooks, ABS works best with an Author/Title/files layout (or Author/Series/Title/). It can fetch metadata and covers online (Audible, Google Books…) through the match feature, which is very handy.

7. Apps

There is an official mobile app, and a few third-party apps use the Audiobookshelf API. For podcasts, I ended up writing my own, more on that soon. Either way, you enter the server URL (https://abs.example.com) and your credentials.

8. Updates and backups

Updating is the usual routine:

docker compose -f ~/docker/audiobookshelf/compose.yml pull
docker compose -f ~/docker/audiobookshelf/compose.yml up -d

For backups, there are two complementary options:

  • Built-in backups (Settings / Backups): ABS regularly archives its database and metadata into /metadata/backups. Handy, but they live on the same disk as the original: copy them somewhere else.
  • A copy of the SQLite file: stop the container, copy config/absdatabase.sqlite, start it again. Copying an SQLite database while it is in use can produce an inconsistent copy, hence the stop: a few seconds of downtime at night, nobody will notice.
cd ~/docker/audiobookshelf
docker compose stop audiobookshelf
cp config/absdatabase.sqlite ~/backups/abs-$(date +%F).sqlite
docker compose up -d audiobookshelf

As for your media, they get backed up along with the rest of your library.

Wrapping up

Twenty-odd lines of YAML, three lines of Caddyfile, and you have an audiobook and podcast server over HTTPS, synced across all your devices. The two things to remember: create the root account before opening access, and back up before every update.

Tested with Audiobookshelf 2.37.1 and Caddy 2.

Written by Kevin Gautreau — freelance PHP/Drupal developer & trainer in Auvergne, France. get in touch

Comments (0)