Add the Audiobookshelf playbook

This commit is contained in:
tanshu committed 2026-10-18 21:35:52 +05:30
1 parent 34cb4aa3dc
commit 5e0a27b32b
8 files changed
+826

No files matched your search

+79
View File
@@ -0,0 +1,79 @@
---
# ---------------------------------------------------------------------------
# Rootless Podman / Quadlet
# ---------------------------------------------------------------------------
# Duplicated on purpose from caddy/vars/default.yml: a play cannot include that
# file wholesale, because it also sets `host_directory` — to the Caddy data
# directory — and every playbook defines that for itself. Keep these three in
# sync with caddy/vars/default.yml. (Its fourth, podman_unprivileged_port_start,
# belongs to the podman tasks, which this play does not run: Audiobookshelf
# publishes nothing host-side.)
#
# podman_user is derived from the connection: this play carries no become, so
# the Quadlet units belong to whoever Ansible connects as. Requires gather_facts
# (set in playbook.yml).
podman_user: "{{ ansible_facts['user_id'] }}"
podman_data_dir: "{{ ansible_facts['user_dir'] }}/podman-data"
quadlet_dir: "{{ ansible_facts['user_dir'] }}/.config/containers/systemd"
# ---------------------------------------------------------------------------
# Audiobookshelf
# ---------------------------------------------------------------------------
host: audiobooks.tanshu.com
container_name: audiobookshelf
unit_name: "{{ container_name }}.service"
# Already fully qualified, so rootless Podman never resolves a short name
# against unqualified-search-registries — there is no TTY to answer a prompt
# when the systemd unit starts.
image: ghcr.io/advplyr/audiobookshelf:latest
# The Quadlet file is <network_name>.network. caddy/roles/register pins the
# Podman network name to <network_name>_net (so: audiobookshelf.network,
# audiobookshelf_net).
network_name: "{{ container_name }}"
host_directory: "{{ podman_data_dir }}/{{ container_name }}"
# The four mount targets, straight from the Docker-era `docker run`. Two are
# state, two are the library:
#
# config/ absdatabase.sqlite + migrations/ irreplaceable, 2.6 MB
# metadata/ backups/, cache/, logs/, streams/ irreplaceable, 19 MB
# audiobooks/ the book library 15 GB, re-downloadable media
# podcasts/ downloaded podcast episodes
#
# The image declares NO VOLUME (verified against the published image), so these
# are conventional bind-mount targets, not image volumes: without the Volume=
# lines in the unit Podman creates nothing, the data lands in the container's
# writable layer, and recreating the container destroys it.
config_dir: "{{ host_directory }}/config"
metadata_dir: "{{ host_directory }}/metadata"
audiobooks_dir: "{{ host_directory }}/audiobooks"
podcasts_dir: "{{ host_directory }}/podcasts"
# The port inside the container that Caddy proxies to. The image sets
# EXPOSE 80 and ENV PORT=80.
container_port: 80
# The one setting the Docker-era container passed. TZ is not a secret, so unlike
# bitwarden/ and tandoor/ this unit has no EnvironmentFile=: Audiobookshelf
# generates its own JWT signing key inside config/ and needs nothing from
# Ansible that has to be hidden.
timezone: Asia/Kolkata
# The image ships no HEALTHCHECK, so this play defines one on the unit.
# /healthcheck is the app's own unauthenticated endpoint and answers 200 OK.
# `wget` is what the runtime image has — `curl` exists only in its builder
# stage.
health_cmd: "wget -q -O /dev/null http://127.0.0.1:{{ container_port }}/healthcheck"
# The shared Caddy unit and its Caddyfile, both owned by caddy/playbook.yml.
caddy_name: caddy
caddyfile_path: "{{ podman_data_dir }}/{{ caddy_name }}/conf/Caddyfile"
snippet_block: |
{{ host }} {
reverse_proxy {{ container_name }}:{{ container_port }}
}