Running Ansible Semaphore in Your Home Lab
If you've been using Ansible for home lab automation, you've probably run playbooks from the command line: ansible-playbook -i inventory.yml site.yml. This works fine when you're the only person managing infrastructure, but it's not ideal for:
Photo by Vishnu Mohanan on Unsplash
- Running playbooks on a schedule (weekly updates, nightly backups)
- Giving others (family, team members) access to run specific playbooks without SSH access
- Tracking playbook run history and output
- Triggering automation from webhooks or APIs
Ansible Semaphore solves all of this. It's a modern, self-hosted web UI for Ansible — lighter and easier to deploy than AWX/Ansible Tower, but still powerful enough for serious home lab automation.
What is Ansible Semaphore?
Semaphore is an open-source web interface for running Ansible playbooks. It provides:
- Web-based playbook execution: Click a button to run a playbook instead of SSH-ing to a control node
- Scheduling: Cron-like scheduling for recurring tasks (updates, backups)
- Access control: LDAP/local user authentication with role-based permissions
- Inventory management: Store and version multiple inventories
- Task history: See past runs, output, success/failure status
- API: Trigger playbooks via HTTP (integrate with webhooks, monitoring alerts)
- Secrets management: Store Ansible Vault passwords and SSH keys securely
It's not as feature-rich as AWX (Red Hat's Ansible Tower open-source version), but it's much simpler to deploy and maintain. For home labs, Semaphore is the sweet spot.
Semaphore vs AWX vs Ansible CLI
| Feature | Ansible CLI | Semaphore | AWX/Tower |
|---|---|---|---|
| Installation | apt install ansible |
Docker Compose | K8s operator or Docker (complex) |
| Learning curve | Steep | Moderate | Very steep |
| Web UI | No | Yes | Yes |
| Scheduling | External (cron) | Built-in | Built-in |
| Multi-user | No | Yes (RBAC) | Yes (advanced RBAC) |
| API | No | Yes | Yes |
| Inventory management | Files | Web UI + files | Web UI + dynamic inventory |
| Best for | Solo sysadmin | Small teams, homelabs | Enterprises |
When to use Semaphore: You want a web UI for Ansible, scheduled runs, and multi-user access without the complexity of AWX.
When to use AWX: You need advanced features like dynamic inventories, workflows, or integrate with Red Hat ecosystem.
Installation: Docker Compose
The easiest way to run Semaphore is via Docker Compose.
Prerequisites
- Docker and Docker Compose installed
- A machine to run Semaphore (a mini PC, VM, or Docker host)
- SSH access to target machines (Semaphore needs SSH keys to run Ansible)
Docker Compose Setup
Create a project directory:
mkdir -p ~/semaphore
cd ~/semaphore
Create docker-compose.yml:
version: '3'
services:
semaphore:
image: semaphoreui/semaphore:latest
container_name: semaphore
restart: unless-stopped
ports:
- "3000:3000"
environment:
SEMAPHORE_DB_DIALECT: bolt # Use BoltDB (file-based, no separate DB needed)
SEMAPHORE_ADMIN_PASSWORD: changeme # Change this!
SEMAPHORE_ADMIN_NAME: admin
SEMAPHORE_ADMIN_EMAIL: [email protected]
SEMAPHORE_ADMIN: admin
SEMAPHORE_ACCESS_KEY_ENCRYPTION: "your-32-char-encryption-key-here" # Generate a random key
volumes:
- ./semaphore:/etc/semaphore # Config and database
- ./playbooks:/playbooks # Mount your Ansible playbooks
- ./keys:/keys # SSH keys for Ansible
Generate an encryption key:
openssl rand -hex 16
Replace SEMAPHORE_ACCESS_KEY_ENCRYPTION with the output.
Start Semaphore:
docker-compose up -d
Access Semaphore at http://your-server-ip:3000. Log in with:
- Username:
admin - Password:
changeme(or whatever you set)
Change the admin password immediately after first login (Settings → Users).
Reverse Proxy with Caddy (Optional)
If you want HTTPS and a proper domain:
# Caddyfile
semaphore.homelab.local {
reverse_proxy localhost:3000
}
Or use Nginx, Traefik, or Cloudflare Tunnel.
Like what you're reading? Subscribe to HomeLab Starter — free weekly guides in your inbox.
Initial Configuration
Once logged in, you'll configure:
- Key Store: SSH keys for Ansible to connect to target hosts
- Repositories: Git repos or local directories with playbooks
- Inventory: Ansible inventory files
- Environment: Variables and Vault passwords
- Task Templates: Playbook configurations
1. Add an SSH Key
Go to Key Store → New Key.
- Name:
homelab-ssh-key - Type: SSH Key
- Key: Paste your private SSH key (the one you use for
ansible_useron target hosts)
If you don't have a dedicated Ansible key:
ssh-keygen -t ed25519 -f ~/.ssh/ansible -C "ansible@semaphore"
ssh-copy-id -i ~/.ssh/ansible user@target-host
Upload the private key (~/.ssh/ansible) to Semaphore.
2. Add a Repository
This is where your Ansible playbooks live. You can use a Git repo or mount a local directory.
Option A: Git Repository
Go to Repositories → New Repository.
- Name:
homelab-ansible - URL:
https://github.com/yourusername/homelab-ansible.git - Branch:
main - Access Key: (None if public repo, or add a Git SSH key if private)
Option B: Local Directory
In docker-compose.yml, you already mounted /playbooks. Put your Ansible project there:
cp -r ~/homelab-ansible/* ~/semaphore/playbooks/
In Semaphore:
- Name:
homelab-ansible - URL:
file:///playbooks
3. Add an Inventory
Go to Inventory → New Inventory.
- Name:
homelab-hosts - Inventory: Paste your Ansible inventory (YAML or INI format)
Example (YAML):
all:
children:
servers:
hosts:
proxmox:
ansible_host: 192.168.1.10
ansible_user: root
nas:
ansible_host: 192.168.1.50
ansible_user: admin
pis:
hosts:
pi-vpn:
ansible_host: 192.168.1.61
ansible_user: pi
Or you can reference an inventory file from your repository.
4. Add an Environment (Optional)
If you use Ansible Vault or extra vars:
Go to Environment → New Environment.
- Name:
production - Extra Variables: (YAML key-value pairs)
- Vault Password: (If using Ansible Vault)
Example extra vars:
timezone: America/Los_Angeles
ntp_servers:
- 0.pool.ntp.org
- 1.pool.ntp.org
Creating a Task Template
Task Templates define how to run a playbook.
Go to Task Templates → New Template.
Example: Weekly System Updates
- Name:
update-all-systems - Playbook:
update-all.yml(from your repository) - Inventory:
homelab-hosts - Repository:
homelab-ansible - Environment:
production(or None) - Vault Password: (Select if needed)
- SSH Key:
homelab-ssh-key
Survey variables (optional): If your playbook accepts variables (e.g., --extra-vars "reboot=yes"), you can define a form here. Users can check a box to enable reboots when running the template.
Running a Playbook
Once a task template is created:
- Go to Task Templates
- Click the Run button next to your template
- Semaphore executes the playbook in the background
- Click the task in Task Queue to see live output
Output looks like standard Ansible output, color-coded with success/failure.
Scheduling Playbooks
Go to your task template → Schedules → New Schedule.
- Cron Expression:
0 2 * * 0(every Sunday at 2 AM) - Template:
update-all-systems
Common cron patterns:
0 2 * * *— Daily at 2 AM0 2 * * 0— Weekly on Sunday at 2 AM0 3 1 * *— Monthly on the 1st at 3 AM
Semaphore will automatically run the playbook on schedule.
Use Cases for Home Labs
1. Scheduled System Updates
Create a playbook update-all.yml:
---
- name: Update all Debian/Ubuntu hosts
hosts: all
become: true
tasks:
- name: Update apt cache
apt:
update_cache: true
cache_valid_time: 3600
- name: Upgrade packages
apt:
upgrade: dist
- name: Autoremove
apt:
autoremove: true
- name: Check if reboot required
stat:
path: /var/run/reboot-required
register: reboot_required
- name: Reboot if needed
reboot:
when: reboot_required.stat.exists
Schedule it to run every Sunday at 2 AM. Your entire homelab stays updated automatically.
2. Backup Automation
Playbook backup.yml:
---
- name: Backup critical data
hosts: nas
tasks:
- name: Run Restic backup
command: restic backup /data --repo /mnt/backups/restic
environment:
RESTIC_PASSWORD: "{{ vault_restic_password }}"
Schedule nightly. Semaphore logs the output, so you can verify backups succeeded.
3. Deploy Docker Stacks
Playbook deploy-monitoring.yml:
---
- name: Deploy Prometheus monitoring stack
hosts: pi-monitor
become: true
tasks:
- name: Copy docker-compose file
copy:
src: files/monitoring-compose.yml
dest: /opt/monitoring/docker-compose.yml
- name: Start stack
community.docker.docker_compose_v2:
project_src: /opt/monitoring
state: present
Run this from Semaphore whenever you update your monitoring config.
4. Trigger from Webhooks
Use Semaphore's API to trigger playbooks from external events.
Example: Trigger a deployment when you push to a Git repo.
curl -X POST http://semaphore.homelab.local:3000/api/project/1/tasks \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{"template_id": 5}'
Get an API token from Settings → API Tokens.
Multi-User Access and Permissions
Semaphore supports multiple users with role-based access.
Add a User
Go to Settings → Users → New User.
- Username:
family-member - Email:
[email protected] - Password:
temporary-password
Assign Permissions
Go to Settings → Projects → [Your Project] → Team.
Add the user with a role:
- Owner: Full control (edit templates, keys, users)
- Manager: Can run and edit tasks
- Task Runner: Can only run existing templates
- Guest: Read-only
Example: Give a family member "Task Runner" access. They can click "Run" on the "update-all-systems" template but can't see SSH keys or modify playbooks.
LDAP Integration (Optional)
Semaphore supports LDAP for centralized authentication. If you run an LDAP server (OpenLDAP, FreeIPA), you can integrate it:
Settings → LDAP → Enable LDAP.
Configuration (example):
LDAP Server: ldap://192.168.1.100:389
Bind DN: cn=admin,dc=homelab,dc=local
Bind Password: your-ldap-password
Search Base: ou=users,dc=homelab,dc=local
Username Attribute: uid
Comparison to AWX
Semaphore is simpler and lighter:
- One Docker container (or a few with PostgreSQL)
- BoltDB or PostgreSQL backend
- Minimal resource usage (~200MB RAM)
- 15-minute setup
AWX is more powerful but complex:
- Requires Kubernetes (or complicated Docker setup)
- PostgreSQL + Redis + multiple AWX containers
- ~2GB+ RAM
- Multi-hour setup
- Advanced features: workflows, dynamic inventories, job slicing, surveys
When to use AWX over Semaphore:
- You need dynamic inventories (cloud APIs, VMware vCenter)
- You need workflow chaining (run playbook A, then B, then C conditionally)
- You're already invested in Red Hat ecosystem
For 95% of home labs, Semaphore is the better choice.
Troubleshooting
Playbook fails with "Permission denied (publickey)"
Semaphore can't SSH to target hosts. Check:
- SSH key is uploaded to Key Store
- The key is the correct private key (not public)
- The public key is in
~/.ssh/authorized_keyson target hosts ansible_userin inventory matches the user with the authorized key
Test manually:
docker exec -it semaphore ssh -i /keys/ansible [email protected]
Playbook runs but tasks fail with "sudo: a password is required"
Your ansible_user doesn't have passwordless sudo. Fix:
# On target host
echo "ansible_user ALL=(ALL) NOPASSWD:ALL" | sudo tee /etc/sudoers.d/ansible
Or add ansible_become_password to your inventory.
Semaphore can't find playbook
Check:
- Repository path is correct (Git URL or local path)
- Playbook name matches exactly (case-sensitive)
- If using Git, ensure the branch is correct
View repository contents:
Go to Repositories → [Your Repo] → Browse.
Can't access Semaphore web UI
Check Docker logs:
docker logs semaphore
Verify the container is running:
docker ps | grep semaphore
Check port binding:
curl http://localhost:3000
If using a reverse proxy, check proxy logs.
Best Practices
Use Git for playbooks: Store playbooks in version control. Semaphore pulls from Git, so you have history and rollback.
Secrets in Ansible Vault: Don't put passwords in plain text in playbooks. Use Ansible Vault and store the vault password in Semaphore's Environment settings.
Test playbooks in CLI first: Before adding a playbook to Semaphore, run it manually via ansible-playbook to debug. Semaphore just wraps Ansible; it doesn't change behavior.
Schedule carefully: Don't schedule heavy playbooks (OS upgrades, reboots) during business hours. Use off-peak times (2-4 AM).
Monitor task history: Periodically review Task History to catch failures. Set up notifications (webhook to Discord/Slack) for failed tasks.
Limit task concurrency: Semaphore can run multiple tasks in parallel. If you have limited resources, set Max Parallel Tasks in project settings.
Notifications and Alerts
Semaphore can send notifications when tasks succeed/fail.
Go to Project Settings → Integrations.
Webhook (send to Discord, Slack, or custom endpoint):
Example Discord webhook payload:
{
"content": "Playbook **{{ .alias }}** {{ if eq .status \"success\" }}succeeded{{ else }}failed{{ end }}!"
}
Or use email notifications (requires SMTP configuration).
Conclusion
Ansible Semaphore turns Ansible from a CLI tool into a fully-fledged automation platform. You get scheduled runs, a web UI, multi-user access, and task history — all without the complexity of AWX.
For home labs, it's the perfect middle ground: more powerful than raw Ansible CLI, simpler than enterprise tools. Install it via Docker Compose, load your existing playbooks, and start scheduling automation.
Your home lab will thank you when weekly updates, backups, and deployments happen automatically — and you have logs to prove it.
