REST API

The Docker API, from one binary.

cardinal serve exposes a Docker-compatible REST API (Docker API version 1.44) so Portainer, VS Code Dev Containers, CI runners and custom scripts talk to cardinal without changes — with a Bearer token, TLS and rate limiting built in.

Quick start

Start the API and hit it.

start the API
# loopback only — safe without a token
cardinal serve

# external bind requires a token
cardinal serve -H 0.0.0.0 -p 2375 --token "$CARDINAL_TOKEN" -d

# or as a systemd service (auto-start on boot)
sudo cardinal serve on --port 2375
sudo cardinal serve status
sudo cardinal serve off
first requests
curl -s http://localhost:2375/_ping          # OK
curl -s http://localhost:2375/version          # Docker API 1.44
curl -s http://localhost:2375/containers/json  # running containers
curl -s http://localhost:2375/images/json      # local images
In every example below, add -H "Authorization: Bearer $CARDINAL_TOKEN" when you started the server with a token. Container IDs work as full ID, ID prefix, or container name.
Reference

System & discovery

MethodPathDescription
GET/_pingHealth check — returns OK
GET/versionServer + API version (1.44, min 1.24)
GET/infoHost, storage, CPU, memory, container/image counts
GET/API banner — version and data directory

Containers

MethodPathDescription
GET/containers/jsonList containers (?all=1 includes stopped)
POST/containers/createCreate a container (JSON body; pulls the image)
GET/containers/{id}/jsonInspect — full container state
POST/containers/{id}/startStart a created/stopped container
POST/containers/{id}/stopStop (?t=SECONDS grace period)
POST/containers/{id}/restartRestart
POST/containers/{id}/killForce-kill the main process
DELETE/containers/{id}Remove (?v=1 remove volumes, ?force=1)
GET/containers/{id}/logsLogs (?tail=50, ?stdout=1, ?stderr=1)
GET/containers/{id}/topProcesses running inside
GET/containers/{id}/statsCPU / memory / I/O usage
POST/containers/{id}/renameRename (?name=web2)
POST/containers/{id}/updateChange limits (memory, CPUs, restart policy)
POST/containers/{id}/execRun a command inside (JSON body with Cmd)
POST/containers/{id}/waitBlock until exit — returns status code
GET/containers/{id}/changesFilesystem changes vs image

Images

MethodPathDescription
GET/images/jsonList local images
GET/images/{name}/jsonInspect an image
DELETE/images/{name}Remove an image
POST/images/{name}/pushPush to a registry (auth via X-Registry-Auth)
POST/images/{name}/tagTag (?repo=…, ?tag=…)
GET/images/{name}/historyBuild history
GET/images/{name}/getExport an image archive

System, cluster & metrics

MethodPathDescription
POST/system/pruneRemove unused containers/images (?containers=false, ?images=false)
POST/cluster/replicasCreate a service replica (JSON body)
DELETE/cluster/replicas/{id}Remove a replica
GET/cluster/containersList containers on this node
GET/cluster/healthCluster health — {"status":"ok"}
GET/metricsPrometheus metrics (Bearer token required by default)
Examples

Create, run, inspect — with curl.

create a container
curl -s -X POST http://localhost:2375/containers/create \
  -H "Content-Type: application/json" \
  -d '{
    "Image": "nginx:alpine",
    "Hostname": "web",
    "HostConfig": {
      "PortBindings": { "80/tcp": [{ "HostPort": "8080" }] },
      "RestartPolicy": { "Name": "always" },
      "Memory": 268435456
    }
  }'

# → { "Id": "a1b2c3…", "Warnings": [] }
lifecycle & inspection
curl -s -X POST http://localhost:2375/containers/web/start
curl -s http://localhost:2375/containers/web/json | head -20
curl -s "http://localhost:2375/containers/json?all=1"
curl -s "http://localhost:2375/containers/web/logs?tail=50"
curl -s http://localhost:2375/containers/web/top
curl -s http://localhost:2375/containers/web/stats

curl -s -X POST http://localhost:2375/containers/web/exec \
  -H "Content-Type: application/json" \
  -d '{"Cmd": ["echo", "hello from cardinal"]}'

curl -s -X POST "http://localhost:2375/containers/web/rename?name=web2"
curl -s -X DELETE "http://localhost:2375/containers/web2?v=1&force=1"
images & system
curl -s http://localhost:2375/images/json
curl -s http://localhost:2375/images/nginx/json
curl -s -X POST "http://localhost:2375/images/nginx/tag?repo=myrepo/nginx&tag=v1"
curl -s -X DELETE http://localhost:2375/images/nginx:latest
curl -s -X POST http://localhost:2375/system/prune
curl -s http://localhost:2375/metrics | head -10
Tooling

Point your tools at it.

portainer

Portainer

Environments → Add → Docker Standalone → API. Use http://host:2375 (or https:// with TLS) and paste the Bearer token when prompted.

dev containers

VS Code Dev Containers

Set the Docker context to the API: docker context create cardinal --docker host=tcp://host:2375 — Dev Containers and the Docker extension talk to cardinal directly.

scripts

Anything that speaks Docker

The API tracks the Docker contract — list, inspect, create, start, stop, exec, logs, stats, images — so CI runners and orchestration scripts keep working unchanged.

Hardening

How the API stays safe.

token

Bearer token, constant-time

External binds are refused entirely without --token or CARDINAL_TOKEN; comparisons are constant-time. TLS is optional but does not replace the token — external access always needs both.

limits

Rate limit & body cap

A per-IP token bucket (25 req/s, burst 50) gates non-loopback callers, and request bodies are capped at 8 MB. Loopback traffic is exempt so cardinal exec and friends stay snappy.

cors

No accidental web exposure

CORS is limited to loopback by default; add origins with CARDINAL_CORS_ORIGINS deliberately. Server timeouts, header caps and a hard cap on tracked clients are configured out of the box.

metrics

Metrics stay private

/metrics (Prometheus) requires the Bearer token by default — set CARDINAL_METRICS_REQUIRES_AUTH=0 only on loopback-bound instances.

Compatibility notes: GET /containers/{id}/export returns 501 (use cardinal export), /containers/{id}/changes returns an empty list, and container IDs accept prefixes and names — not just full IDs.

One binary, every endpoint.

The CLI reference covers the same operations from the terminal — run, stop, exec, logs, images, volumes, networks and more.

Read the CLI reference cardinal-wings (remote agent) →