Deploy workers / Containers and sandboxes

Containers and managed sandboxes

Use these profiles when Horde should create and manage worker resources in an existing container environment or sandbox provider. Start with a configured Horde controller and a provider account or cluster you can already access.

Configure Docker, Kubernetes, E2B, or Daytona profiles in runtimes.toml. Docker and Kubernetes require a digest-pinned image. Replace IMAGE_FROM_SIGNED_RELEASE_MANIFEST with the image value, including its immutable digest, from the release manifest.

Docker

# Top-level enrollment settings; use your controller's CA and address.
issuer_key = "/absolute/path/to/controller/ca.key"
controller_address = "CONTROLLER_TAILNET_IP:7443"
controller_tls_name = "controller.your-tailnet.ts.net"

[profiles.containers]
provider = "docker"
context = "default"
image = "IMAGE_FROM_SIGNED_RELEASE_MANIFEST"
concurrency = 4
cpus = 2
memory_mb = 2048
executor_roles = ["planner", "worker", "reviewer"]

The issuer key must match the controller’s configured CA and have mode 0600. Configure the selected roles and managed accounts on the controller. Horde provisions their authorized credentials to workers; ambient subscription logins are not copied.

horde runtime create worker-1 --profile containers --request-id create-worker-1
horde runtime inspect worker-1
horde runtime stop worker-1 --request-id stop-worker-1
horde runtime start worker-1 --request-id start-worker-1

Kubernetes

For Kubernetes, use provider = "kubernetes" with a kubeconfig context and namespace. Each runtime gets a StatefulSet and persistent storage. Make sure the cluster can pull the configured image.

E2B and Daytona

E2B and Daytona require a prepared Horde template or snapshot with persistent runtime data and a restart supervisor. They do not provision from an arbitrary blank image:

[profiles.e2b]
provider = "e2b"
api_key_env = "E2B_API_KEY"
image = "YOUR_HORDE_TEMPLATE_ID"
lifetime_seconds = 3600

[profiles.daytona]
provider = "daytona"
api_key_env = "DAYTONA_API_KEY"
image = "YOUR_HORDE_SNAPSHOT_NAME"
lifetime_seconds = 3600

Sandbox startup and persistence

Install the signed binary inside the template, configure its executor credentials, and use this supervisor as its start command. Keep its data directory on persistent storage:

curl -fsSL https://horde.sh/install | bash -s -- --no-service
#!/bin/sh
# Use as the start command of an E2B template or Daytona snapshot after installing
# an official release with install.sh --no-service. Storage must survive restarts.
set -u
export HORDE_SUPERVISED=1
horde_data_dir=${HORDE_DATA_DIR:-}
set --
[ -z "$horde_data_dir" ] || set -- --data-dir "$horde_data_dir"
child=''
stop() {
  if [ -n "$child" ]; then kill -TERM "$child" 2>/dev/null || true; wait "$child" 2>/dev/null || true; fi
  exit 0
}
trap stop TERM INT
while :; do
  "$HOME/.local/bin/horde" "$@" daemon &
  child=$!
  wait "$child"
  result=$?
  child=''
  [ "$result" -ne 0 ] || exit 0
  sleep 2
done

A provisioned resource becomes ready only after its authenticated controller connection is established.

For enrollment, updates, certificate lifetimes, and project access across several workers, see fleet management. An existing AX deployment uses the separate AX guide.