Use case · Audiobook server

Audiobookshelf server on a dedicated machine: Docker, root user, proxy, backups

An Audiobookshelf server is one Docker container, ghcr.io/advplyr/audiobookshelf, that listens on port 80 inside the container, keeps its SQLite database in /config and its covers, logs and backups in /metadata, and reads audiobooks and podcasts from folders you mount beside them. On a dedicated machine the library sits on local disks, the database stays off the network as the project requires, and a reverse proxy you control carries the WebSocket traffic the apps depend on.

See the machines

What the container keeps, and where

Audiobookshelf splits its state across two fixed paths and any number of library mounts. The project's Docker page names them, and the split decides how you lay out disks and what you back up.

Container pathHoldsPlacement
/configThe SQLite database and its migration scriptsLocal disk only. The docs warn that a database reached over the network will eventually corrupt
/metadataBook metadata, cover and author images, logs, the backups folderLocal disk; backups land in /metadata/backups unless BACKUP_PATH moves them
/audiobooks, /podcastsYour audio files: one folder per book (Author/Series/Book or Author/Book), one flat folder per podcast with no season subfoldersAny local disk or array in the machine

Folder layout is the most common source of trouble. A loose audio file next to a book folder can make several titles merge into one, and the fix is removing the item and rescanning, which drops its listening progress. Lay files out as Author/Series/Book or Author/Book before the first scan.

Sizing the machine

The project publishes no CPU or memory minimums, so size from what the server actually does. Disk is the library: the total size of the audio you own, plus room for podcast episodes you let it download. The CPU matters when a client cannot play a file as stored and the server converts it with FFmpeg on the fly; the Docker image is the only install method that ships FFmpeg 8. Memory has to hold the operating system, Docker and one Node.js process with its SQLite file.

That points to two shapes on the dedicated server range. A Moonshot cartridge is a whole small machine sold for one service per box, which is what a personal Audiobookshelf instance is. A large collection wants drive bays, and a build to order lets you pick the disks, count and RAID level, delivered in 4 to 24 hours. Racked machines are handed over in about 30 minutes once payment is approved.

What a whole machine changes

  • Local disks for /config. The SQLite file lives on the same machine as the server, which is the only placement the docs support.
  • Root. You choose the Docker version, the proxy, the firewall and the disk layout; nobody else runs anything on the box.
  • Unmetered port. Phones streaming chapters away from home and podcast downloads are not counted against any transfer allowance.
  • Out-of-band console on every racked single-, dual- and quad-socket server (HPE iLO, Dell iDRAC or a Supermicro BMC); among the cartridges, the m510 and m710x have one as well. A firewall mistake costs a console session, not a ticket.
  • Reinstall the OS from the control panel whenever needed. Linux images carry no charge.
  • AS19624, our own network, in New York, Miami, San Francisco, Amsterdam and Bucharest; see the city list and test IPs to pick the one nearest your listeners.

Install with Docker Compose

Install Docker Engine with the Compose plugin from Docker's own repository, then fence the host before any container starts. A port mapping without an address listens on every host address, 0.0.0.0 and [::] alike; on IPv4 that traffic skips ufw's rules, and on IPv6 it does too when Docker's own IPv6 networking is on. Publishing to 127.0.0.1 keeps the port local, and on Docker Engine 28 and later that loopback binding is reachable from the host alone. As root:

sed -i 's/^IPV6=.*/IPV6=yes/' /etc/default/ufw
ufw allow OpenSSH
ufw --force enable
mkdir -p /srv/abs/config /srv/abs/metadata /srv/media/audiobooks /srv/media/podcasts
chown -R you:you /srv/media
cd /srv/abs

Save this as /srv/abs/compose.yaml. It is the project's minimal example with the host port pinned to loopback and real paths filled in:

services:
  audiobookshelf:
    image: ghcr.io/advplyr/audiobookshelf:latest
    ports:
      - "127.0.0.1:13378:80"
    volumes:
      - /srv/abs/config:/config
      - /srv/abs/metadata:/metadata
      - /srv/media/audiobooks:/audiobooks
      - /srv/media/podcasts:/podcasts
    environment:
      - TZ=America/New_York
    restart: unless-stopped
  1. From inside /srv/abs, bring the container up with docker compose up -d.
  2. Copy in audiobooks that are yours to keep, such as DRM-free purchases and your own recordings, with rsync or scp over your own SSH login (the chown above lets you write there).
  3. The image ignores PUID and PGID. To run it as another user, add Compose's user: key and give that UID ownership of the four directories.

The root user comes first

Audiobookshelf has no default username or password: whoever loads the web page first sets the root account, which admins cannot edit afterwards. Create it while the port is still on loopback. Open the tunnel from your workstation under your normal login, ssh -L 13378:127.0.0.1:13378 you@host, browse to http://localhost:13378, set a long password, then add admin, user or guest accounts from Settings. Only then put the proxy in front.

