Skip to content

proxy ​

The Manager renders the edge proxy's configuration and pushes it to the proxy. pfy proxy lets you look at that loop and drive it by hand: status reports its state, diff compares what the Manager renders now with what the proxy applied, and sync pushes immediately. All three need a system-administrator token.

Synopsis ​

bash
pfy proxy status [--exit-code]
pfy proxy diff   [<app-slug> | --slug <slug> | --id <uuid>] [--project <slug>] [--show-rendered] [--exit-code]
pfy proxy sync   [--exit-code]

All three require a system-administrator token: they describe, and sync reshapes, the install's edge rather than the caller's own data. A non-admin token does not get an error; see Withheld looks like off.

The model ​

The Manager renders the edge proxy's whole configuration from its deployment data and pushes it to the proxy's admin API. It does this on its own after every config-changing mutation and on a periodic reconcile; these commands let you look at that loop and drive it by hand.

Two hashes carry the state:

  • the rendered hash: SHA-256 of the config the Manager renders right now
  • the applied hash: the config the proxy is running

Everything below turns on where the applied hash came from, because the Manager can fill it in two very different ways:

proxy_metrics_urlApplied hash sourceWhat it means
configuredproxyRead back from the proxy's own /config-hash. An observation.
not configuredpushThe hash the Manager itself just rendered, recorded after the proxy returned 2xx. An assumption.

With source push, rendered == applied is the same number written down twice. It is an identity, not evidence, and it stays true even if the proxy failed to load the config, was rolled back, was restarted onto a stale on-disk Caddyfile, or was reconfigured by hand.

Matching hashes are not, by themselves, a check.

pfy proxy status reports an unverified match as unknown, not healthy; the one branch that says healthy is the only one holding evidence. Set proxy_metrics_url in the Manager to turn the comparison into a real check.

pfy proxy status ​

Reads the sync loop's telemetry and scores it.

bash
pfy proxy status

A verified, converged install:

Proxy sync is ON and healthy - the proxy itself reports running the config the Manager renders.

  sync:          ON
  verdict:       healthy
  drift:         in_sync
  rendered hash: 9f2c4ae1b7d03e58
  applied hash:  9f2c4ae1b7d03e58
  hash source:   the proxy itself (verified)
  last attempt:  2026-09-05T14:31:07Z

The same hashes, with no proxy_metrics_url:

Proxy sync is ON and the hashes match, but NOTHING VERIFIED IT - the proxy has not been asked what it is running.

  the rendered and applied hashes match, but the applied hash is the
  Manager's own record of what it last pushed (source "push"), not something
  read back from the proxy. Accepting a config and serving it are different
  claims: if the proxy failed to load it, was rolled back, or was changed
  out of band, this payload would look exactly the same. Configure
  `proxy_metrics_url` in the Manager so the applied hash is read from the
  proxy's own /config-hash, and this becomes a real check.

  sync:          ON
  verdict:       unknown
  drift:         in_sync
  rendered hash: 9f2c4ae1b7d03e58
  applied hash:  9f2c4ae1b7d03e58
  hash source:   the Manager's own last push (ASSUMED, not verified - set proxy_metrics_url to verify)
  last attempt:  2026-09-05T14:31:07Z

Note drift: in_sync alongside verdict: unknown. The drift field reports the hash comparison, and the hashes genuinely do match; the verdict reports whether that means anything.

A render the proxy rejected:

Proxy sync is ON but UNHEALTHY - the Manager could not render or could not push the proxy's configuration.

  sync:          ON
  verdict:       unhealthy
  drift:         drift
  rendered hash: 9f2c4ae1b7d03e58
  applied hash:  41b8005cd9e7a222
  hash source:   the proxy itself (verified)
  last attempt:  2026-09-05T14:33:52Z
  last error:    proxy rejected the configuration: adapting config using caddyfile: Caddyfile:212 - unrecognized directive

The previous routing is still serving: the proxy rejects a bad config whole rather than applying part of it. The applied hash is the older config it kept.

Exit codes ​

Only with --exit-code; without it a successful read always exits 0.

CodeMeaning
0sync is on, the last push was accepted, rendered == applied, and that agreement was verified
1the status could not be read at all: unreachable manager, bad token, bad flags
3sync is on and the state is bad: unhealthy, or drifted
4the state could not be determined: sync off, status withheld, no applied hash yet, or the hashes match but nothing verified them

pfy proxy diff ​

Compares the two hashes and reports in_sync / drift / unknown.

bash
pfy proxy diff
in_sync - the proxy last applied the same config the Manager renders now.

  compared:      SHA-256 hashes only (the proxy does not expose its running config text)
  rendered hash: 9f2c4ae1b7d03e58
  applied hash:  9f2c4ae1b7d03e58
DRIFT - the config the Manager renders now differs from the one the proxy last applied.

  compared:      SHA-256 hashes only (the proxy does not expose its running config text)
  rendered hash: 9f2c4ae1b7d03e58
  applied hash:  41b8005cd9e7a222

This is not a line-by-line diff.

No Manager API exposes the proxy's running configuration text, only its hash. pfy proxy diff therefore tells you that the two differ, never how. The name is aspirational.

