Whisper · Docs
Containers & cloud

Docker / GHCR

If your deployment target is "wherever docker run works," installing a package manager, a Go toolchain, or a language SDK just to get one static binary onto the box is friction you shouldn't pay.

A bare VM, a CI runner, a Nomad job, a Compose stack, a pod that isn't ready for an operator — ghcr.io/whisper-sec/whisper is the same whisper CLI with nothing to install, a locked digest to pin, and three run-modes (plain CLI, MCP server, egress sidecar) behind one entrypoint.

Container images solve a narrower problem than package managers, but they solve it better for the case that actually dominates agent infrastructure: you don't control the host. A GitHub Action runner, a serverless container platform, a customer's Kubernetes cluster, an air-gapped CI pipeline — none of these let you apt install or brew install anything, but all of them can pull an OCI image. Whisper ships one multi-arch image that carries the exact same Go binary as every other channel — no separate codebase, no "the Docker build lagged the release," because the image is the release: the same CI job that cuts a CLI version bakes it into the container and pushes both in the same run.

What's in the image

ghcr.io/whisper-sec/whisper:<version>     # e.g. :0.128.0
ghcr.io/whisper-sec/whisper:latest        # tracks the newest tagged release

Verify the image is what it claims to be

Don't trust a README that says "run this" — check the same things you would for any third-party image: which CPU archs are actually in the manifest, and that the binary inside answers a --version.

With stock tools:

# what's actually in the manifest (needs buildx or `docker manifest`)
docker manifest inspect ghcr.io/whisper-sec/whisper:latest | jq '.manifests[].platform'
# -> {"architecture":"amd64","os":"linux"}
#    {"architecture":"arm64","os":"linux"}

# pull and run it — proves the binary executes on your arch
docker run --rm ghcr.io/whisper-sec/whisper --version
# -> whisper 0.128.0 (linux/amd64)

# who signed the manifest push / what digest are you actually running
docker inspect --format='{{index .RepoDigests 0}}' ghcr.io/whisper-sec/whisper:latest
# -> ghcr.io/whisper-sec/whisper@sha256:...

With Whisper: there's nothing Whisper-specific to run here — verifying an OCI image is a Docker/OCI-spec operation, not a Whisper API, which is the point: the same docker manifest inspect / docker run --version pattern you'd use on any third-party image is all you need. Pin by digest (ghcr.io/whisper-sec/whisper@sha256:...) rather than :latest in anything that matters — the tag moves, the digest doesn't.

Three run-modes behind one entrypoint

The image is one artifact; what it does is picked by the arguments after it, exactly like the native binary.

1. Plain CLI — one-shot commands

docker run --rm ghcr.io/whisper-sec/whisper verify 2a04:2a01:eb5a:ca74:cef2:2a:323d:40d4
# -> DNSSEC chain valid, PTR matches forward, TLSA present — same keyless check as `whisper verify` anywhere else

No API key needed for verify/rdap — see Verify an agent for what the check actually walks (DNSSEC → PTR → forward A/AAAA → TLSA, RFC 4035 / RFC 6698). Mount a key in for the control-plane half:

docker run --rm -e WHISPER_API_KEY=whisper_live_... ghcr.io/whisper-sec/whisper list
# -> the agents registered under that key

2. MCP server — stdio, for any MCP-speaking agent host

docker run -i --rm -e WHISPER_API_KEY=whisper_live_... ghcr.io/whisper-sec/whisper mcp

This is the container form of the registry entry io.github.whisper-sec/whisper — same tool set (keyless verify/rdap; keyed register/list/policy/logs/revoke/egress-config), just running as a container instead of a locally-installed binary. Point Claude Code, Zed, or any MCP client's config at docker run -i --rm ghcr.io/whisper-sec/whisper mcp as the command instead of a bare whisper mcp if you'd rather not install the CLI on the host at all — see MCP server.

3. Egress sidecar — the mode Kubernetes wants

Run the image as a long-lived connect sidecar; it holds the API key and exposes a loopback SOCKS5 port — exactly the shape the Kubernetes operator injects into a pod.

docker run -d --name whisper-egress \
  -e WHISPER_API_KEY=whisper_live_... \
  ghcr.io/whisper-sec/whisper connect my-agent --tier socks5

Give the app container the same network namespace as the sidecar (Docker --network container:whisper-egress, or the shared-loopback pod model in Kubernetes) so it reaches the proxy on localhost, and point ALL_PROXY at it. Traffic then egresses from my-agent's routable /128 — the same Tier 1.5 mechanism (AnyIP + IP_FREEBIND) described in Connect & egress, just running as a long-lived container next to your app instead of inline in the same process. The app image needs no Whisper code and never handles the bearer — the sidecar does, and the app only ever sees a loopback proxy.

With stock tools, from a container sharing the sidecar's netns:

docker run --rm --network container:whisper-egress curlimages/curl \
  curl -x socks5h://localhost:1080 -s https://api64.ipify.org
# -> 2a04:2a01:eb5a:ca74:cef2:2a:323d:40d4

With Whisper, whisper run inside the app container does the same proxy-env wiring plus a pre-flight egress check in one step — see the whisper connect/whisper run walkthrough in Connect & egress.

Compose — app + sidecar in one file

services:
  whisper-egress:
    image: ghcr.io/whisper-sec/whisper:latest
    environment:
      WHISPER_API_KEY: whisper_live_...
    command: ["connect", "my-agent", "--tier", "socks5"]

  agent:
    image: my-agent:latest
    network_mode: "service:whisper-egress"   # share the sidecar's netns → reach it on loopback
    environment:
      ALL_PROXY: socks5h://localhost:1080
    depends_on: [whisper-egress]

docker compose up gives you an agent process that talks to the world through a routable /128 without a single line of proxy-handling code in the app image — the ALL_PROXY env var is what curl, Python's requests/httpx, Go's net/http, and Claude Code already read natively (Node's global fetch needs undici's EnvHttpProxyAgent wired in — one line, since it doesn't pick up proxy env vars on its own).

Where this fits next to the operator and the raw CLI

The GHCR image is the building block; two other channels consume it rather than duplicate it:

Every path — native binary, container, or Kubernetes sidecar — is the same two-tier contract: no key still gets verify/rdap for free (real value, zero friction); a key unlocks register/list/policy/logs/revoke/egress. The full source for the image build lives in whisper-sec/whisper-cli; status of every distribution channel, this one included, is tracked live at whisper.online/integrations.

Next

Kubernetes — the operator that injects this image as a sidecar automatically · CLI & one-command setup — the same binary installed directly on a host.