A forgotten root password cannot be reset from the interface. The documented recovery is stopping the server and clearing that user's password field in the SQLite file by hand. Store it in a password manager the day you create it.

Reverse proxy and WebSockets

Audiobookshelf serves plain HTTP and has no remote-access feature of its own, so TLS belongs to a proxy. It also requires a WebSocket connection, so the proxy has to pass on the Upgrade and Connection request headers. This follows the project's NGINX example, pointed at the loopback port, with an IPv6 listener added:

server {
    listen 443 ssl;
    listen [::]:443 ssl;
    server_name books.example.com;
    ssl_certificate     /etc/ssl/books/fullchain.pem;
    ssl_certificate_key /etc/ssl/books/privkey.pem;

    location / {
        proxy_set_header X-Forwarded-For   $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header Host              $http_host;
        proxy_set_header Upgrade           $http_upgrade;
        proxy_set_header Connection        "upgrade";
        proxy_http_version 1.1;
        proxy_pass http://127.0.0.1:13378;
        proxy_redirect http:// https://;
        client_max_body_size 10240M;
    }
}
  • ufw allow 80,443/tcp opens the web ports; NGINX runs on the host, so ufw filters it like any service.
  • client_max_body_size is the docs' guard against upload failures on large book files.
  • Serving under a path instead of a subdomain works only at /audiobookshelf; the path is fixed.
  • The Caddy equivalent is a site block with reverse_proxy 127.0.0.1:13378.

Apps and listening progress

The Android and iOS apps are open source and still labelled beta. Android installs from Google Play. iOS ships through TestFlight, which Apple caps at 10,000 testers, so it is often full; the docs list the web client saved as a Progressive Web App (no offline playback) and third-party apps as stopgaps. The apps play and download; server management stays in a browser.

Progress syncs per connection profile. Media downloaded under one profile only syncs back through that same profile, so give every device the single public HTTPS name rather than a LAN address at home and another one outside.

Backups, updates and the licence

Backups. Settings has a Backups page where you set how many to keep and a size cap, where 0 means no limit; the project's README describes the automated backups as daily. Each backup holds the database and the cover images kept in the metadata folder. Covers stored beside the books are left out, and so is every audio file. A restore uses the Restore button, or by hand: stop the container, unzip the newest .audiobookshelf file, copy audiobookshelf.sqlite into /config and the metadata-items and metadata-authors folders back. A backup cannot move between install methods, Windows to Docker for example, without losing progress and metadata, and Windows backups restore only on Windows, Linux backups only on Linux. Copy the backups folder and the media directories off this machine yourself, to storage that does not share its disks.

Updates. From /srv/abs run docker compose pull, docker compose down, then docker compose up --detach. The FAQ says a server release generally arrives about monthly. :latest tracks stable releases, :edge follows every master commit, and a version tag pins a release you choose.

Licence. The server repository is GPL-3.0: no fee, no account with the project, and the source is public. Our general reading of the GPL, not a statement from the project's docs: obligations such as offering the source apply when you distribute copies, modified or not, and not when you only run it yourself.

Where it is the wrong tool

Audiobookshelf is built for spoken word: chapters, series, per-user position and podcast feeds. For films and TV, run Jellyfin on its own machine or Plex with Quick Sync; for a music collection with Subsonic clients, Navidrome fits better. Cover and author images are fetched without authentication by design, addressed by random UUIDs; the security page treats that as intended. Switching install method later, Windows to Docker for example, is unsupported and best effort, so start on Docker.

Questions

What are the default login details for a new install?

There are none. The first person to open the web interface sets the root username and password, and that account becomes the owner admins cannot edit. Do it through an SSH tunnel to the loopback port before a proxy publishes the site.

Do the built-in backups protect the audiobooks themselves?

No. They contain the SQLite database and the cover images kept in the metadata folder, which preserves users and progress. Covers saved beside the books and the audio files in your library mounts are not included; copy those separately, ideally to another machine.

Can /config sit on a NAS or network share?

The project says no. /config holds the SQLite database, and reaching it over the network degrades performance and eventually corrupts it. Keep it on a local disk of the machine running the container; the libraries can be any local array.

Why do the apps fail to connect through my proxy?

Audiobookshelf needs a WebSocket connection, so the proxy has to relay Upgrade and Connection over HTTP/1.1. A proxy that drops them breaks that connection. The NGINX block above carries both.

Can it run under a path such as /books?

Only under /audiobookshelf. Subfolder hosting needs no extra settings, but the path name is fixed by the project. Any other prefix needs its own subdomain.

Which Docker tag should I run?

:latest is the newest stable release and suits most servers. :edge is rebuilt from every master commit for people testing new features. A numeric tag such as 2.19.0 pins one release until you change it.

Run your audiobook library on your own hardware

Pick a cartridge for one personal library, or a build with the drive bays a large collection needs.

See the machines

Related on Server Room

Other use cases