Updates¶
Three separate things get updated here, on different schedules and through different mechanisms. Conflating them is the easiest way to either miss a security fix or accidentally roll a service version you didn't mean to touch.
A fourth thing - moving the host to the next Debian major release - is not an update in the same sense and has its own section at the end.
Host security patches: automatic, no action needed¶
The common role's unattended-upgrades configuration installs security updates on
its own, daily, without a reboot (common_unattended_upgrades_automatic_reboot is
false by default - deliberately, an unannounced reboot on a host running an
integration engine is riskier than a kernel update waiting). See
common: unattended-upgrades for what's
actually covered and how to verify it's running.
Node Exporter, being a native Debian package rather than a container, is covered by this too - that's one of the reasons it isn't containerized (see Architecture).
Container image versions: a deliberate variable bump¶
Every container image in this kit is pinned to a specific tag - CONVENTIONS.md forbids
latest outright, so nothing updates a container image on its own. Bumping one is a
conscious action:
| Role | Variable | Current pin |
|---|---|---|
| caddy | caddy_image |
caddy:2.11.4-alpine |
| bridgelink | bridgelink_image |
innovarhealthcare/bridgelink:26.6.0-dhi-slim |
| bridgelink | bridgelink_postgres_image |
postgres:17.11-alpine |
| bridgelink | bridgelink_exporter_image |
python:3.13.15-alpine |
| monitoring | monitoring_prometheus_image |
prom/prometheus:v3.13.2 |
| monitoring | monitoring_grafana_image |
grafana/grafana:13.1.4 |
| monitoring | monitoring_loki_image |
grafana/loki:3.7.6 |
| monitoring | monitoring_alloy_image |
grafana/alloy:v1.18.1 |
| monitoring | monitoring_alertmanager_image |
prom/alertmanager:v0.33.1 |
| monitoring | monitoring_cadvisor_image |
ghcr.io/google/cadvisor:v0.60.5 |
| monitoring | monitoring_docker_socket_proxy_image |
tecnativa/docker-socket-proxy:0.3.0 |
The roles remain the source of truth, but this table is no longer allowed to drift away
from them: scripts/check-variable-docs.py compares every row against the roles' defaults
on every push, and fails on a wrong tag, a missing image or one that no role defines. It
said "it will drift" until 2026-08-21, and it had - two tags behind and three images
missing entirely (issue #81). That was defensible while the table was a convenience. It
stopped being defensible when ADR 0010
made this table the documentation that keeps those thirteen variable names inside the
v1.0 promise.
Note what is checked and what is not: that the table matches the roles, not that the pins
are current upstream. The latter needs a scanner and a network and is
scripts/scan-images.py's job, weekly in CI (issue #67).
To bump one: override the variable in your inventory, re-run site.yml. Ansible
recreates only the affected container. There's no version-check tooling in this repo
yet - checking for new upstream releases is manual, per image.
Before rolling monitoring image bumps into production, read
monitoring: Observability stack - several images in
that stack (Grafana, cAdvisor, docker-socket-proxy) have no command: override and
depend on being pre-pulled before the Compose apply computes their config hash, or a
version bump can trigger a spurious second recreate. That's already handled by the role
for a version you set once, but worth knowing if something looks like it "changed twice"
after a bump.
Ansible itself and its collections¶
ansible/requirements.yml pins the collections this repo needs (currently
community.docker, community.general). Update with:
ansible-galaxy collection install -r ansible/requirements.yml --force
--force matters - without it, ansible-galaxy silently keeps an already-installed
older version even if the requirements file asks for a range that includes something
newer.
After any update: verify, don't assume¶
The same rule applies here as after a first deployment - see Deployment: verifying a deployment actually worked. A version bump that applies cleanly isn't the same as a version bump that still works; run each role's verification commands afterward.
Moving to the next Debian major release¶
The supported path is a reinstall and a restore, not an in-place dist-upgrade.
This is a stated position rather than a tested procedure, and the distinction matters. The
kit targets Debian stable and only Debian stable (CONVENTIONS.md). Debian 13 has full
security support until 9 August 2028 and LTS until 30 June 2030; Debian 14 (Forky)
is in testing with no announced release date, and Debian's cadence has been roughly two
years. So this is a question with years of runway - but it needed an answer, because
without one an operator reaches Debian 13's end of life and discovers there is no guidance
at all.
Why reinstall rather than upgrade in place¶
Not dogma - it follows from what this kit actually does to a host:
- The roles configure through drop-ins, and a major upgrade rewrites the files they drop
into.
sshd_config.d/,apt.conf.d/,timesyncd.conf.d/,ssh.socket.d/all survive in principle, but adist-upgradeprompts about changed configuration files and the outcome depends on how those prompts are answered. That is not a path anyone should be taking on a clinic's integration host at 2am. - Docker comes from Docker's own repository, keyed on the Debian codename. The role
already anticipates the lag - it probes whether Docker publishes a suite for the running
codename and falls back to the previous one (
docker_apt_release_fallback, todaybookworm). So this does not block an upgrade, but it does mean a freshly upgraded host may run Docker packages built for the older Debian for a while, and that fallback codename will need revisiting rather than being left atbookwormforever. - Nothing here has been tested across a major upgrade, because there has not been one to test against.
A reinstall, by contrast, exercises paths that are tested on every change: the bootstrap
script, site.yml against a fresh host, and a restic restore. test/vm-test.sh proves the
first two on every relevant push, and the backup role's weekly restore test (#36) proves
the third on a real host.
The procedure, in outline¶
- Verify the backup restores - before touching anything.
restore_test_successshould be 1; see Backup & Restore. - Install Debian 14 fresh on the target.
- Run
scripts/bootstrap.sh, thensite.ymlwith the same inventory and vault. - Restore the data from restic.
- Verify as described under "After any update" above, plus the role-specific checks.
The inventory and vault are what carry a deployment's identity across the move. Keeping
bridgelink_server_id stable matters especially - BridgeLink treats a changed ID as a
different server.
When this gets revisited¶
When Debian 14 is released and there is something to test against. If an in-place upgrade turns out to work reliably, it becomes a documented option; until it has been exercised against a real host, presenting it as supported would be a guess dressed as guidance.