james@perkins :~/writing$
← writing / engineering apis

Deploying and Securing Your API with Unkey

Ship APIs, not infrastructure

Most API teams end up running two stacks: a hosting platform (Vercel, Fly, Render, a Kubernetes cluster) and an auth or rate-limiting layer bolted on top (custom middleware, a gateway, an API-key service). Two dashboards, two sets of logs, two failure modes, and usually a gap between them where things like per-key rate limits or instant revocation get implemented twice, or not at all.

Unkey collapses that. You push a Dockerfile; Unkey builds it, runs it across regions, fronts it with a reverse proxy that enforces auth and rate limits before requests reach your code, and gives you instant rollbacks. This post walks through the deployment model and the security layer.

Requirements

Two things:

  1. A Dockerfile in your repo. Unkey doesn’t auto-detect runtimes and doesn’t run buildpacks. You own the build contract.
  2. Either a connected GitHub repository (for push-to-deploy) or a pre-built image in a registry (for CLI deploys).

That’s the full surface area.

The three deploy paths

All three produce identical, immutable deployments. They differ only in what triggers them.

GitHub push. Connect a repo, pick a branch. Pushes to the default branch go to production; every other branch gets its own preview environment. This is the default path and what most teams use.

CLI. For CI pipelines and custom build systems:

unkey deploy ghcr.io/your-org/api:v1.4.2 \
  --project=api \
  --env=production

The CLI takes a pre-built image, creates the deployment, and streams status until it’s serving traffic. UNKEY_ROOT_KEY and UNKEY_PROJECT can be set via env vars so the command stays clean in CI.

Dashboard. Manually redeploy a specific commit. Useful for re-running a deployment after fixing an environment variable, or promoting a specific SHA.

What happens between push and live

Every deployment, regardless of trigger, moves through the same six phases. This matters because it’s what makes deployments deterministic, and it’s where most self-hosted API platforms get messy.

  1. Event received. Webhook, CLI invocation, or dashboard click. A deployment record is created with status Pending.
  2. Queued. Build capacity is allocated. Skipped entirely for CLI deploys since the image is already built.
  3. Building. Source is fetched at the exact commit SHA and docker build runs on remote infrastructure. Build logs stream live to the deployments tab. If the build fails, the deployment moves to Failed and nothing downstream changes.
  4. Deploying containers. The image is scheduled across your configured regions. Instances start up, and if you’ve defined a health check, Unkey waits for healthy responses on your endpoint before moving on.
  5. Assigning domains. Four domains get generated automatically:
    • A commit domain, permanent and tied to this exact SHA. Useful for comparing versions side-by-side.
    • A branch domain, which tracks the latest deployment on that branch.
    • An environment domain, which tracks the latest deployment in the environment.
    • A live domain (production only), which points to the currently serving deployment.
  6. Finalizing. Routes flip over, traffic flows, status becomes Ready. In production, the previous live deployment goes to standby for 30 minutes so a rollback is one click away. Preview deployments stay running as long as they receive traffic; idle ones (no requests for six hours) are archived automatically.

Every deployment is immutable. The image, config, and variables are frozen at creation time. If you need to change something, you deploy again. This is the property that makes rollbacks safe and reproducible.

Securing the API with Sentinel

This is where Unkey stops looking like just another PaaS.

A Sentinel is a reverse proxy that sits in front of every deployment. It’s provisioned automatically when you create an environment, with nothing to install and nothing to configure at the infra level. Production environments get three Sentinel replicas for HA; preview environments get one. Each environment’s Sentinel is fully isolated, so a bad policy in preview can’t take down production, and cache hit rates stay high because each proxy only caches its own environment’s data.

The Sentinel evaluates policies in order on every inbound request. If all pass, the request is forwarded to a healthy instance in the same region (random distribution, no session affinity). If any policy rejects, your app never sees the request.

Core policy types:

Configuring API-key auth today is three clicks: Project Settings → Sentinel configurations → select keyspace(s) → Save. Other policy types are available via support while the Sentinel dashboard is being built out.

The architectural win: authentication, rate limiting, and validation run in the proxy in front of your code, not inside it. Your app stays a plain HTTP service. Revoke a key in the dashboard and it’s rejected globally within seconds. No cache invalidation code in your app, no race conditions.

Rollbacks

Because deployments are immutable and the previous live version stays warm for 30 minutes, rolling back is a single action in the dashboard and takes effect with zero downtime. If you catch a bad deploy after the 30-minute window, any prior deployment can still be promoted; it just takes a moment to spin back up.

Putting it together

A minimal production setup:

  1. Add a Dockerfile to your API repo.
  2. Create a project in Unkey, import from GitHub, select the repo and regions.
  3. Push to main. Your app is live on an auto-assigned domain within a few minutes.
  4. Add a custom domain.
  5. In project settings, attach a keyspace under Sentinel configurations.
  6. Generate keys for your users via the Unkey API or dashboard.

You now have a multi-region API with per-key auth, rate limiting, instant revocation, and one-click rollbacks, without writing middleware, managing a gateway, or running a second control plane.

0 claps
JP
james perkins
CEO & co-founder at Unkey. Writing about the messy middle between a blank editor and a working company.

Discussion // 0 comments

sort: oldest ↓
?
be excellent to each other
no comments yet — be the first.