diff is narrower than status, and scores an unverified match as clean ​

diff's contract is explicitly the hash comparison, so on an unverified match it reports in_sync and exits 0, where pfy proxy status reports unknown and exits 4 on the identical payload.

That is deliberate (the hashes do match, and reporting the comparison is all diff claims to do), but it means pfy proxy diff --exit-code is not a gate on the edge being correct. Use pfy proxy status --exit-code for that.

Inspecting one application's rendered vhost ​

Given an application target, diff additionally prints the vhost blocks the Manager would render for it:

bash
pfy proxy diff my-app --project my-saas
pfy proxy diff my-app --project my-saas --show-rendered   # full text

This is the rendered side only. It is useful to read, it is not diffed against anything, and it never changes the verdict above it.

Flags ​

FlagDescription
--slugtarget slug (or pass it positionally); a UUID value is auto-detected as an ID
--idtarget by ID explicitly, the escape hatch when a slug happens to look like a UUID
--projectproject slug, needed to resolve an application slug to an ID
--show-renderedwith an application target, print the full rendered vhost text
--exit-codeexit 3 on drift and 4 when undetermined, instead of always 0

Exit codes ​

CodeMeaning
0in_sync: rendered and applied hashes match
1the comparison could not be made at all
3drift: the hashes differ
4unknown: sync is off, status withheld, or nothing is known to have been applied

pfy proxy sync ​

Asks the Manager to render and push now, blocking until the push has settled.

This is the same push the Manager already performs on its own. Run it by hand when you would rather not wait for the reconcile, or to re-assert the declared config over a proxy that was changed out of band.

There is deliberately no confirmation prompt and no --yes. This pushes the configuration the Manager already declares: it is convergent and idempotent, it deletes nothing, and a config that does not parse is rejected whole with the previous routing still serving.

Outcomes ​

A call that returned without an error is not proof that this Manager pushed, so the outcome is always stated:

OutcomeMeaning
PUSHEDthe proxy accepted the configuration; it is live
ALREADY_CURRENTthe proxy reported it is already running exactly this configuration, so nothing was pushed. This one is read from the proxy, so it is evidence about the edge
LOCK_BUSYanother Manager instance holds the push lock. This Manager pushed nothing. The install is converging, just not from here; re-run to sync from this Manager

Sync being off, a failed render, a config the proxy rejected, and an unreachable proxy are errors rather than outcomes: they never come back as a result.

PUSHED - the Manager rendered the current configuration and the proxy accepted it.

  manager: the proxy accepted the configuration

The sync loop's state after this push:

Proxy sync is ON and healthy - the proxy itself reports running the config the Manager renders.

  sync:          ON
  verdict:       healthy
  drift:         in_sync
  rendered hash: 9f2c4ae1b7d03e58
  applied hash:  9f2c4ae1b7d03e58
  hash source:   the proxy itself (verified)
  last attempt:  2026-09-05T14:31:07Z

LOCK_BUSY exits 4 with or without --exit-code, even when the state it reports looks healthy:

NOT SYNCED (LOCK_BUSY) - this Manager pushed nothing: another Manager instance holds the proxy-sync lock.

  manager: another Manager instance holds the push lock

  the install is converging, just not from here: another instance is pushing
  from the same database. The state below was read by THIS Manager and may
  predate that other push. Nothing you asked for was done by this call -
  re-run it to push from this Manager.

A drift report is information about the world; a sync that did not sync is the command failing to do the one thing it was asked to do.

Exit codes ​

CodeMeaning
0the call pushed, or found the proxy already current, and (with --exit-code) the state it left behind is healthy, in sync, and verified
1the sync did not happen: sync is off, the render failed, the proxy rejected the config or was unreachable, or the token is not an admin token
3only with --exit-code: the push completed and the state it left behind is bad
4LOCK_BUSY (not gated by the flag), or, with --exit-code, a state that cannot be determined, including a PUSHED whose agreement is unverified

Withheld looks like off ​

When the token is not a system-administrator one, the Manager does not return an error. It returns proxy status in the same zero-valued shape it uses when no sync loop is configured, and the two cannot be told apart from the client side:

Proxy sync is OFF - the Manager is not maintaining the proxy's configuration.

  sync is OFF or was withheld: the Manager's proxy status is unset either
  because `proxy_admin_url` is not configured (no sync loop runs, and the
  proxy holds whatever config last reached it) or because this token is not
  an admin token (the Manager withholds proxy status using the same
  zero-valued shape). This is NOT a clean result - nothing has been
  compared.

Both are reported as unknown and exit 4 with --exit-code. Neither is ever scored as healthy: in that state the Manager has never looked at the proxy, so its empty hashes and false booleans are zero values, not agreement.

In CI ​

bash
# Gate a pipeline on the edge actually being correct.
pfy proxy status --exit-code

Reserve exit 1 in your own handling for "could not get an answer": it is the default for every pfy failure and does not describe the edge.

On an install without proxy_metrics_url, pfy proxy status --exit-code can never exit 0: nothing is verifiable, so the answer is always "undetermined". If a gate on such an install is what you want, configure proxy_metrics_url first; do not substitute pfy proxy diff --exit-code, which returns 0 by ignoring the question.

See also ​