Self-host Docker
Self-host Docker is available by request for private deployments. Hosted Pulse is the fastest path for most teams; Docker self-host is for organizations that need the gateway inside their own infrastructure (Docker/workerd).
Canonical detail lives in the Pulse-Proxy docs/self-host/docker.md on GitHub (build pipeline, env files, and verification commands).
Access (private during launch)
The ghcr.io/orionslock/pulse-proxy package is private during this phase. A public, unauthenticated docker pull is not supported. Access is granted by request to trusted beta users, paid self-host customers, and enterprise or security-review engagements. Use docker login ghcr.io with a GitHub token that has the read:packages scope and access to the package. Do not paste tokens into chat, tickets, or logs; revoke and reissue if exposed.
After access is granted — pull
Prefer a semver tag; do not use :latest as a production default.
docker login ghcr.io
docker pull ghcr.io/orionslock/pulse-proxy:v0.1.3
Digest-pinned (example; use the digest from your trusted release if different):
docker pull ghcr.io/orionslock/pulse-proxy@sha256:bd519d536efafb394e35e2547c4ebd2517a9594090f80b4998ac2a092fcdf2bd
What the runtime image contains
The image does not ship the TypeScript source tree, tests, docs/, .git, .env, package manifests, tsconfig, or dev dependencies. It does include the compiled, minified bundle (dist/worker.js) and docker/workerd.capnp (plus the workerd binary and OS base). The minified JavaScript is still a program and can be analyzed with effort; minification is not encryption.
Hosted Pulse vs Docker self-host
| Area | Hosted Pulse | Docker self-host |
|---|---|---|
| Availability | Public self-serve | Private access by request (this phase) |
| Where it runs | Managed Cloudflare edge | Your infrastructure (VMs/Kubernetes) |
| Operations | Managed updates, dashboard, retention | You manage scaling, upgrades, and ops |
| Edge | Global anycast | Not global Cloudflare edge unless you also deploy to Cloudflare |
| Onboarding | Fastest default | Private deployment, compliance, or formal security review |
Self-hosting gives runtime control in your network. Pulse Cloud (hosted) provides managed edge scale, dashboard, retention, team governance, incident history, updates, and support.
Build and run (from source)
npm run docker:build
docker compose up --build -d
npm run docker:smoke builds the image, boots it, checks health endpoints, verifies missing-env behavior, and exports the final image filesystem to ensure source tree artifacts are absent.
Required environment variables
SUPABASE_URL: Managed state-store URL used for dashboard metadata, key lookup fallback, and budget RPC fallback.SUPABASE_SERVICE_KEY: Service-role key used server-side only. Supply via your orchestrator secret store.
Optional environment variables
ENVIRONMENT: Deployment label such as self-host, staging, or prod.SCANNER_VERSION: ThreatPrint scanner version exposed in readiness output and logs.RULES_VERSION: ThreatPrint rules version exposed in readiness output and logs.DEFAULT_RATE_LIMIT: Default per-key request rate when no explicit key limit is present.MIN_RESERVATION_USD: Smallest budget reservation amount for a proxied request.
Health semantics
/v1/livez is process-only liveness and must not require the managed state store. /v1/ready returns structured JSON for state-store, KV, and budget Durable Object status. Missing KV or state-store returns not_ready; missing budget DO may return degraded because state-store budget RPC fallback is supported.
Self-host limitations
Docker and workerd do not automatically provide Cloudflare global HA, globally replicated KV, or globally coordinated Durable Objects. Single-container deployments are simplest. Multi-replica deployments need sticky routing, external coordination, or the documented state-store fallback path for budget coordination.
Security model
Treat docker/workerd.capnp, the image digest, and runtime env vars as trusted infrastructure. Store SUPABASE_SERVICE_KEY in orchestrator secrets. Terminate TLS in front of workerd. No original source tree is shipped, but the minified bundle remains inspectable like any binary artifact.
Supply chain verification
Releases are built in GitHub Actions: Docker smoke and source-tree checks, Trivy (HIGH/CRITICAL), an SPDX SBOM via Syft, Cosign signing, then push to private GHCR. Trivy SARIF upload to GitHub Code Scanning may not appear on all org plans; the scans still run in CI.
Example (adjust tag to your release): cosign verify with --certificate-oidc-issuer https://token.actions.githubusercontent.com and an identity regexp matching your repo’s release-image.yml at a semver tag — see the workflow’s printed summary. Example ref: ghcr.io/orionslock/pulse-proxy@sha256:…
cosign download attestation and trivy image work against the same registry reference. Pin by digest in production.
Troubleshooting
/v1/livezfails: workerd is not serving or the container is not reachable on port 8787./v1/readyreturnsnot_ready: inspect dependency checks for missing env, state-store reachability, or KV binding issues./v1/readyreturnsdegraded: budget Durable Object is absent and the deployment is using the state-store fallback path.- Image verification fails: deploy by digest, confirm the tag was built by
.github/workflows/release-image.yml, and check the OIDC issuer. unauthorizedon pull: you are not logged in to ghcr.io, the token lacksread:packages, or your account has not been granted package access.