Image updates — pinning & update notifications¶
How container images are versioned in this repo and how we get told when updates ship.
Convention: pin explicitly, watch the repo¶
Every service in stacks/*/ is pinned to an explicit version tag — no latest, stable,
production, or bare-variant tags (rocm) on running services. Each watchable service also carries
Diun watch_repo labels so Diun alerts on new version releases (not just a digest change on the
tag you're already running):
labels:
diun.watch_repo: "true"
diun.include_tags: '<regex for this image's tag scheme>'
diun.sort_tags: "semver"
diun.max_tags: "3"
include_tags regex per scheme (Go RE2, single-quoted in YAML so backslashes survive):
| Scheme | Example image | include_tags |
|---|---|---|
vX.Y.Z |
adguard, traefik, homarr, postmoogle | ^v\d+\.\d+\.\d+$ |
X.Y.Z |
zigbee2mqtt, uptime-kuma, forgejo, frigate | ^\d+\.\d+\.\d+$ |
CalVer YYYY.M.P |
home-assistant, esphome | ^\d{4}\.\d+\.\d+$ |
X.Y.Z-<variant> |
mosquitto (-alpine), peertube (-trixie), ollama (-rocm) |
^\d+\.\d+\.\d+-alpine$ etc. |
| Base OS major | postgres/redis (-alpine) |
^\d+-alpine$ |
| Base OS minor | alpine | ^\d+\.\d+$ |
Left unwatched on purpose: digest-pinned images (@sha256:… — otbr, matter-server, immich pg/redis)
have no tag to walk; the locally-built beszel-hub-patched isn't in a registry (rebuild on bumps —
see its compose comment); Immich is a coupled stack on a version-locked pgvecto.rs DB image and is
bumped as a set per upstream release notes, not piecemeal.
Registry sources: keeping off Docker Hub¶
watch_repo makes Diun list a repository's full tag set each scan to find the newest, then
digest-check the top max_tags (3). Docker Hub's anonymous pull limit (100/6h) is easily
exhausted by the tag-heavy Official Images (postgres, python have thousands of tags to page),
which then return HTTP 429.
Rather than authenticate to Docker Hub (which needs an account + brings the tracking that comes with one), images are sourced from mirrors that need no account and have no restrictive anonymous cap:
- Docker Official Images →
public.ecr.aws/docker/library/*(AWS ECR Public mirror): postgres, redis, python, alpine, traefik, eclipse-mosquitto. - Third-party images that also publish to ghcr →
ghcr.io/*:crazy-max/diun,louislam/uptime-kuma,tecnativa/docker-socket-proxy. - Still on Docker Hub (no public ghcr mirror; 403): adguard/adguardhome, henrygd/beszel-agent, livekit/livekit-server, rhasspy/wyoming-{piper,whisper}, mrcreativ3001/moonlight-web-stream, ollama/ollama — few tags each, so they stay under the anon limit.
After repointing, a full Diun scan reports 0 × 429. Trade-offs: a mirror can lag Docker Hub by
hours–days on a brand-new release (a "new version" alert may arrive slightly later), and you must
verify the exact pinned tag resolves on the mirror before repointing (they occasionally lag). The
include_tags regexes are unchanged — mirrors carry the same tag names.
diun.max_tags: 3does cap the digest checks to the newest 3/repo (a full scan is ~115 checks, not hundreds —diun image inspectprints the full tag listing, not the watched set). What tripped the limit was the tag listing itself, whichmax_tagscan't shrink — hence mirrors, not auth.
Renovate (not deployed)¶
stacks/renovate/ exists but has never run — pinned-version bumps are handled by the Diun
watch_repo alerts above instead. To revive Renovate it needs: a stacks/renovate/.env with a Forgejo
token, this repo actually pushed to Forgejo (currently no git remote; Forgejo has 0 repos), and either
re-enabling Forgejo issues (disabled per ADR-0003) or the PR-only config already set in renovate.json
(dependencyDashboard: false).
Postgres major upgrades (16 → 18)¶
postgres:18+ crash-loops if the volume is mounted at /var/lib/postgresql/data directly — it now
requires a subdirectory. Set PGDATA=/var/lib/postgresql/data/pgdata (matches ha-postgres). A major
bump is not a tag change; migrate via dump/restore:
docker exec <pg-old> pg_dumpall -U <superuser> > backup.sql # 1. dump (while old is running)
# 2. edit compose: image -> :18-alpine, add PGDATA subdir, point volume at a NEW name (keep old for rollback)
docker compose -f <stack> up -d --wait postgres # 3. fresh 18 initialises
docker exec -i <pg-new> psql -U <superuser> < backup.sql # 4. restore
Done 2026-07-19 for byos_postgres and peertube_postgres; PeerTube app also went 7.3.0 → 8.2.2
(bookworm → trixie). Dumps + row-count baselines kept in /home/skill-lava/pg-backups/.
Gotchas¶
- Registry tag lookups lie. Paginated registry tag lists can miss the newest line (frigate's
stable= 0.17.2 while a naive scan returned 0.16.1; same for mosquitto, open-webui). Always check the running version before pinning; pin to current when unsure. - Frigate config schema changes between minors. 0.16 dropped the old
record: continuous/motion: {days}retention format and changedclassification: custom. Pinned at 0.17.2 (current). Moving the config forward is a manual migration — a downgrade to 0.16 crash-loops on the 0.17 config.