Activating the controlled update channel (owner ceremony)
The controlled update channel is live as of the ceremony date. The owner ceremony is complete: the vendor serves a signed channel at the singular update.downpipes.io, and the engine’s pinned release-signer public key verifies it. On the shipped base and demo config the signer is pinned and the channel URL is set. The live confirmation is GET /admin/updates reporting verified: true: it has somewhere to look and the host serves a channel that verifies under the pinned key. The ceremony that activated it is a one-time piece of owner and infrastructure work that lives outside the product: you stand up the host, generate and pin a release-signer key (or confirm the pinned one), point the engine at the signed document, and redeploy. This page is for the owner who ran that ceremony, and for re-keying or rotating it later. It is the prerequisite for applying updates, which is where the day-to-day flow lives. None of this gates a backup or a recovery: an update is never required for either.
Activation only switches on the verify-and-review side. The first time you actually apply a live update on your deployment, and the first time you run a rollback drill, are supervised first-live gates: they need real Cloudflare credentials, and the deploy drivers are validated against a stubbed Cloudflare by design. The engine driver has run against a real account exactly once (2026-07-03, on the vendor’s own demo deployment: one promote and one automatic rollback, both of which executed correctly); the console component’s driver has not run live at all.
What you are turning on
The engine updates itself by pulling a vendor-signed channel document from inside your own account and verifying it against a release-signer public key you have pinned. Since channel schema v2 a release can also carry the console as a component, applied by the same engine under the same one signature. The vendor never pushes code, and never holds a token that can rewrite your Workers. This is the deliberate alternative to a vendor-held deploy credential, which would be a worse custody risk than the data itself.
The verify side is what already ships in the engine. It is presence-gated on two settings and is otherwise a pure pull-and-verify, so activation is a handful of operator actions plus one offline vendor action.
The activation steps
Sign the channel offline (vendor action)
The vendor signs the channel document with the release-signer private key, offline, on a machine with no network. That signing tool lives outside the engine and console packages. It emits the channel JSON, its detached signature, and the public key for you to pin. The signature covers exactly the emitted bytes (the engine verifies over the bytes it fetches and then parses those same bytes, with no canonicalisation), so the document must be published verbatim. Re-serialising or reformatting it after signing breaks the signature. The release-signer private key never leaves that offline step. The vendor process is documented on publishing a signed release.
Stand up the channel host on a custom domain
Publish two objects at a stable HTTPS URL: the channel body, and the same URL with a
.sigsuffix holding the base64url signature on a single line. Because the engine trusts the pinned signature and not the host, this is static signed content with no server logic, so it is served as two static files from an R2 public bucket attached to a custom domain. The host is the singularupdate.downpipes.io, servinghttps://update.downpipes.io/stable.jsonandhttps://update.downpipes.io/stable.json.sig. The host also carries the artefact bytes each release points at: the engine bundle and, for a release that carries a console component, the self-describing console artefact (console-<version>.json), both hash-pinned by the one signed document. Until the bucket is created, public access enabled and the custom domain attached, the host is not reachable and serves nothing; the vendor has completed those steps, so the host is live and serving the signed channel.Pin the signer and point the engine at the channel
Set two values in the account, either in Secrets Store or as a wrangler secret or var (the engine reads either transparently).
UPDATE_SIGNER_PUBLICis the printed release-signer public key (an Ed25519 32-byte half concatenated with the ML-DSA-87 public 2592-byte half, 2624 bytes, base64url). This pin is the whole security model.UPDATE_CHANNEL_URLis the channel body URL from the previous step.A third setting exists for component-aware releases and is optional:
CONSOLE_WORKER_NAMEnames the console script a release’s console component may deploy to, and it defaults todownpipe-console, so set it only if your console Worker uses a different script name. The name alone is never trusted: before the engine touches that script it requires the script’s live bindings to include theENGINEservice binding pointing back at this engine, so a wrong name can never redeploy an unrelated Worker.Redeploy the engine
Redeploy so the engine picks up the two settings. Presence of both makes the status report
configured: true, but the channel does not verify, and nothing applies, until the host is stood up and serving the signed channel.Confirm configured and verified
Read the engine’s update status. The status flag reports the channel as configured (presence only). The dedicated updates route does the real work: it fetches the signed document and its signature, verifies them under your pinned key, and returns whether the channel verified. Confirm that it reports verified true, and that the recommended version it returns is the one you signed.
Configured is not verified
The distinction is deliberate and it is the thing operators most often conflate. They are two different checks, answered by two different routes.
| Reading | Where it comes from | What it actually means |
|---|---|---|
configured |
The status report flag updateChannelConfigured |
Presence only: both UPDATE_CHANNEL_URL and UPDATE_SIGNER_PUBLIC are set. It says nothing about validity |
verified |
The updates route, which fetches and checks the signature | The real result: the channel was fetched over HTTPS and its detached signature verified under the pinned signer |
The status flag is a pure truthiness check on purpose: it cannot leak a parse-derived detail of a secret, and it is cheap enough for the console to poll during onboarding. So a malformed pinned key still reads as configured at the status level. The honest answer always comes from the updates route, which never throws and never falls back to an unverified document. A wrong signer, a tampered body or an unfetchable URL all surface there as not verified, with a reason. If both settings are absent, the channel simply reports not configured, which is not an error.
The console reflects these states directly. The update tile reads “Channel not set” when the channel is unconfigured, and the signing tile reads “Configured, not verified” when the settings are present but the signature has not verified. Only when the channel is both configured and verified does the signing tile read “Signer verified”.
The trust property
The engine pulls and verifies; it never accepts a push, and nothing inbound is ever accepted. The document is fetched outbound over TLS with redirects disabled, so a redirected signed fetch cannot be steered to another host. The signature is the hybrid scheme used everywhere else in the product, an Ed25519 signature alongside an ML-DSA-87 signature, both halves required, so the channel is post-quantum hybrid signed. The engine verifies against the key you pinned, never a key the channel asserts about itself.
The custody story is the point of the whole design. The vendor never holds a credential that can rewrite your Workers, and the release-signer private key lives offline and is never deployed. A compromised channel host therefore cannot substitute an unsigned or wrong-signer document, because the engine checks the pinned signature rather than trusting the host. For the deploy step of an actual apply, the only credential involved is a one-shot token scoped to the “Edit Cloudflare Workers” template (Workers Scripts: Edit), collected in the console at apply time and used once; it is distinct from your full account deploy credential and is never stored.
A release-signer fingerprint is pinned via the UPDATE_SIGNER_PUBLIC setting and that pin alone. There is no compile-time bake of the fingerprint into the engine binary, so do not rely on the engine printing a baked-in fingerprint or on a recovery sheet carrying one; the pin is the environment value you set in step three.
The generated deploy config cannot drift the channel settings
The base config and the demo config both point at the singular update.downpipes.io host and pin the key. A bare wrangler deploy is destructive to bindings: it replaces the worker’s whole binding set with exactly what wrangler.toml lists, so it would drop any source attached from the console. Deploys instead run through scripts/sync-bindings.mjs, which reads the live worker’s current bindings and writes wrangler.deploy.toml: a generated, gitignored file that is the committed wrangler.toml plus those live source-binding stanzas appended. Deploying that generated file (npm run deploy, or wrangler deploy -c wrangler.deploy.toml) carries the console-attached sources forward instead of dropping them. Nothing in that generation step touches the update settings, so wrangler.deploy.toml always carries the same UPDATE_CHANNEL_URL and UPDATE_SIGNER_PUBLIC as wrangler.toml. There is no separate deploy-only copy of these settings to reconcile; editing wrangler.toml is enough.
The supervised first-live gates
Activation makes the channel verifiable and reviewable. It does not make a live apply battle-tested. Two things stay owner-pending until you do them under supervision with real credentials.
The first live apply exercises the real Cloudflare deploy drivers for the first time on your account. The drivers are correct by the documented API shapes and refuse rather than risk a brick. The engine driver has now run against a real Cloudflare account exactly once, on the vendor’s demo deployment on 2026-07-03, where a promote and an automatic rollback both executed correctly; once is once, and your account is not that account, so watch the first one. The console component’s static-assets driver has not run live anywhere yet, so a release that carries the console keeps the full supervised-first caveat. The first rollback drill proves the revert direction end to end on your deployment. Plan both deliberately rather than discovering them during an incident; the mechanics are on applying updates and the recovery controls on update trust and rollback.
Where this fits
Once the channel reports verified, move to applying updates for the review, preview and one-click apply flow. For the brick-safety and trust model in depth, including the standalone rollback and the opt-in gradual ramp, read update trust and rollback. For the vendor side of signing and publishing a channel, see publishing a signed release. For the scopes a deploy token needs, see Cloudflare token scopes.
Last updated .