Skip to content

A Watchtower alternative with automatic rollback

Watchtower is the tool most people reach for to auto-update Docker containers: it watches your running containers, pulls newer images, and restarts them. It is battle-tested and simple — but it updates and walks away. If the new image is broken, your service stays down until you notice and intervene.

Hoister is a self-hosted Watchtower alternative built around that exact gap. It does the same automatic image updates, but treats every update as a deployment: it runs the new container, watches its health check, and rolls back to the previous image — restoring named volumes — if the update fails. An optional dashboard then aggregates what happened across all your hosts.

  • No rollback. Watchtower has no notion of a failed update. A bad image, a missing migration, or a crash-looping container just becomes downtime.
  • No data safety. If an update corrupts a volume, there is nothing to restore from.
  • One host at a time. Watchtower runs per host and reports to logs and notifications only — there is no shared view of what updated where.
  • Slowing development. Watchtower’s release cadence and issue triage have become infrequent, which pushes teams to look for an actively maintained option.

If none of those bother you, Watchtower is a perfectly good choice. If they do, read on.

CapabilityHoisterWatchtower
Automatic image updatesYesYes
Scheduled checks (cron or interval)YesYes
Opt in/out via container labelsYesYes
Private registries (GHCR, ECR, ACR, GCR)YesYes
NotificationsA dozen-plus channelsYes (via shoutrrr)
Removes the old image after updatingYes (automatic)Optional (--cleanup)
Automatic rollback on failed health checkYesNo
Volume backup & restore on rollbackYesNo
Approve-before-apply (detection-only) modeYesMonitor-only (notify, no apply)
Web dashboardYes (optional controller)No
Multi-host aggregationYesNo (per host)
Deployment history & container metricsYesNo
Secret redaction before data leaves the hostYes
Runs standalone without a backendYesYes
Pre/post-update lifecycle hooksNoYes
ImplementationSingle Rust binarySingle Go binary

This is the headline. With hoister.enable=true on a container, Hoister pulls a new image, starts it, and watches its Docker health check. If the container becomes healthy, the update sticks and the old image is cleaned up. If it fails, Hoister puts the previous image back — automatically, within the same update cycle. Watchtower has no equivalent: once it restarts the container, you own whatever happens next.

Add hoister.backup-volumes=true and Hoister snapshots the container’s named volumes before the update. If the update is rolled back, the volumes are restored from that snapshot, so a botched migration doesn’t leave your data in a half-written state. Watchtower does not touch volumes at all.

Point the agent at the optional controller and every host reports deployments, rollbacks, pending updates, and CPU/memory metrics to one web dashboard. Watchtower is per-host and surfaces results only through logs and notifications.

Set auto_update = false and Hoister switches to detection-only mode: it finds new images on schedule but doesn’t apply them. They show up as Pending Updates in the dashboard, where you click to roll out. Watchtower’s monitor-only mode can notify you, but it can’t apply an update on demand from a UI. See Operating modes.

Hoister runs as a single service in your Compose stack, the same way Watchtower does. Drop the Watchtower service and add Hoister:

docker-compose.yml
services:
hoister:
image: hoister/hoister:latest
volumes:
- /var/run/docker.sock:/var/run/docker.sock
security_opt:
- no-new-privileges:true
app:
image: ghcr.io/acme/app:latest
labels:
- "hoister.enable=true" # was: com.centurylinklabs.watchtower.enable=true
- "hoister.backup-volumes=true" # no Watchtower equivalent

The concepts map across directly:

WatchtowerHoister
com.centurylinklabs.watchtower.enable=truehoister.enable=true label
WATCHTOWER_SCHEDULE / --interval[schedule] cron or interval in hoister.toml
WATCHTOWER_MONITOR_ONLY=trueauto_update = false (detection-only mode)
Shoutrrr notification URLs[dispatcher.*] tables (Notifications)
Registry auth via Docker configRegistry credentials (GHCR, ECR, ACR, GCR)

That’s the whole migration: swap the service, relabel your containers, and optionally turn on volume backups for the containers whose data you care about.