Migrating from Watchtower
Move from Watchtower to Outpost by translating your settings and labels, and know up front which Watchtower options don't carry over.
Why Migrate?
- Gets automatic rollback so an update that breaks a container no longer leaves it down.
- Keeps anonymous volume data and the new image's defaults through every recreation.
- Runs the updater as a non-root user that only joins the Docker socket's group.
- Moves to a project that is actively maintained.
Migration Steps
- Stop and remove the Watchtower container so the two never update the same container at once.
- Translate its environment variables into Outpost settings and your container labels with the tables below.
- If Watchtower pulled private images, add a sign-in for each registry under Private registries on Outpost's Settings page, as shown in Private Registries.
- Turn on Monitor only on Outpost's Settings page and check the first report.
- If scripts or Prometheus called Watchtower's API, create an access token for each one on the dashboard's Access tokens page.
- If Watchtower sent notifications, add a destination for each service on the dashboard's Notifications page, and select Send test.
- Turn off Monitor only once the results look right.
Environment Variables and Settings
| Watchtower | Outpost | Notes |
|---|---|---|
WATCHTOWER_SCHEDULE | Schedule on the Settings page | Six-field cron with seconds carries over, but replace ? with *, since Outpost reads ? as the time it started. @every intervals need rewriting as cron. |
WATCHTOWER_POLL_INTERVAL | Schedule on the Settings page | No interval setting. Express it as cron, such as 0 0 */6 * * *. |
WATCHTOWER_RUN_ONCE | Check when Outpost starts | Outpost runs at start, but keeps running afterwards. |
WATCHTOWER_LABEL_ENABLE | Container selection set to Opt-in | |
WATCHTOWER_MONITOR_ONLY | Monitor only | |
WATCHTOWER_CLEANUP | Clean up old images | Outpost cleans up by default. Turn it off to keep old images. |
WATCHTOWER_TIMEOUT | Stop timeout | Whole seconds, such as 30, not a duration like 30s. |
WATCHTOWER_HTTP_API_TOKEN | An access token | Create one for each client on the Access tokens page. Outpost makes the token's value, so each client needs the new one. |
WATCHTOWER_HTTP_API_UPDATE | The updates:run scope | POST /v1/update is always on, and only tokens with updates:run can call it. |
WATCHTOWER_HTTP_API_METRICS | The metrics:read scope | /metrics is always on, and only tokens with metrics:read can read it. Metric names differ. |
WATCHTOWER_HTTP_API_PERIODIC_POLLS | None | Not needed. The schedule always runs alongside the API. |
WATCHTOWER_ROLLING_RESTART | None | Not needed. Outpost always updates one container at a time. |
WATCHTOWER_NOTIFICATION_URL | Destinations on the Notifications page | Outpost doesn't read Shoutrrr URLs, so add one destination per URL and fill in its fields. ntfy, Telegram, Discord, Slack, Gotify, Pushover, Matrix, and email have their own service, and Apprise reaches most others. |
WATCHTOWER_NOTIFICATIONS | Destinations on the Notifications page | Email, Slack, and Gotify have their own service, and Microsoft Teams works through Apprise. |
WATCHTOWER_NOTIFICATIONS_LEVEL | The events each destination chooses | Pick events, such as Update failed, instead of a log level. |
WATCHTOWER_NOTIFICATION_REPORT | None | Each alert covers one event and lists its containers. |
WATCHTOWER_NOTIFICATION_TEMPLATE | None | The wording of each alert is fixed. |
WATCHTOWER_INCLUDE_STOPPED | None | Outpost checks running containers only. |
WATCHTOWER_REVIVE_STOPPED | None | |
WATCHTOWER_INCLUDE_RESTARTING | None | |
WATCHTOWER_NO_PULL | None | |
WATCHTOWER_NO_RESTART | None | |
WATCHTOWER_SCOPE | None | Run one Outpost per host and use labels instead. |
WATCHTOWER_DISABLE_CONTAINERS | None | Label those containers io.cbnventures.outpost.enable=false. |
WATCHTOWER_LIFECYCLE_HOOKS | None | Pre-update and post-update commands are not supported. |
WATCHTOWER_DEBUG, WATCHTOWER_TRACE | None | Outpost logs one line per container per cycle. |
REPO_USER, REPO_PASS | Private registries on the Settings page | Add a sign-in for each registry host, with its username and a password or registry access token. |
DOCKER_HOST | DOCKER_HOST | Unix sockets and plain tcp:// only. |
DOCKER_TLS_VERIFY | None | TLS connections to the Docker daemon are not supported. |
DOCKER_CONFIG | None | Outpost doesn't read config.json. Add each login under Private registries on the Settings page instead. |
Container names passed as arguments, such as watchtower nginx redis, have no equivalent. It is recommended to use opt-in mode with labels instead.
Labels
| Watchtower | Outpost | Notes |
|---|---|---|
com.centurylinklabs.watchtower.enable | io.cbnventures.outpost.enable | Outpost accepts only lowercase true or false. |
com.centurylinklabs.watchtower.monitor-only | io.cbnventures.outpost.monitor-only | true makes the container monitor-only. |
com.centurylinklabs.watchtower.depends-on | None | Compose depends_on is read automatically. |
com.centurylinklabs.watchtower.scope | None | |
com.centurylinklabs.watchtower.no-pull | None | |
com.centurylinklabs.watchtower.stop-signal | None | Docker uses the container's own stop signal. |
com.centurylinklabs.watchtower.lifecycle.* | None | Lifecycle hooks are not supported. |
Outpost ignores Watchtower labels entirely. You can keep them while you migrate, but they have no effect.
API and Metrics
- Port — The API listens on port
22601rather than Watchtower's8080, so update port mappings, scripts, and scrape targets. - Tokens — Watchtower's one shared token becomes an access token for each client, with only the scopes it needs. Clients still send it as
Authorization: Bearer, so only the token's value changes. - Update — Watchtower's
/v1/updatebecomesPOST /v1/update, which returns202or409instead of waiting for the run to finish. AGET, which is what plaincurlsends, gets404with the codenot_found. - Single images —
POST /v1/updateignores query parameters, so Watchtower's?image=has no equivalent there. To check one container, send its ID toPOST /api/v1/checks, as shown in HTTP API and Metrics. - Status —
GET /v1/statusis new and returns the latest report as JSON. - Metrics —
/metricsusesoutpost_*names, so dashboards and alerts built onwatchtower_*metrics need updating. See HTTP API and Metrics for the list.
Behavior Differences
- Rollback — A new container that stops or turns unhealthy is replaced by the previous one.
- Self-updates — Like Watchtower, Outpost updates its own container by default, but last in each check and through a helper container that puts the old one back if the new one fails. To keep it on its current image, label it
io.cbnventures.outpost.enable=false, and in opt-in mode, label itio.cbnventures.outpost.enable=trueto let it update itself. - Cleanup default — Old images are removed after an update unless you turn off Clean up old images in Settings.
- Shared network namespaces — Containers with
network_mode: container:...orservice:...are skipped and need updating by hand. - Registry logins — Outpost doesn't read Docker's
config.jsonor run credential helpers such ascredsStore. Add each login on the Settings page instead; see Private Registries.