A deployment platform is a program that runs privileged operations on behalf of a user. It starts containers, writes nginx configs, opens SSH sessions, and edits DNS records. Every one of those is a command an attacker would like to run.
The naive shape is a request handler that does the work. A POST arrives, the handler shells out to docker compose up, and the response waits. That design puts privileged execution on the same path as an unauthenticated HTTP request, which is the wrong place for it.
Three layers, one direction
The control plane separates into three parts. The request layer validates input, checks permissions, and enqueues a job. Background workers pick jobs up and run them. Runtime adapters wrap the actual privileged commands, one per target: Docker, Compose, SSH, Git, DNS, ingress.
Requests only ever write to the queue. Workers only ever read from it. Adapters only ever run what a worker hands them, and each adapter exposes a narrow set of operations rather than a general shell.
// The handler enqueues; it never executes.
queue.enqueue(Job::Deploy { service_id, revision }).await?;
What this buys is a single choke point. Permissions are checked where the job is created, so a worker does not have to re-derive whether the caller was allowed. The adapter surface is small enough to audit, because it is a list of named operations rather than a command builder.
Secrets that stay encrypted
Credentials for Git hosts, registries, and DNS providers are encrypted at rest and decrypted only inside the worker that needs them, for the duration of one job. The request layer never holds a decrypted credential, and the API never returns one.
That constraint shapes the API. There is no endpoint that reads back a stored token, because there is no layer that could safely serve it. Rotation writes a new value and the old one is gone.
Loopback only, by default
The control plane binds to loopback unless explicitly configured otherwise. A self-hosted deployment tool is often reached through a reverse proxy on the same machine, so the safe default is the one that is not reachable from the network at all.
Each of these decisions is small. Together they mean that compromising the HTTP layer does not immediately hand over the host, which is the property that matters when the software is designed to run with root-equivalent access.
Rollback is part of the job, not an undo
Every deploy records the revision it replaced, so rolling back is a new deploy of a known-good revision rather than a reversal of the last one. Reversals are fragile: they assume nothing else changed in between, and something usually did.
The record is what makes the difference. A deployment history that stores what actually ran is worth more than a revert button that guesses.



