Semaphore (or Semaphore UI) is the open-source web interface for running Ansible playbooks. Simple, lightweight, self-hostable. Born as a pragmatic alternative to AWX (upstream open-source of Ansible Tower / Red Hat Ansible Automation Platform) — fewer features, but dramatically simpler to operate. For mid-size teams that have outgrown “run from laptop” but don’t need AWX complexity, it’s the sensible choice.
What Semaphore Solves
Problems arising as teams grow:
- Audit: who ran which playbook when against which hosts?
- Permissions: which users can run which playbooks against which inventory?
- History: what output did that execution a week ago produce?
- Schedules: periodic playbooks without dedicating a cron host.
- Centralised secrets: vault keys, SSH keys, without distributing across laptops.
Without a central UI, all this becomes ad-hoc and fragile.
Architecture
Minimum components:
- Semaphore server (Go, single binary).
- Database: MySQL/MariaDB, PostgreSQL, or embedded BoltDB.
- Ansible available on the server or container.
No distributed workers or complex queues. For teams with <100 simultaneous runs, enough.
Docker Install
version: "3.8"
services:
semaphore:
image: semaphoreui/semaphore:latest
ports:
- "3000:3000"
environment:
SEMAPHORE_DB_DIALECT: postgres
SEMAPHORE_DB_HOST: postgres
SEMAPHORE_DB_USER: semaphore
SEMAPHORE_DB_PASS: ${DB_PASS}
SEMAPHORE_DB: semaphore
SEMAPHORE_PLAYBOOK_PATH: /tmp/semaphore
SEMAPHORE_ADMIN_PASSWORD: ${ADMIN_PASS}
SEMAPHORE_ADMIN_NAME: admin
SEMAPHORE_ADMIN_EMAIL: admin@example.com
volumes:
- semaphore_data:/etc/semaphore
- semaphore_tmp:/tmp/semaphore
depends_on:
- postgres
postgres:
image: postgres:16
environment:
POSTGRES_USER: semaphore
POSTGRES_PASSWORD: ${DB_PASS}
POSTGRES_DB: semaphore
volumes:
- postgres_data:/var/lib/postgresql/data
volumes:
semaphore_data:
semaphore_tmp:
postgres_data:
Start and log into http://localhost:3000 as admin.
Key Concepts
Project: isolated space with its inventory, keys, templates.
Inventory: list of hosts. Can be static (direct list) or dynamic (script, AWS, etc).
Key Store: SSH keys, passwords, vault passwords. Used when running playbooks.
Repository: Git repo where your playbooks live. Semaphore pulls and executes.
Task Template: associates a playbook + inventory + keys. This is what runs.
Schedule: a template that runs on cron.
Typical Flow
- Your team has a Git repo with Ansible playbooks.
- Create project in Semaphore, pointing at the repo.
- Define inventory (production, staging, etc).
- Load SSH key with host access.
- Create templates: “deploy web service”, “rotate certs”, “restart postgres”.
- Team members run templates from UI, with live logs.
All with permissions: admin can everything, others only what you assign.
Permissions and RBAC
Semaphore has:
- Global admin: manage users, settings.
- Project owner: manage their project.
- Manager: can run + edit templates.
- Task runner: only run existing templates.
- Guest: read-only.
For teams with clear dev/ops separation, this covers. For complex multi-tenancy, AWX has more granularity.
CI/CD Integration
Semaphore exposes REST API. Common patterns:
- Gitea / GitHub Actions calls Semaphore API after PR merge.
- Repo webhook to Semaphore for dynamic-inventory rebuild.
- ChatOps: Slack bot running templates via API.
- Monitoring: alerts trigger remediation templates.
Example curl:
curl -X POST https://semaphore.example.com/api/project/1/tasks \
-H "Cookie: semaphore=..." \
-d '{"template_id": 5, "debug": false}'
Semaphore vs AWX
| Aspect | Semaphore | AWX |
|---|---|---|
| Deploy complexity | Simple (Docker) | Complex (Kubernetes recommended) |
| Database | Simple PostgreSQL | PostgreSQL + Redis |
| RBAC | Basic-medium | Advanced |
| Custom collections | Yes | Yes |
| Workflows | Limited | Advanced (graph) |
| Notifications | Basic | Advanced |
| Commercial support | — | Yes (Red Hat) |
| Resource consumption | Low (~500MB RAM) | High (~4GB RAM) |
| Learning curve | Low | Medium-high |
Semaphore for teams <50 with moderate needs. AWX for large teams with complex requirements.
Where It Falls Short
Honestly:
- Complex multi-step workflows: AWX does better.
- Enterprise SSO with complex SAML: Semaphore has basic OIDC.
- Multi-organisation: Semaphore has “projects”, AWX has orgs.
- Horizontal scaling: Semaphore runs on one node; AWX distributes.
- Fine-grained metrics: AWX has more built-in observability.
Real Cases
Patterns we see:
- 20-50 admin company: Semaphore as centralised runner.
- MSP managing 100 clients: one project per client in Semaphore.
- Platform engineering team: self-service for dev teams via pre-approved templates.
- Compliance: audit log to show who did what when.
Security
Operational checklist:
- Mandatory HTTPS via reverse proxy (Traefik, Nginx).
- Integrated auth with OIDC or LDAP if available.
- SSH keys with passphrase or Vault for secrets.
- Regular backup of data volume + DB dump.
- Monitor failed login attempts.
- Update versions — read changelog.
HashiCorp Vault Integration
Semaphore can query Vault secrets at runtime:
- name: fetch secret
set_fact:
api_key: "{{ lookup('hashi_vault', 'secret=secret/data/api token=VAULT_TOKEN') }}"
With VAULT_TOKEN in Semaphore as env var. Secrets never on disk.
Conclusion
Semaphore is the pragmatic option for mid-size teams wanting an Ansible UI without AWX complexity. Its simplicity focus is its strength: install in minutes, operate painlessly, covers real cases. For large organisations with complex workflow requirements, enterprise SSO, and multi-tenancy, AWX remains the reference. Choice should be based on team size and needs sophistication. Often, simple is right.
Follow us on jacar.es for more on Ansible, automation, and practical DevOps.