SwitchTenderSwitchTender Docs

Quickstart

No install needed to look around. The live demo is a seeded, read-only instance of exactly what you get.

Requirements

Ansible on the PATH: ansible-playbook and ansible-inventory. Nothing else for the default SQLite setup. Building from source instead of installing the release binary needs Go 1.26, and Docker Compose is an alternative, where docker compose --profile stack up --build builds the image from this repository.

Install

curl -fsSL https://switchtender.com/install.sh | sh

The script downloads the release binary for your platform, checks it against the published checksums, and installs it. It writes to /usr/local/bin when it can and to ~/.local/bin otherwise, which is what happens on a stock Mac and on any Linux install without root. That second directory is often not on PATH, so the script says so and prints its closing commands with the full path; add the line it gives you to run switchtender by name. Running in about a minute. Prefer to build it yourself, or want to hack on it? go build -o switchtender . from a clone produces the same binary; the commands below assume it is on your PATH, so prefix a locally built binary with ./.

Run the server

SWITCHTENDER_ENCRYPTION_KEY=change-me SWITCHTENDER_ENCRYPTION_SALT=change-me-too \
  switchtender serve --addr :8080 --db switchtender.db

The key and salt together seal stored credentials at rest with argon2id and AES-256-GCM. Without both the server still runs, but credential features stay off. Keep the salt stable across restarts or existing credentials cannot be decrypted.

The first start on an empty database mints an initial admin token and prints it once, so the API is authenticated from the first request. Export it for the commands below:

export ST_TOKEN=<the token serve printed>

Open http://localhost:8080 for the web UI and sign in with that token, or use the API directly.

A fresh install opens with an empty templates list. switchtender examples --db switchtender.db seeds a handful of starter templates that run with no project, inventory, or credential, so a first launch works on the spot. It skips a template whose name is already present, so it is safe to re-run.

On your own machine, switchtender desktop does all of this in one command. It picks a stable loopback port, keeps its data in a per-user directory, and opens the UI. The desktop guide covers it, including packaging.

Submit a run

The first one needs nothing on disk, so it succeeds on an install that is minutes old:

curl -X POST localhost:8080/v1/runs \
  -H "Authorization: Bearer $ST_TOKEN" \
  -d '{"tool": "bash", "command": "echo hello from switchtender"}'

An Ansible run takes a playbook and an inventory. The server resolves both relative to its own working directory, so site.yml and hosts.ini have to exist there, or the run names a project and they are resolved inside that checkout instead. Without either the run is submitted, accepted, and then fails with "the playbook: site.yml could not be found":

curl -X POST localhost:8080/v1/runs \
  -H "Authorization: Bearer $ST_TOKEN" \
  -d '{"playbook": "site.yml", "inventory": "hosts.ini"}'

The response carries a run id. Fetch its status, its structured events, or its log:

curl -H "Authorization: Bearer $ST_TOKEN" localhost:8080/v1/runs/<id>
curl -H "Authorization: Bearer $ST_TOKEN" localhost:8080/v1/runs/<id>/events
curl -H "Authorization: Bearer $ST_TOKEN" localhost:8080/v1/runs/<id>/logs

Add "shards": 4 to the body to split the run across four slices of the inventory, balanced by each host's measured duration in recent runs.

Add a worker (Team)

Distributed execution is a Team feature, so every switchtender worker needs a license and refuses to start without one. Community runs everything on the server itself, which is the default and needs no extra process: this section is for when one machine is no longer enough.

Point a worker at the same database and it competes for queued runs:

SWITCHTENDER_ENCRYPTION_KEY=change-me SWITCHTENDER_ENCRYPTION_SALT=change-me-too \
  switchtender worker --db switchtender.db --name laptop

For more than one machine, use a PostgreSQL DSN as the --db value on every process.

Queues are part of the same feature: naming one on a run, a template, or an inventory source routes it to a worker serving that name, so it is refused on Community rather than accepted and left with nothing able to claim it.

Lock down the API

The initial admin token from the first start is yours to keep, but a shared install deserves named tokens so the audit trail says who did what. Mint one per person and per CI job:

switchtender token new --db switchtender.db --name ci

A loopback bind, or --read-only, serves without authentication instead, since neither exposes an unauthenticated API to the network.

Create user accounts with roles for sign-in:

SWITCHTENDER_PASSWORD=secret switchtender user new operator-jane --role operator --db switchtender.db

Run with Docker

The compose file lives in the repository, so this one needs a checkout rather than the installed binary:

git clone https://github.com/kordloom/switchtender
cd switchtender
export SWITCHTENDER_ENCRYPTION_KEY=change-me
export SWITCHTENDER_ENCRYPTION_SALT=change-me-too
docker compose --profile stack up --build

This starts a server and a PostgreSQL database. The server listens on port 8080. Set SWITCHTENDER_PORT to change the host port.

Workers are a separate profile because they are Team: docker compose --profile stack --profile workers up --build adds one, and it needs a license to start.

Set up a production server

For a real install, init generates the encryption key and salt, creates the first admin account, and writes a config file in one step. It can also write a systemd unit:

switchtender init --db switchtender.db --config switchtender.env --systemd switchtender.service

It prints the admin password once, so save it. Move the unit into place and start it:

sudo cp switchtender.service /etc/systemd/system/switchtender.service
sudo systemctl enable --now switchtender

Serve HTTPS directly, with no reverse proxy in front, by pointing the server at a certificate and key:

switchtender serve --db switchtender.db --tls-cert tls.crt --tls-key tls.key

Run on Kubernetes

SwitchTender needs no operator. A Helm chart installs the server and a worker as ordinary pods sharing a database:

The chart is in the repository too, so clone it first if you installed the binary alone:

git clone https://github.com/kordloom/switchtender
cd switchtender
helm install switchtender ./deploy/helm/switchtender \
  --set encryptionKey=$(openssl rand -hex 32) \
  --set encryptionSalt=$(openssl rand -hex 16)

Add --set auditKey=$(openssl rand -hex 32) too, a 32 byte ed25519 seed as hex, or that install cannot sign a receipt. A deployment that shares one database will not create a signing key by itself, because every server and worker has to sign as the same install, and a key minted inside one pod would be that pod's alone. Without it the chain still records and still verifies, but no receipt, signed bundle or trust document can be produced, which is most of why anyone runs this. Keep the seed where you can restore it.

Both values are required, and the salt has to stay the same across upgrades: it is what every stored secret was sealed against, so a new salt makes the old ones unreadable. Keep them in a secret manager and pass --set existingSecret=<name> instead once you have one. The chart pulls ghcr.io/kordloom/switchtender.

Try the demo

To look around without setting anything up, run the seeded demo. It fills a fresh database with sample projects, templates, inventories, and real runs, including a flaky host, a split, and a pipeline, then serves it read-only so it is safe to expose:

switchtender demo --addr :8080

Or with Docker, from a checkout: docker compose --profile demo up --build.