| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Name | Name | Last commit date | ||
|---|---|---|---|---|
A Docker/Podman Compose stack for deploying Audiobookshelf with media on Hetzner Object Storage (S3) or a Hetzner Storage Box, and Caddy as the default reverse proxy.
Built for small VPS disks: your library stays on Hetzner. This stack FUSE-mounts the remote with rclone (rclone mount) — it does not sync or mirror the library onto the VPS. Local disk only holds:
Create a Hetzner Object Storage bucket and S3 credentials.
Copy and edit the environment file:
cp .env.example .env
# Set S3_ACCESS_KEY, S3_SECRET_KEY, S3_REGION, S3_ENDPOINT, S3_BUCKET
# Leave STORAGE_BACKEND=objectstorage
# Tune VFS_CACHE_MAX_SIZE if the VPS disk is tight (default 2G)Create local data directories:
mkdir -p data/config data/metadataStart the stack (rclone mounts the bucket; nothing is synced down):
docker compose up -dOpen your instance (e.g. https://books.example.com or http://localhost if DOMAIN=:80).
In Audiobookshelf, add a library pointing at /audiobooks (and optionally /podcasts, /ebooks).
Upload media to Hetzner (from your PC or another machine — not a VPS sync job):
rclone copy ./my-book/ hetzner:my-audiobooks/audiobooks/my-book/Create a Hetzner Storage Box and enable SSH support in Hetzner Console.
Copy and edit the environment file:
cp .env.example .env
# Set STORAGE_BACKEND=storagebox
# Set STORAGEBOX_HOST, STORAGEBOX_USER, STORAGEBOX_PORT (default 23)
./scripts/obscure-password.sh 'your-storagebox-password'
# Paste the output into STORAGEBOX_PASS=Create folders on the Storage Box (audiobooks, and optionally podcasts / ebooks), then start with the Storage Box overlay:
mkdir -p data/config data/metadata
docker compose -f compose.yml -f compose.storagebox.yml up -dThat runs rclone mount over SFTP into /audiobooks (FUSE). Files remain on the Storage Box.
In Audiobookshelf, add libraries pointing at /audiobooks (and optionally /podcasts, /ebooks).
Upload media to the Storage Box from elsewhere (PC, another host). Examples:
# rclone (SFTP remote named storagebox)
rclone copy ./my-book/ storagebox:audiobooks/my-book/
# or rsync over SSH port 23
rsync -e 'ssh -p23' -av ./my-book/ uXXXXX@uXXXXX.your-storagebox.de:audiobooks/my-book/Storage Box accounts allow a limited number of simultaneous connections (typically 10). The Storage Box overlay caps rclone checkers to stay within that limit.
| File | Description |
|---|---|
| compose.yml | Default — Object Storage FUSE mount + Audiobookshelf + Caddy |
| compose.core.yml | Sidecar stack without proxy (exposes port 13378) |
| compose.storagebox.yml | Overlay — mounts Storage Box via SFTP instead of S3 |
| compose.coolify.yml | Coolify — Object Storage mount (no Caddy / no custom networks) |
| compose.coolify.storagebox.yml | Coolify — Storage Box SFTP mount |
| compose.caddy.yml | Caddy overlay — pairs with any core file |
| compose.rclone-plugin.yml | Plugin stack + Caddy (all-in-one) |
| compose.rclone-plugin.core.yml | Plugin stack without proxy |
| compose.rclone-plugin.caddy.yml | Caddy overlay for plugin core |
Uses an rclone container with FUSE. No host plugin install required.
# Object Storage — all-in-one with Caddy
docker compose up -d
# Storage Box — all-in-one with Caddy
docker compose -f compose.yml -f compose.storagebox.yml up -d
# Modular — no proxy
docker compose -f compose.core.yml up -d
docker compose -f compose.core.yml -f compose.storagebox.yml up -d
# Modular — with Caddy
docker compose -f compose.core.yml -f compose.caddy.yml up -d
docker compose -f compose.core.yml -f compose.storagebox.yml -f compose.caddy.yml up -d
# Optional podcast / ebook libraries
docker compose --profile podcasts --profile ebooks up -d
docker compose -f compose.yml -f compose.storagebox.yml --profile podcasts --profile ebooks up -dUses the native rclone volume driver (still a mount, not a sync). Requires a one-time host setup.
# 1. Configure credentials on the host
sudo mkdir -p /var/lib/docker-plugins/rclone/config
sudo cp rclone/rclone.conf.example /var/lib/docker-plugins/rclone/config/rclone.conf
sudo $EDITOR /var/lib/docker-plugins/rclone/config/rclone.conf
# 2. Install the plugin
./scripts/install-rclone-plugin-docker.sh
# 3. Set RCLONE_REMOTE in .env
# Object Storage: RCLONE_REMOTE=hetzner:my-audiobooks
# Storage Box: RCLONE_REMOTE=storagebox:
# 4. Start the stack
docker compose -f compose.rclone-plugin.yml up -d
# Modular
docker compose -f compose.rclone-plugin.core.yml -f compose.rclone-plugin.caddy.yml up -dCreate audiobooks, podcasts, and ebooks prefixes on the remote before starting (plugin subpath mounts require them).
Yes — use the Coolify-specific compose files. Coolify already provides the reverse proxy, so these files omit Caddy, custom networks, fixed container_names, and host port publishes.
In Coolify: New Resource → your Git repo → build pack Docker Compose.
Set Docker Compose Location to one of:
Fill environment variables in the Coolify UI:
Assign your domain:
Deploy.
In Audiobookshelf: Settings → Libraries → Add Library and set the folder to one of:
Type the path if the browser does not show it. Do not use a host path like /data/coolify/....
Create those folders on the remote before the first scan. Storage Box: enable SSH support (port 23).
If uploads in ABS never appear on the Storage Box (or remote files never appear in ABS), ABS is using a local VPS folder while rclone FUSE is separate.
Required once on the Coolify host before a working deploy:
# 1) make the filesystem shared ( /data/coolify itself is often NOT a mountpoint )
findmnt -T /data/coolify
sudo mount --make-rshared "$(findmnt -n -o TARGET -T /data/coolify)"
# 2) allow FUSE allow_other
grep -q user_allow_other /etc/fuse.conf 2>/dev/null || echo user_allow_other | sudo tee -a /etc/fuse.conf
# 3) delete local shadow files ABS wrote on the VPS
sudo find /data/coolify/applications/w2cqu8zgqq5hw35ol4fzkanb/mnt -mindepth 1 -deleteIn Coolify env set (example):
HOST_MNT_BASE=/data/coolify/applications/w2cqu8zgqq5hw35ol4fzkanb/mnt AUDIOBOOKSHELF_HOST=books.example.com STORAGEBOX_PATH=media/ STORAGEBOX_AUDIOBOOKS_DIR=audiobooks STORAGEBOX_PODCASTS_DIR=podcast STORAGEBOX_EBOOKS_DIR=ebooks
rclone mounts Storage Box on the host via nsenter (in-container fusermount fails on Coolify paths). Enable Raw Compose Deployment. ABS binds ./mnt/… after audiobooks mount is healthy.
If rclone logs fusermount3: Permission denied or /dev/fuse missing, confirm Raw Compose Deployment is enabled.
| Topic | Detail |
|---|---|
| Proxy | Raw Compose: set AUDIOBOOKSHELF_HOST (Traefik labels). Non-raw: Coolify Domains on audiobookshelf |
| Domains missing | Expected with Raw Compose — use AUDIOBOOKSHELF_HOST instead of the Domains UI |
| Networks | Coolify compose files define no custom networks (required for Traefik) |
| Media mounts | rclone FUSE on host at $HOST_MNT_BASE/…; ABS binds ./mnt/… after audiobooks mount is healthy |
| HOST_MNT_BASE | Required env (not a volume source): /data/coolify/applications/<uuid>/mnt |
| Upload not on box | ABS wrote to local VPS shadow. Confirm rclone logs say HOST mounting, set HOST_MNT_BASE, clear …/mnt/*, redeploy |
| rclone unhealthy | Open rclone logs. Often missing Raw Compose, bad HOST_MNT_BASE, or bad remote folder (podcast vs podcasts) |
| Raw mode | Required for host FUSE (privileged / pid:host / /dev/fuse); use AUDIOBOOKSHELF_HOST for domains |
| FUSE | privileged: true, /dev/fuse, pid: host; alpine downloads rclone binary at start |
| Healthcheck | Greps host /proc/1/mounts for $HOST_MNT_BASE/<lib> |
| Password | Coolify Storage Box compose expects a plain STORAGEBOX_PASS |
| Paths | Default remote prefix media/ + dirs audiobooks / podcast / ebooks (override via env) |
| Leftover dirs | If an older deploy created fuse.conf/entrypoint.sh as directories under the app path, delete them before redeploying |
| Build ${ error | Coolify rejects ${…} in volume sources — use literal ./mnt/… (this compose) |
| Build :: error | Short :rshared syntax + absolute paths can yield mnt:: — use long bind syntax |
| Empty / no sync | ABS /audiobooks has files but Storage Box empty ⇒ local VPS shadow. Clear …/mnt/*, confirm HOST mounting in logs, redeploy |
| Disk | Still a mount, not a sync. Lower VFS_CACHE_MAX_SIZE on small VPS disks |
| Logs | Check rclone logs for HOST mounting hetzner:media/audiobooks |
The sidecar stack (compose.yml) is the recommended path on Podman.
# Object Storage
podman compose -f compose.yml -f podman/compose.override.yml up -d
# Storage Box
podman compose -f compose.yml -f compose.storagebox.yml -f podman/compose.override.yml up -dDocker's managed plugin (docker plugin install) does not work on Podman. Use rclone serve docker via systemd instead:
./scripts/install-rclone-plugin-podman.sh
podman compose -f compose.rclone-plugin.yml up -dCaddy is isolated in compose.caddy.yml (or inline in the all-in-one files). To use Traefik, nginx, or another proxy:
Start a core file without Caddy:
docker compose -f compose.core.yml up -d
# or Storage Box:
docker compose -f compose.core.yml -f compose.storagebox.yml up -dPoint your proxy at http://audiobookshelf:80 on the audiobookshelf_web network.
server {
listen 443 ssl;
server_name books.example.com;
location / {
proxy_pass http://audiobookshelf:80;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}Add to audiobookshelf in a custom override:
labels:
- traefik.enable=true
- traefik.http.routers.abs.rule=Host(`books.example.com`)
- traefik.http.services.abs.loadbalancer.server.port=80| Variable | Description |
|---|---|
| STORAGE_BACKEND | objectstorage (default compose) or storagebox (use with compose.storagebox.yml) |
| S3_ACCESS_KEY | Object Storage access key (sidecar) |
| S3_SECRET_KEY | Object Storage secret key (sidecar) |
| S3_REGION | Region: fsn1, nbg1, or hel1 |
| S3_ENDPOINT | e.g. fsn1.your-objectstorage.com |
| S3_BUCKET | Bucket name |
| STORAGEBOX_HOST | e.g. uXXXXX.your-storagebox.de |
| STORAGEBOX_USER | Storage Box username (or sub-account) |
| STORAGEBOX_PASS | rclone-obscured password (./scripts/obscure-password.sh) |
| STORAGEBOX_PORT | SSH/SFTP port (default 23) |
| STORAGEBOX_PATH | Prefix on the box with trailing slash (Coolify default media/) |
| STORAGEBOX_AUDIOBOOKS_DIR | Remote folder name for books (default audiobooks) |
| STORAGEBOX_PODCASTS_DIR | Remote folder name for podcasts (Coolify default podcast) |
| STORAGEBOX_EBOOKS_DIR | Remote folder name for ebooks (default ebooks) |
| RCLONE_REMOTE | Plugin volume remote (hetzner:bucket or storagebox:) |
| VFS_CACHE_MODE | rclone VFS mode (default full — best for ABS seeking) |
| VFS_CACHE_MAX_SIZE | Max local cache per mount (default 2G) — keep this small on tiny VPS disks |
| VFS_CACHE_MAX_AGE | Evict unused cache entries after this age (default 72h) |
| VFS_DIR_CACHE_TIME | How long directory listings are cached (default 72h) |
| DOMAIN | Caddy site address (books.example.com or :80 for local HTTP) |
| ACME_EMAIL | Email for Let's Encrypt (production HTTPS) |
| ABS_HOST_PORT | Host port when running without Caddy (default 13378) |
| Remote path | Container path | How to enable (sidecar) |
|---|---|---|
| …/audiobooks/ | /audiobooks | Always |
| …/podcasts/ | /podcasts | --profile podcasts |
| …/ebooks/ | /ebooks | --profile ebooks |
Object Storage examples use s3://<bucket>/audiobooks/. Storage Box examples use audiobooks/ at the account root (or under STORAGEBOX_PATH).
See rclone/rclone.conf.example. Copy to /var/lib/docker-plugins/rclone/config/rclone.conf on the host. Uncomment and fill the [storagebox] section when using a Storage Box, then set RCLONE_REMOTE=storagebox: in .env.
| Sidecar | Volume plugin | |
|---|---|---|
| Host setup | None | Plugin install + rclone.conf |
| Docker | Yes | Yes |
| Podman | Yes (recommended) | Advanced (systemd) |
| FUSE in container | Yes | No |
| Object Storage | Default compose | [hetzner] + RCLONE_REMOTE=hetzner:bucket |
| Storage Box | compose.storagebox.yml | [storagebox] + RCLONE_REMOTE=storagebox: |
| Back | FazBrowse Home | New Git URL |