Read this before upgrading. Only releases that need you to do something are
listed here. If a version is not mentioned, docker compose pull && docker compose up -d
is all it needs.
CHANGELOG.md carries the detailed notes recorded so far — it is not a complete release history, so do not treat it as the authoritative list of what an upgrade requires. This file is: what breaks, who it affects, and what to type.
Always upgrade the UI and every worker to the same version. The compose files pin both images to the same tag for exactly this reason.
Back up /data first. cashpilot.db holds your earnings history and
.fernet_key decrypts every stored credential — without that key they cannot be
recovered. See Backing up node identities for the rest.
Affects you if a worker appears in your fleet but has never confirmed its own key. On the Workers page these now show an "enrollment incomplete" badge. If every worker shows a normal Last seen time and no badge, no action is required.
In practice this means: a worker running a pre-1.0.0 image, or one whose /data
is read-only or is not a persistent volume, so it cannot keep the key it was
issued. It also affects the Android app before v0.2.0, which did not persist
its per-worker key.
What changed. CASHPILOT_API_KEY is the shared enrollment key. Once a
worker has been issued its own key, the shared one is meant to stop working for
it — that is the entire point of per-worker keys. Until now, a worker that never
confirmed kept the shared key valid for its identity forever, and the UI
re-sent that key to whoever held it every 60 seconds. The window is now bounded
at 24 hours from the moment the key was issued.
What breaks if you do nothing. Such a worker starts receiving 401 on its
heartbeat and disappears from the dashboard. Containers it manages keep running
and keep earning — you simply stop seeing and controlling them.
What to do. Give the worker somewhere to keep its key, then let it enrol again:
-
Upgrade that worker to
1.0.0or newer. -
Make sure
/datais a writable, persistent volume, not a tmpfs and not read-only. -
Keep
/data/.worker_id. It is the worker's identity, read once at startup. If it is missing, the worker registers under a brand-new id and you get a duplicate row in the fleet rather than the same machine re-enrolling. Before recreating the container, make sure the file exists and is owned by the container user:ls -l /path/to/worker/data/.worker_id chown 1000:1000 /path/to/worker/data/.worker_id
-
Remove the worker on the fleet page, then restart the container — the identity is read at startup, so
docker compose up -don an already-running container does not re-read it:docker compose restart cashpilot-worker docker logs cashpilot-worker | grep -i enrolIt writes
/data/.worker_keyonce enrolled. Confirm that file exists. -
For the Android app, update it to v0.2.0 or newer — earlier builds cannot persist the key at all.
Existing, already-enrolled workers are untouched: they authenticate with their own key, which does not expire.
Affects you if you copied docker-compose.yml from the repo and are relying
on it tracking the newest build. Your existing deployment is unaffected until
you edit your compose file — nothing changes underneath you.
What changed. The examples pin 1.11 instead of latest, so following the
quickstart gives you a known version rather than whatever was pushed most
recently.
What to do. Nothing. If you want a different version, pin an explicit one —
drumsergio/cashpilot:1.12.0 — rather than a floating tag. :latest is not
supported: it makes the version you are running unknowable, which is what
produced a months-old bug report against a bug that had already been fixed.
Affects you if your /data is not writable. No action is required if it
is a normal bind mount or volume.
What changed. Credentials are encrypted with a key at /data/.fernet_key. If
that could not be written, CashPilot used to carry on with a key that died with
the process — so everything encrypted during that run became unreadable on the
next restart. It now refuses to start instead.
What breaks if you do nothing. The container exits at startup with an error naming the path.
What to do. Fix the mount so /data is writable. If a throwaway instance is
genuinely what you want, set CASHPILOT_ALLOW_EPHEMERAL_KEY=true and accept that
stored credentials will not survive a restart.
Back up /data/.fernet_key. Without it, stored credentials cannot be
decrypted — not by you, and not by us.
Affects you if you reach the dashboard from another machine on your LAN and you use the shipped compose file. No action is required if you browse from the host itself, or if you front it with a reverse proxy on the same machine.
What changed. The compose files bind the dashboard — and, in the fleet
compose, the Docker-socket worker — to 127.0.0.1 instead of 0.0.0.0. The
worker has the Docker socket, which is root-equivalent on the host, so publishing
it to the whole network by default was the wrong default.
What breaks if you do nothing. The dashboard stops answering on the LAN address you were using.
What to do. Set CASHPILOT_BIND_ADDR to 0.0.0.0, or better, to the one
interface you actually want it on:
CASHPILOT_BIND_ADDR=192.168.1.10 docker compose up -dOn a single-host install, leave the worker on loopback. Only the UI needs to reach it, and it does so over the Docker network.
On a fleet, a remote worker must be reachable by the UI, and it uses a
different variable — CASHPILOT_WORKER_BIND_ADDR in docker-compose.fleet.yml.
Left on loopback, a remote worker is unreachable and its containers become
unmanageable. Bind it to the interface the UI reaches it on — a tailnet address
rather than 0.0.0.0, since that port carries the Docker socket API:
CASHPILOT_WORKER_BIND_ADDR=100.x.y.z docker compose up -dA full cutover with its own page: Upgrade to v1.0.0.
In short: every worker is issued its own key on first heartbeat and uses it
thereafter; CASHPILOT_API_KEY becomes an enrollment credential only. Keep it
set — enrollment still needs it. Upgrade the UI first, then every worker.
No action required. Pull and recreate:
docker compose pull && docker compose up -dOn a fleet, run that on every host. It only updates the Compose project it runs in, so remote workers stay on their old version until you upgrade them too — and the UI and workers are meant to be on the same release.