Runners
Runners execute your steps. Managed runners (Linux/OpenBSD) work out of the box; self-hosted runners put builds and deploys on your own machines — the recommended setup when your targets live behind a firewall, since probes and deploys originate from the runner.
Install
Runners → New runner mints a one-time token and shows the install command for each distribution:
- Script — self-updating (signed, key-pinned), needs Elixir on the host.
- Binary — self-contained (no runtime needed), systemd unit included.
- Docker / Helm — container image, or the Helm chart for Kubernetes with optional KEDA scale-to-zero on queue depth.
Isolation
Build steps run isolated by default — hardened docker on Linux (all capabilities dropped, read-only rootfs), vmm on OpenBSD, bhyve on FreeBSD (jails as a lighter opt-in), Tart VMs on macOS, Windows containers on Windows. Self-hosted runners may opt into bare execution per runner; managed runners never run bare.
SSH access
Deploy steps (and target connectivity probes) SSH from the runner using its own keys —
the web tier never holds your machine credentials. Add the runner's public key to each
target user's ~/.ssh/authorized_keys.
Register runners over the API
Admins can register, change and revoke runners with an API key
(GET/POST /api/v1/runners, PUT/DELETE /api/v1/runners/:id, or the
runner_*
MCP tools). To keep the token on the runner host, generate it there
and register only its SHA-256:
TOKEN=ykd_$(head -c 24 /dev/urandom | base64 | tr '+/' '-_' | tr -d '=')
SHA=$(printf '%s' "$TOKEN" | sha256sum | cut -d' ' -f1)
curl -fsS -X POST https://yakdeploy.com/api/v1/runners \
-H "authorization: Bearer $YAKD_API_KEY" -H 'content-type: application/json' \
-d "{\"name\":\"build-2\",\"tags\":[\"docker\"],\"token_sha256\":\"$SHA\"}"
Omit token_sha256 and a token is minted and returned once. Every change is in
the audit log; revoking a runner that is running a job needs force=true.
Managed builders
Don't want to run build machines? Set builders: managed
(or own_then_managed) on a project or a fleet in yakdeploy.yaml
and its
per-OS fleet builds run on YakDeploy managed builders: one job per builder, a fresh
container (Linux) or VM (OpenBSD) and workspace each time, no outbound network except
YakDeploy and allowlisted hosts, and a credential that can only upload that one build and
dies with the job. Usage is metered in build-minutes per OS
(GET /api/v1/managed-builders/usage) against your monthly budget.
Private SSH through YakTunnel
Hosts that should not accept SSH from the internet can be reached through a YakTunnel
connector. Link YakTunnel once (PUT /api/v1/tunnels/integration; the
management key is write-only), declare a connector on a target and install it:
curl -fsS -X PUT https://yakdeploy.com/api/v1/targets/42/tunnels \
-H "authorization: Bearer $YAKD_API_KEY" -H 'content-type: application/json' \
-d '{"ssh_route":"direct_then_tunnel","tunnels":[{"name":"h1-ssh","target":"127.0.0.1:22","grants":["jobs"]}]}'
curl -fsS -X POST https://yakdeploy.com/api/v1/tunnels/7/install -H "authorization: Bearer $YAKD_API_KEY"
YakDeploy creates a private endpoint on YakTunnel and installs the connector with a runbook
(systemd or rc.d; its key is written 0600 and never logged). Steps on a tunnel-routed host
then get $YAKD_SSH_PROXY_OPT
(an OpenSSH ProxyCommand) and a
YakTunnel key that works only for that host and only while the step runs. SSH stays
end-to-end: the host key is checked against the same pinned known_hosts
entry. Runners need the yaktunnel
client. In your own scripts, add
${YAKD_SSH_PROXY_OPT:+"$YAKD_SSH_PROXY_OPT"}
to ssh.