homelab/src/watchstate/ansible/unraid/docker-compose.yml
Russell Seymour 3cd33d350e
Some checks failed
deploy / deploy (push) Has been cancelled
Added Jellyfin deployment to the repo
2026-08-31 20:14:43 +01:00

100 lines
5 KiB
YAML

services:
watchstate:
image: ghcr.io/arabcoders/watchstate:${WATCHSTATE_VERSION}
container_name: watchstate
restart: unless-stopped
# The image runs rootless and drops privileges to this uid:gid — it is a
# `user:` directive, not PUID/PGID env vars like the LinuxServer images
# (arr, jellyfin). It must match the owner of the appdata bind below or
# the container exits on start, unable to write /config. On Unraid that is
# 99:100 (nobody:users) — upstream's own Unraid note says the same.
#
# WatchState won't chown /config itself the way the LinuxServer images do,
# so the `appdata:` block on this stack's host_vars entry pre-creates the
# bind directory owned by 99:100 before `docker compose up` — otherwise
# Docker makes it root:root on first start and the container exits.
user: "${PUID}:${PGID}"
# Unraid's Docker page normally reads icon, WebUI link and console shell
# from the dockerMan template that created the container. A Compose stack
# has no template, so 6.10+ falls back to these labels; without them the
# container renders as a question mark with no WebUI or Console entry.
# See README.md → "Icons on the Unraid Docker page".
#
# `sh`, not `bash`: the image is Alpine-based (frankenphp on Alpine).
labels:
net.unraid.docker.icon: ${STACK_ICON}
net.unraid.docker.webui: "http://[IP]:${WATCHSTATE_HTTP_PORT}/"
net.unraid.docker.shell: sh
# Joins Caddy's network by the fixed `proxy` alias, same shape as arr and
# jellyfin; the real network it maps to is a per-host decision in vars.yml
# (WATCHSTATE_NETWORK → caddy-net). Caddy then proxies to
# `watchstate:8080` — the container name on caddy-net — rather than nas1's
# LAN IP and the published port.
#
# This also puts Jellyfin one hop away: WatchState reaches it as
# `http://jellyfin:8096` when adding it as a backend. Plex and anything
# else off caddy-net is addressed by nas1's LAN IP and its published port
# (e.g. http://192.168.50.1:32400) — a runtime concern configured in the
# WebUI, not here.
networks:
- proxy
environment:
# Image default is UTC; TZ comes from vars.yml. Both are named here
# because Compose reads .env only to interpolate `${...}` in this file —
# a var that nothing references never reaches the container.
WS_TZ: ${TZ}
TZ: ${TZ}
# The task scheduler (import every hour, export every 90 min) and the
# built-in cache server are both on by default. Uncomment to turn either
# off — e.g. DISABLE_CRON while doing the initial one-off backend sync by
# hand, before enabling the tasks on the Tasks page.
# DISABLE_CRON: "1"
# DISABLE_CACHE: "1"
# --- Reverse-proxy auth (optional) --------------------------------------
# WatchState has its own internal auth (the first-run system user). If it
# is ever fronted by Caddy + Authentik forward-auth instead, set these so
# it trusts the proxy rather than double-prompting. Setting BOTH disables
# all internal auth — only do that once the external layer is definitely
# in front of it.
# WS_TRUST_PROXY: "true"
# WS_TRUST_LOCAL: "true"
volumes:
# SQLite database (db/watchstate_v01.db), backend configs, guid.yaml and
# logs — this directory *is* the application state, same standing as
# arr's SHELFARR_DATA_PATH. Back it up accordingly.
- ${WATCHSTATE_CONFIG_PATH}:/config
ports:
- "${WATCHSTATE_HTTP_PORT}:8080"
# Restated from the image's own HEALTHCHECK. The port here is the fixed
# internal 8080, never WATCHSTATE_HTTP_PORT.
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/v1/api/system/healthcheck"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
networks:
# `external: true` means "attach to a network that already exists; don't
# create it, don't delete it on `down`". Without it Compose would create a
# *new* network named `watchstate_<key>` — the deploy would still succeed and
# Caddy would silently fail to resolve `watchstate`. `name:` is what stops
# the project-name prefix being applied.
#
# The local alias is a fixed `proxy` so the compose file stays static; which
# real network it maps to is a per-host decision in vars.yml
# (WATCHSTATE_NETWORK). Same shape as arr's `proxy` → `caddy-net` and
# jellyfin's.
#
# caddy-net is defined in Unraid's Docker settings on nas1 rather than by a
# stack in this repo, so nothing here has to deploy before WatchState does.
# It must exist on the target host — an absent external network fails the
# deploy outright.
proxy:
name: ${WATCHSTATE_NETWORK}
external: true
# Reaching WatchState through Caddy means proxying to `watchstate:8080` — the
# container name on caddy-net — rather than nas1's LAN IP and the published
# port. The `ports:` mapping above is kept for direct access that bypasses the
# proxy; drop it if you don't want WATCHSTATE_HTTP_PORT reachable on the LAN.