[{"data":1,"prerenderedAt":169},["ShallowReactive",2],{"seo-verification":3,"blog-audiobookshelf-self-hosted-audiobook-and-podcast-server-on-vps-ma-en":6,"promo-bar-likely":168},{"google":4,"bing":5},"EycwPY2XMyTkVzas3n1ygeNJFGAH513qrMjfDljzsMQ","",{"key":7,"data":8},"blog-audiobookshelf-self-hosted-audiobook-and-podcast-server-on-vps-ma-en",{"id":9,"slug":10,"slugs":11,"title":15,"excerpt":16,"readTime":17,"views":18,"isPinned":19,"noindex":19,"publishedAt":20,"updatedAt":21,"category":22,"categories":28,"featuredImage":30,"bgImage":31,"posterImage":32,"relatedSolution":33,"intro":36,"sections":37,"ctaTitle":163,"ctaBody":164,"ctaButton":165,"ctaUrl":166,"relatedPosts":167},326,"audiobookshelf-self-hosted-audiobook-and-podcast-server-on-vps",{"fr":12,"en":10,"ar":13,"es":14},"heberger-audiobookshelf-vps","audiobookshelf-خادم-أوديوبوك-وبودكاست-على-vps","audiobookshelf-audiolibros-y-podcasts-self-hosted-en-vps","Audiobookshelf — Self-Hosted Audiobook and Podcast Server on VPS","Deploy Audiobookshelf on a VPS: serve your audiobook and podcast library, sync with iOS and Android open-source apps, resume where you left off — no subscription.",12,0,false,"2026-01-11T00:00:00+00:00","2026-11-04T16:30:27+00:00",{"id":23,"name":24,"slug":25,"color":26,"icon":27},7,"Self-hosting","self-hosting","bg-indigo-500\u002F10 text-indigo-400","cloud",[29],{"id":23,"name":24,"slug":25,"color":26,"icon":27},null,"\u002Fblog\u002Fcovers\u002Fbg.svg","\u002Fblog\u002Fcovers\u002Fheberger-audiobookshelf-vps-poster.svg",{"categorySlug":34,"appSlug":35},"collaboration-productivity","audiobookshelf","Audiobookshelf is a self-hosted, open-source (GPL-3.0) audiobook and podcast server. Unlike cloud services, your audio files stay on your server — you own them entirely, with no subscription, no quota limits and no listening-habit tracking. The official iOS and Android apps — fully open-source — connect to your instance and sync progress, bookmarks and playlists across all your devices.",[38,42,52,55,58,80,83,86,118,121,139,142,145,148,156,160],{"type":39,"title":40,"body":41},"h2","Why self-host your audio library?","Audiobook platforms impose their catalogues, their DRM and their monthly fees. With Audiobookshelf you import your own M4B, MP3 or FLAC files — bought, borrowed or produced yourself — and reach them from any device through the open-source mobile apps. The library grows at your pace, not theirs.",{"type":43,"title":44,"items":45},"ul","What Audiobookshelf brings to a ServOrbit VPS",[46,47,48,49,50,51],"**Streaming and sync** — resume an audiobook where you left off, on the web or on mobile, without a third-party cloud account.","**Open-source iOS and Android apps** — the official clients are GPL-3.0, auditable and maintained by the community.","**Built-in scheduled backups** — the server can produce an archive of its own database and metadata, with adjustable retention.","**Built-in podcasts** — subscribe to RSS feeds, episodes are downloaded automatically and play in the same interface.","**Multi-user** — each family member gets their own account, history and playlists.","**Automatic metadata** — covers, chapters and descriptions can be fetched from providers such as Audnexus, with no manual entry.",{"type":39,"title":53,"body":54},"Supported audio formats","Audiobookshelf plays the common formats, including MP3, M4A, M4B (with chapters), AAC, OGG, FLAC, WAV and OPUS. M4B chapters appear in the player with their title and duration. DRM-protected Audible files do not play as they are: only import files you have the right to use, in an open format.",{"type":39,"title":56,"body":57},"Requirements and sizing","The server itself is modest: an Ubuntu 24.04 VPS with Docker is enough for a family. What weighs is disk, because the library (above all podcast episodes, downloaded over time) keeps growing, and CPU only when a client asks for transcoding through ffmpeg instead of direct playback. Size your data volume on your collection, and leave room for metadata, covers and backups, which live by default in the same `\u002Fmetadata` volume.\n\nThe server's SQLite database must stay on the VPS's local disk. The Audiobookshelf documentation is explicit: the `\u002Fconfig` folder must not be mounted on a network share, or you risk slowdowns and then corruption. The audio files themselves can live elsewhere.",{"type":59,"title":60,"steps":61},"steps","Deploy Audiobookshelf with Docker Compose",[62,65,68,71,74,77],{"title":63,"body":64},"Prepare the VPS and Docker","Connect over SSH, update the system, then install Docker and the Compose plugin. Check with `docker compose version`. On a ServOrbit VPS the Audiobookshelf template does this for you: this guide helps you understand what is running and take it over.",{"title":66,"body":67},"Create the folders and set the owner","Create one folder per volume: `mkdir -p \u002Fopt\u002Faudiobookshelf\u002F{config,metadata,audiobooks,podcasts}`. Pick the user the container will run as (for example 1000:1000), then give it the folders: `chown -R 1000:1000 \u002Fopt\u002Faudiobookshelf`. The four folders must be distinct mount points, not nested in one another.",{"title":69,"body":70},"Write the docker-compose.yml","Declare an `audiobookshelf` service with the image `ghcr.io\u002Fadvplyr\u002Faudiobookshelf` (pin the tag of the version you checked rather than `latest`), `restart: unless-stopped`, the directive `user: \"1000:1000\"`, the port `127.0.0.1:13378:80` and the four mounts `\u002Fopt\u002Faudiobookshelf\u002Fconfig:\u002Fconfig`, `\u002Fopt\u002Faudiobookshelf\u002Fmetadata:\u002Fmetadata`, `\u002Fopt\u002Faudiobookshelf\u002Faudiobooks:\u002Faudiobooks` and `\u002Fopt\u002Faudiobookshelf\u002Fpodcasts:\u002Fpodcasts`. Add `TZ=Africa\u002FCasablanca` (or your time zone) as an environment variable. Audiobookshelf does not use the PUID and PGID variables: the `user:` directive sets the user.",{"title":72,"body":73},"Start and check","Run `docker compose up -d`, then `docker compose logs -f audiobookshelf`. On first start the server applies its database migrations: wait for the line announcing it is listening on the container's port 80. If `docker compose ps` shows the service restarting constantly, go straight to the troubleshooting section below.",{"title":75,"body":76},"Create the admin account and the library","Open the interface (through an SSH tunnel or your domain), create the root account, then add a library pointing to `\u002Faudiobooks` and another to `\u002Fpodcasts`. Start a scan: books appear with their covers and chapters.",{"title":78,"body":79},"Connect the mobile app","In the iOS or Android app, enter your instance's HTTPS address, your username and password. Progress then syncs between the phone and the web. For permanent use, put an HTTPS reverse proxy in front of the container by following the Audiobookshelf documentation's \"Reverse Proxy\" page (notably the WebSocket passthrough).",{"type":39,"title":81,"body":82},"Setup without a domain name","Audiobookshelf does not need a domain name to run. With the ServOrbit template, the container listens only on the VPS loopback, port 13780. Open an SSH tunnel from your machine: `ssh -L 13378:127.0.0.1:13780 root@\u003Cvps-ip>`, then browse to `http:\u002F\u002Flocalhost:13378`. For permanent use from the mobile app, attach a domain from your ServOrbit client area — nginx proxies the container over HTTPS — or use the free subdomain `{app}.{dns_slug}.servorbit-dns.com` included with every VPS.",{"type":39,"title":84,"body":85},"Volume permissions and running as non-root","Four volumes, four roles. `\u002Fconfig` holds the SQLite database and the migration scripts. `\u002Fmetadata` holds metadata, covers, author images, logs, the cache and, by default, backups. `\u002Faudiobooks` and `\u002Fpodcasts` give access to the media files. The server must be able to write to `\u002Fconfig` and `\u002Fmetadata`; on `\u002Faudiobooks`, writing is only needed if you want it to write metadata next to the files, and on `\u002Fpodcasts` it is essential since episodes are downloaded there.\n\nBy default, the official example sets no user. To harden, add the `user:` directive: the container then no longer has root rights on the mounts, and that is precisely where permission errors appear. The rule is simple: the owner of the host folders must be the UID:GID of the `user:` directive. Test before loading the library: `docker compose exec audiobookshelf touch \u002Fconfig\u002Ftest \u002Fmetadata\u002Ftest`, then delete both files.\n\nOn a filesystem with ACLs (ZFS with NFSv4 ACLs, for example), a `chown` is not always enough: the incident described below illustrates it, with a container running as user 568, all capabilities dropped, on a ZFS dataset.",{"type":87,"title":88,"headers":89,"rows":93},"comparison","Named volume or host folder for \u002Fconfig and \u002Fmetadata",[90,91,92],"Criterion","Docker named volume","Host folder",[94,98,102,106,110,114],[95,96,97],"Initial owner","Managed by Docker, often root","You set it yourself with chown",[99,100,101],"Compatibility with `user:`","Check before the first import","Direct, if the UID:GID matches",[103,104,105],"Cold backup","Use `docker volume inspect` to find the path","Direct `rsync` of the folder",[107,108,109],"Path readability","Less obvious","Fixed, known path",[111,112,113],"Portability to another VPS","Volume export to plan","Copy the folder",[115,116,117],"Recommended use","Quick trial, ready-made template","Production with a non-root user",{"type":39,"title":119,"body":120},"Consistent backups: what the built-in backup covers","Audiobookshelf can create its own backups from the interface (schedule, number of backups kept, maximum size). Each archive contains the database and the cover images from the metadata folder; the media files stored with library items are not in it. By default, archives are written to `\u002Fmetadata\u002Fbackups`, that is on the same disk as the data: a VPS failure takes both. Copy them off the server regularly.\n\nA backup only protects if it is consistent. The database is a live SQLite file: copying `\u002Fconfig` with `cp` or `rsync` while the server writes (listening progress, scans) can produce an inconsistent file. Two safe methods: use the server's built-in backup, then copy the archive it produced; or stop the container for the duration of the copy. Audio files are backed up separately, with `rsync` or a deduplicating backup tool.\n\nA restore is done on the same kind of system: the documentation warns that a Linux backup is restored on Linux, and that switching from one installation method to another can lose progress and metadata.",{"type":59,"title":122,"steps":123},"Cold backup and manual restore",[124,127,130,133,136],{"title":125,"body":126},"Stop the container","From the compose folder, run `docker compose stop audiobookshelf`. No writes are in progress on the database any more.",{"title":128,"body":129},"Copy the configuration and metadata","Copy `\u002Fopt\u002Faudiobookshelf\u002Fconfig` and `\u002Fopt\u002Faudiobookshelf\u002Fmetadata` to a location off the VPS with `rsync -a`, keeping permissions. Add the audio folders according to your media backup strategy.",{"title":131,"body":132},"Restart and check","Run `docker compose start audiobookshelf` and check in the logs that the server is listening again. The interruption lasts as long as the database copy.",{"title":134,"body":135},"Restore from a server archive","Stop the container, unzip the most recent archive from `metadata\u002Fbackups`, copy `audiobookshelf.sqlite` into the configuration folder, replacing the existing file, then copy the `metadata-authors` and `metadata-items` folders to `authors` and `items`. If the archive is unusable, try the previous one. The Backups page of the interface also offers a restore button.",{"title":137,"body":138},"Test a dry-run restore","Once a quarter, restore a backup on a test VPS and check that users, progress and libraries are there. A backup never restored remains a hypothesis.",{"type":39,"title":140,"body":141},"Updates and versions: pin rather than follow latest","The ServOrbit template pulls the `latest` image. It is convenient, but it exposes you to regressions from one version to the next. The documented update is simple: `docker compose pull`, `docker compose down`, `docker compose up --detach`. Before each update, take a backup (built-in or cold) and read the release notes on the GitHub repository's releases page.\n\nA recent case justifies this. Version `2.37.0` moved the server to Node.js 24, and `2.37.1` was hit by a restart loop on some installations (see below). The fix is published in `2.37.2`, which is, at the time of writing, the latest stable version listed by the project. A pinned tag and a prior backup let you roll back without improvising.",{"type":39,"title":143,"body":144},"Troubleshooting: restart loop at startup (EPERM … copyfile)","Symptom: the container restarts in a loop after an upgrade to `2.37.1`, and the logs show \"Failed to copy migrations to the config directory\", then \"EPERM: operation not permitted, copyfile\" from the `\u002Fapp\u002Fdist-server\u002Fserver\u002Fmigrations\u002F` folder to `\u002Fconfig\u002Fmigrations\u002F`, followed by \"Database migration failed\".\n\nActual state of the incident (issue no. 5637 of the advplyr\u002Faudiobookshelf repository, opened in October 2026): it is closed. The reporter used TrueNAS SCALE, a container running as user 568, all capabilities dropped and `no-new-privileges`, with `\u002Fconfig` on a ZFS dataset as a bind mount. Several TrueNAS users reported the same thing. No root cause is formally established in the discussion; a test showed `copyFileSync` failing with EPERM on that mount while writing a file directly worked with the same user, and a regression in the copy path linked to Node.js 24 is suspected. The fix (PR no. 5668) adds a fallback when the copy fails; it ships in `2.37.2`.\n\nRemedy: upgrade to `2.37.2` or later. If you cannot update right away, the workaround mentioned in the issue is to go back to `2.36.1` with a backup taken before the update. If the same message persists after the update, check the owner of the configuration folder and the dataset ACLs: it is no longer that bug.",{"type":39,"title":146,"body":147},"Troubleshooting: the nightly backup crashes the container (SQLITE_BUSY)","Symptom: the server stops at the scheduled backup time, with \"FATAL: [Server] Uncaught exception\" and `SQLITE_BUSY: database is locked`. With `restart: unless-stopped`, Docker restarts the container: you only see a brief outage, revealed by a non-zero restart counter (`docker inspect --format '{{.RestartCount}}' \u003Ccontainer>`; replace the name with your container's).\n\nActual state (issue no. 4572, opened in August 2025): it is still open. A contributor explains the cause: the SQLite backup emits the \"database busy\" error as an event with no listener, which Node.js treats as an uncaught exception, and no retry is made. The crash happens when another write, for example a client saving listening progress, holds the lock for more than a second during the copy. PR no. 5660 (batched backup that retries on lock, and session errors logged instead of crashing) is open and not merged to date: no published version contains it. An earlier competing PR was closed in favour of this one.\n\nIn the meantime, three workarounds reported in the issue: move the backup away from listening hours (dawn rather than evening); keep `restart: unless-stopped` so the container comes back on its own; or replace the built-in backup with a scheduled cold backup on the host, which stops the container for a few moments. Reminder from the documentation: the database must be on a local disk, never on a network share.",{"type":43,"title":149,"items":150},"Other common errors",[151,152,153,154,155],"**Permission denied in the logs** — the owner of the host folders does not match the UID:GID of the `user:` directive. Fix with `chown -R`, then restart.","**Empty library after the scan** — the library path is not the container's path. Add `\u002Faudiobooks` or `\u002Fpodcasts`, not a host path.","**\"Cannot find module '\u002Findex.js'\"** — the documentation points to a stale image cache in some container managers: recreate the container or stack after a `docker compose pull`.","**The mobile app cannot connect** — check the HTTPS address, the certificate and the WebSocket passthrough in the reverse proxy; an SSH tunnel only serves the browser.","**Container \"unhealthy\"** — the health check queries the container's port 80: look at `docker compose logs` to see whether a migration fails at startup.",{"type":157,"title":158,"body":159},"tip","Minimal hardening","Pin the image tag, run the container with `user:`, publish the port only on `127.0.0.1` behind an HTTPS reverse proxy, copy the archives from `\u002Fmetadata\u002Fbackups` off the VPS every week and test a restore. This guide is provided as is: ServOrbit does not support the application itself.",{"type":39,"title":161,"body":162},"Going further","Once the server is stable, add a second layer of protection: an encrypted backup of the configuration folders to remote storage, and an alert if the container restarts more than once a day. Keep following the issues cited here: the backup crash will need checking again as soon as PR no. 5660 is merged and released.","Deploy Audiobookshelf on your VPS","ServOrbit provisions an Ubuntu 24.04 VPS and launches Audiobookshelf in a Docker container within minutes — no manual configuration required. Your audiobooks, your rules, your infrastructure.","Deploy Audiobookshelf","\u002Fapplications\u002Fcollaboration-productivity\u002Faudiobookshelf",[],true,1794270369762]