--- slug: semaphore-ui-interface-ansible-terraform title: Semaphore UI, une excellente interface pour Ansible et Terraform description: Démonstration de Semaphore UI, une interface web pour exécuter des playbooks Ansible, du code Terraform et bien plus. Installation avec Docker et exemples rapides. date: 2026-02-09 draft: false tags: - semaphore-ui - ansible - terraform - proxmox - docker categories: - homelab --- ## Intro Dans mon homelab, j'aime expérimenter avec des outils comme Ansible et Terraform. L'interface principale est le CLI, que j'adore, mais parfois une jolie interface web est juste agréable. Après avoir configuré mon cluster OPNsense, je voulais un moyen de le tenir à jour selon un calendrier. Pour moi, l'automatisation passe par Ansible, mais comment automatiser et planifier des playbooks ? Au travail j'utilise Red Hat Ansible Automation Platform, qui est excellent, mais overkill pour mon lab. C'est ainsi que j'ai découvert Semaphore UI. Voyons ce qu'il peut faire. --- ## Qu'est‑ce que Semaphore UI [Semaphore UI](https://semaphoreui.com/docs/) est une interface web élégante conçue pour exécuter de l'automatisation avec des outils comme Ansible et Terraform, et même des scripts Bash, Powershell ou Python. Initialement créé sous le nom Ansible Semaphore, une interface web destinée à fournir un front-end simple pour exécuter uniquement des playbooks Ansible. Au fil du temps, la communauté a fait évoluer le projet en une plateforme de contrôle d'automatisation multi‑outils. C'est une application autonome écrite en Go avec des dépendances minimales, capable d'utiliser différents backends de base de données, tels que PostgreSQL, MySQL ou BoltDB. --- ## Installation Semaphore UI prend en charge plusieurs méthodes d'[installation](https://semaphoreui.com/docs/category/installation) : Docker, Kubernetes, gestionnaire de paquets ou simple binaire. J'ai utilisé Docker pour mon installation, vous pouvez voir comment je déploie actuellement des applications dans ce [post]({{< ref "post/16-how-I-deploy-application" >}}) Voici mon fichier `docker-compose.yml` que j'ai configuré en utilisant PostgreSQL : ```yaml services: semaphore: image: semaphoreui/semaphore:v2.16.45 container_name: semaphore_ui environment: - TZ=Europe/Paris - SEMAPHORE_DB_USER=${POSTGRES_USER} - SEMAPHORE_DB_PASS=${POSTGRES_PASSWORD} - SEMAPHORE_DB_HOST=postgres - SEMAPHORE_DB_PORT=5432 - SEMAPHORE_DB_DIALECT=postgres - SEMAPHORE_DB=${POSTGRES_DB} - SEMAPHORE_PLAYBOOK_PATH=/tmp/semaphore/ - SEMAPHORE_ADMIN_PASSWORD=${SEMAPHORE_ADMIN_PASSWORD} - SEMAPHORE_ADMIN_NAME=${SEMAPHORE_ADMIN_NAME} - SEMAPHORE_ADMIN_EMAIL=${SEMAPHORE_ADMIN_EMAIL} - SEMAPHORE_ADMIN=${SEMAPHORE_ADMIN} - SEMAPHORE_ACCESS_KEY_ENCRYPTION=${SEMAPHORE_ACCESS_KEY_ENCRYPTION} - SEMAPHORE_LDAP_ACTIVATED='no' # - SEMAPHORE_LDAP_HOST=dc01.local.example.com # - SEMAPHORE_LDAP_PORT='636' # - SEMAPHORE_LDAP_NEEDTLS='yes' # - SEMAPHORE_LDAP_DN_BIND='uid=bind_user,cn=users,cn=accounts,dc=local,dc=shiftsystems,dc=net' # - SEMAPHORE_LDAP_PASSWORD='ldap_bind_account_password' # - SEMAPHORE_LDAP_DN_SEARCH='dc=local,dc=example,dc=com' # - SEMAPHORE_LDAP_SEARCH_FILTER="(\u0026(uid=%s)(memberOf=cn=ipausers,cn=groups,cn=accounts,dc=local,dc=example,dc=com))" depends_on: - postgres networks: - backend - web labels: - traefik.enable=true - traefik.http.routers.semaphore.rule=Host(`semaphore.vezpi.com`) - traefik.http.routers.semaphore.entrypoints=https - traefik.http.routers.semaphore.tls.certresolver=letsencrypt - traefik.http.services.semaphore.loadbalancer.server.port=3000 restart: unless-stopped postgres: image: postgres:14 hostname: postgres container_name: semaphore_postgres volumes: - /appli/data/semaphore/db:/var/lib/postgresql/data environment: - POSTGRES_USER=${POSTGRES_USER} - POSTGRES_PASSWORD=${POSTGRES_PASSWORD} - POSTGRES_DB=${POSTGRES_DB} networks: - backend restart: unless-stopped networks: backend: web: external: true ``` Pour générer les clés d'accès chiffrées, j'utilise cette commande : ```bash head -c32 /dev/urandom | base64 ``` Avec Semaphore en fonctionnement, faisons rapidement le tour de l'UI et connectons-la à un dépôt. --- ## Discovery Après avoir démarré la stack, je peux atteindre la page de connexion à l'URL :  Pour me connecter, j'utilise les identifiants définis par `SEMAPHORE_ADMIN_NAME`/`SEMAPHORE_ADMIN_PASSWORD`. Au premier accès, Semaphore me demande de créer un projet. J'ai créé le projet Homelab :  La première chose que je veux faire est d'ajouter mon dépôt _homelab_ (vous pouvez trouver son miroir sur Github [ici](https://github.com/Vezpi/homelab)). Dans `Repository`, je clique sur le bouton `New Repository`, et j'ajoute l'URL du repo. Je ne spécifie pas d'identifiants car le dépôt est public :  ℹ️ Avant de continuer, je déploie 3 VM à des fins de test : `sem01`, `sem02` et `sem03`. Je les ai créées avec Terraform via [ce projet](https://github.com/Vezpi/Homelab/tree/main/terraform/projects/semaphore-vms). Pour interagir avec ces VM, je dois configurer des identifiants. Dans le `Key Store`, j'ajoute la première donnée d'identification, une clé SSH pour mon utilisateur :  Ensuite je crée un nouvel `Inventory`. J'utilise le format d'inventaire Ansible (le seul disponible). Je sélectionne la clé SSH créée précédemment et choisis le type `Static`. Dans les champs je renseigne les 3 hôtes créés avec leur FQDN :  ✅ Avec un projet, un repo, des identifiants et un inventaire en place, je peux avancer et tester l'exécution d'un playbook Ansible. --- ## Launching an Ansible playbook Je veux tester quelque chose de simple : installer un serveur web avec une page personnalisée sur ces 3 VM. Je crée le playbook `install_nginx.yml` : ```yaml --- - name: Demo Playbook - Install Nginx and Serve Hostname Page hosts: all become: true tasks: - name: Ensure apt cache is updated ansible.builtin.apt: update_cache: true cache_valid_time: 3600 - name: Install nginx ansible.builtin.apt: name: nginx state: present - name: Create index.html with hostname ansible.builtin.copy: dest: /var/www/html/index.html content: |