Playbook Runner

Run your playbooks from a browser tab.

Playbook Runner is a self-hosted web UI for Ansible: inventory, SSH credentials, playbooks, schedules and a live log of every run, without the weight of AWX or Tower.

Install on a server
curl -fsSL https://raw.githubusercontent.com/Nonetss/playbook-runner/main/scripts/bootstrap.sh | bash

Run it in an empty directory. It asks a few questions, generates every secret and starts the stack with Docker Compose.

runner.example.com/

What you get

  1. Your inventory, with the right key attached.

    Devices and groups live in the database. Each device points at an SSH credential, so picking a group is enough: the right user and key follow every host. Generate an ed25519 pair in the browser and copy a ready-made script that provisions the user on a new host.

    runner.example.com/inventory
  2. Watch every task as it happens.

    Pick a playbook and a group, confirm, run. PLAY and TASK lines stream into the browser as ansible-runner emits them, with no polling. Close the tab and the run is cancelled on the executor.

    runner.example.com/playbooks/:id/run
  3. Or keep your playbooks in Git.

    Add a repository over HTTPS or SSH, pick a branch and a subdirectory. Its playbooks show up read-only and run from a checkout of the synced commit, so roles, templates and group_vars next to them just work.

    runner.example.com/playbooks
  4. Schedule it, then check what happened.

    Give a job a cron expression and the backend fires it on time. A job never overlaps with itself, and the history keeps the status, duration and hosts of every run.

    runner.example.com/jobs/:id
  5. Script it through the API.

    Every endpoint is documented in an interactive OpenAPI reference served at /scalar. Create a personal API key and call it from scripts or CI.

    runner.example.com/scalar

And the rest of the toolbox

Scripts
Save Bash or Python scripts and run them on a selection of hosts, with the same live console.
Ad-hoc commands
Run the shell or command module against any selection, with optional become, for one-offs that don't deserve a playbook.
Users and roles
No public sign-up. Admins create accounts and assign admin, user or pending, which can sign in but waits for approval.
Single sign-on
Any OIDC provider (Keycloak, Authentik, Google…) next to email and password. Three variables turn it on.
API keys
Personal keys sent as x-api-key, for scripts and CI pipelines.
Installable on mobile
The interface is a PWA: add it to your phone's home screen and check a run from anywhere.

How it fits together

Four services and PostgreSQL, run with Docker Compose. Browsers only talk to the Caddy gateway, which sends the API to the backend and everything else to the frontend. The backend owns the database and reaches the Ansible executor over gRPC, through the gateway's internal router.

Request paths

Opening a page
  1. Browser
    → HTTPS
  2. Gateway:80
    Caddy
    → /*
  3. Frontend:4321
    Astro SSR
Running a playbook
  1. Browser
    → /rpc
  2. Gateway:80
    Caddy
  3. Backend:3000
    Hono · oRPC
    PostgreSQL
    → gRPC
  4. gRPC router:50050
    Caddy
    → /run.*
  5. Executor:50051
    ansible-runner
    → SSH
  6. Your hosts

Gateway routing

RequestGoes to
/rpc /api /scalar /openapi.jsonbackend:3000
any other pathfrontend:4321
gRPC /run.* on :50050ansible:50051
any other gRPC serviceUNIMPLEMENTED

Only the gateway's port 80 is mapped to the host, as GATEWAY_PORT. The rest of the services are reachable only inside the Compose network.

Private keys stay on the server.
SSH keys are encrypted at rest with AES-256-GCM and never returned by the API. They are decrypted only to build a run, and the executor deletes the key files when it finishes.
The executor has no database.
The backend resolves the playbook, the hosts and their keys, then sends one complete payload over gRPC, authenticated with a shared service token. Output streams back on the same call.
Runs are bounded.
At most eight Ansible processes run at once by default; extra requests are refused instead of queued. SSH host keys are verified, trusting a host on first contact and rejecting changed keys.
Read the architecture docs

Up in one command.

On a Linux host with Docker, curl and openssl, from an empty directory:

curl -fsSL https://raw.githubusercontent.com/Nonetss/playbook-runner/main/scripts/bootstrap.sh | bash

Back up the generated .env, above all CREDENTIALS_ENCRYPTION_KEY. Losing it makes every stored SSH key unrecoverable.

Prefer to set it up by hand? Deploy with Docker Compose

What the script does

  1. 1Asks for the public URL, the port and the first admin, plus optional OIDC settings.
  2. 2Generates every secret with openssl, including the key that encrypts stored SSH keys.
  3. 3Writes .env and compose.yml in the current directory.
  4. 4Pulls the images from ghcr.io and starts the stack. The backend migrates the database and creates the admin on startup.
runner.example.com