For a production self-hosted deployment you run the Shipfox control plane on your own
compute and connect it to managed dependencies. This page covers the external
services to provision and how to register runners. For a reference deployment on a
specific platform, see AWS or Kubernetes
(both coming soon).
What you run, and what talks to what
Two directions matter: runners only connect outward — you never open an inbound
port into your compute — and agent traffic to model providers leaves from your
runners, with your API keys, not from the control plane.
External services
Provision and connect the following:
| Service | Recommended options |
|---|
| PostgreSQL | Any managed PostgreSQL 15+ instance (RDS, Cloud SQL, Supabase, self-managed) |
| Temporal | Self-hosted Temporal cluster or Temporal Cloud |
| Object storage | Any S3-compatible service (AWS S3, GCS with interop, MinIO, Cloudflare R2) |
The Shipfox API and dashboard are stateless processes that can be deployed as
containers on any compute platform (Kubernetes, ECS, Fly.io, bare VMs). The runner is
a separate process you deploy on the compute where jobs should execute — it does not
need to be co-located with the API.
Runner registration
A runner is a lightweight process you start on any machine — a VM, a bare-metal
server, or a container. Runners poll Shipfox for jobs that match their labels and
execute them locally, streaming logs back to the API in real time.
To register a new runner:
- In the Shipfox dashboard, create a registration token in the runner settings.
- Copy the generated token — it is shown only once.
- Start the runner on your target machine. The runner ships as a Docker image and is configured entirely through environment variables — the API URL, the registration token, and the labels this runner advertises:
docker run --rm \
-e SHIPFOX_API_URL=<YOUR_SHIPFOX_API_URL> \
-e SHIPFOX_RUNNER_REGISTRATION_TOKEN=<YOUR_REGISTRATION_TOKEN> \
-e SHIPFOX_RUNNER_LABELS=<LABEL_1>,<LABEL_2> \
<shipfox-runner-image>
SHIPFOX_RUNNER_LABELS is a comma-separated list (e.g. linux,x64,self-hosted). A job
is dispatched to a runner only when the runner has all the labels listed in the
workflow’s runner: field. Make sure your runner’s labels match exactly what your
workflows declare — a mismatch is the most common cause of runs sticking in pending.
By default a runner exits after an idle window. For a long-lived runner that keeps
polling, set SHIPFOX_POLL_MAX_DURATION_MS=0 in its environment.
To scale runners automatically instead of starting each one by hand, run a
runner provisioner — it starts ephemeral,
single-job runners on demand and lets them exit when idle.
Managed hosting
Prefer not to operate the control plane yourself? With managed cloud,
Shipfox runs the API, database, and orchestration, and you only deploy and connect
runners. Reach out to the Shipfox team for access.