{"id":600,"date":"2024-03-27T10:00:00","date_gmt":"2024-03-27T10:00:00","guid":{"rendered":"https:\/\/jacar.es\/semaphore-ansible-ui\/"},"modified":"2024-03-27T10:00:00","modified_gmt":"2024-03-27T10:00:00","slug":"semaphore-ansible-ui","status":"publish","type":"post","link":"https:\/\/jacar.es\/en\/semaphore-ansible-ui\/","title":{"rendered":"Semaphore: Ansible UI When the Team Grows"},"content":{"rendered":"<p><strong><a href=\"https:\/\/semaphoreui.com\/\">Semaphore<\/a><\/strong> (or <strong>Semaphore UI<\/strong>) is the open-source web interface for running Ansible playbooks. Simple, lightweight, self-hostable. Born as a pragmatic alternative to <strong>AWX<\/strong> (upstream open-source of Ansible Tower \/ Red Hat Ansible Automation Platform) \u2014 fewer features, but dramatically simpler to operate. For mid-size teams that have outgrown \u201crun from laptop\u201d but don\u2019t need AWX complexity, it\u2019s the sensible choice.<\/p>\n<h2 id=\"what-semaphore-solves\">What Semaphore Solves<\/h2>\n<p>Problems arising as teams grow:<\/p>\n<ul>\n<li><strong>Audit<\/strong>: who ran which playbook when against which hosts?<\/li>\n<li><strong>Permissions<\/strong>: which users can run which playbooks against which inventory?<\/li>\n<li><strong>History<\/strong>: what output did that execution a week ago produce?<\/li>\n<li><strong>Schedules<\/strong>: periodic playbooks without dedicating a cron host.<\/li>\n<li><strong>Centralised secrets<\/strong>: vault keys, SSH keys, without distributing across laptops.<\/li>\n<\/ul>\n<p>Without a central UI, all this becomes ad-hoc and fragile.<\/p>\n<h2 id=\"architecture\">Architecture<\/h2>\n<p>Minimum components:<\/p>\n<ul>\n<li><strong>Semaphore server<\/strong> (Go, single binary).<\/li>\n<li><strong>Database<\/strong>: MySQL\/MariaDB, PostgreSQL, or embedded BoltDB.<\/li>\n<li><strong>Ansible<\/strong> available on the server or container.<\/li>\n<\/ul>\n<p>No distributed workers or complex queues. For teams with &lt;100 simultaneous runs, enough.<\/p>\n<h2 id=\"docker-install\">Docker Install<\/h2>\n<div class=\"sourceCode\" id=\"cb1\">\n<pre class=\"sourceCode yaml\"><code class=\"sourceCode yaml\"><span id=\"cb1-1\"><a href=\"#cb1-1\" aria-hidden=\"true\" tabindex=\"-1\"><\/a><span class=\"fu\">version<\/span><span class=\"kw\">:<\/span><span class=\"at\"> <\/span><span class=\"st\">&quot;3.8&quot;<\/span><\/span>\n<span id=\"cb1-2\"><a href=\"#cb1-2\" aria-hidden=\"true\" tabindex=\"-1\"><\/a><span class=\"fu\">services<\/span><span class=\"kw\">:<\/span><\/span>\n<span id=\"cb1-3\"><a href=\"#cb1-3\" aria-hidden=\"true\" tabindex=\"-1\"><\/a><span class=\"at\">  <\/span><span class=\"fu\">semaphore<\/span><span class=\"kw\">:<\/span><\/span>\n<span id=\"cb1-4\"><a href=\"#cb1-4\" aria-hidden=\"true\" tabindex=\"-1\"><\/a><span class=\"at\">    <\/span><span class=\"fu\">image<\/span><span class=\"kw\">:<\/span><span class=\"at\"> semaphoreui\/semaphore:latest<\/span><\/span>\n<span id=\"cb1-5\"><a href=\"#cb1-5\" aria-hidden=\"true\" tabindex=\"-1\"><\/a><span class=\"at\">    <\/span><span class=\"fu\">ports<\/span><span class=\"kw\">:<\/span><\/span>\n<span id=\"cb1-6\"><a href=\"#cb1-6\" aria-hidden=\"true\" tabindex=\"-1\"><\/a><span class=\"at\">      <\/span><span class=\"kw\">-<\/span><span class=\"at\"> <\/span><span class=\"st\">&quot;3000:3000&quot;<\/span><\/span>\n<span id=\"cb1-7\"><a href=\"#cb1-7\" aria-hidden=\"true\" tabindex=\"-1\"><\/a><span class=\"at\">    <\/span><span class=\"fu\">environment<\/span><span class=\"kw\">:<\/span><\/span>\n<span id=\"cb1-8\"><a href=\"#cb1-8\" aria-hidden=\"true\" tabindex=\"-1\"><\/a><span class=\"at\">      <\/span><span class=\"fu\">SEMAPHORE_DB_DIALECT<\/span><span class=\"kw\">:<\/span><span class=\"at\"> postgres<\/span><\/span>\n<span id=\"cb1-9\"><a href=\"#cb1-9\" aria-hidden=\"true\" tabindex=\"-1\"><\/a><span class=\"at\">      <\/span><span class=\"fu\">SEMAPHORE_DB_HOST<\/span><span class=\"kw\">:<\/span><span class=\"at\"> postgres<\/span><\/span>\n<span id=\"cb1-10\"><a href=\"#cb1-10\" aria-hidden=\"true\" tabindex=\"-1\"><\/a><span class=\"at\">      <\/span><span class=\"fu\">SEMAPHORE_DB_USER<\/span><span class=\"kw\">:<\/span><span class=\"at\"> semaphore<\/span><\/span>\n<span id=\"cb1-11\"><a href=\"#cb1-11\" aria-hidden=\"true\" tabindex=\"-1\"><\/a><span class=\"at\">      <\/span><span class=\"fu\">SEMAPHORE_DB_PASS<\/span><span class=\"kw\">:<\/span><span class=\"at\"> ${DB_PASS}<\/span><\/span>\n<span id=\"cb1-12\"><a href=\"#cb1-12\" aria-hidden=\"true\" tabindex=\"-1\"><\/a><span class=\"at\">      <\/span><span class=\"fu\">SEMAPHORE_DB<\/span><span class=\"kw\">:<\/span><span class=\"at\"> semaphore<\/span><\/span>\n<span id=\"cb1-13\"><a href=\"#cb1-13\" aria-hidden=\"true\" tabindex=\"-1\"><\/a><span class=\"at\">      <\/span><span class=\"fu\">SEMAPHORE_PLAYBOOK_PATH<\/span><span class=\"kw\">:<\/span><span class=\"at\"> \/tmp\/semaphore<\/span><\/span>\n<span id=\"cb1-14\"><a href=\"#cb1-14\" aria-hidden=\"true\" tabindex=\"-1\"><\/a><span class=\"at\">      <\/span><span class=\"fu\">SEMAPHORE_ADMIN_PASSWORD<\/span><span class=\"kw\">:<\/span><span class=\"at\"> ${ADMIN_PASS}<\/span><\/span>\n<span id=\"cb1-15\"><a href=\"#cb1-15\" aria-hidden=\"true\" tabindex=\"-1\"><\/a><span class=\"at\">      <\/span><span class=\"fu\">SEMAPHORE_ADMIN_NAME<\/span><span class=\"kw\">:<\/span><span class=\"at\"> admin<\/span><\/span>\n<span id=\"cb1-16\"><a href=\"#cb1-16\" aria-hidden=\"true\" tabindex=\"-1\"><\/a><span class=\"at\">      <\/span><span class=\"fu\">SEMAPHORE_ADMIN_EMAIL<\/span><span class=\"kw\">:<\/span><span class=\"at\"> admin@example.com<\/span><\/span>\n<span id=\"cb1-17\"><a href=\"#cb1-17\" aria-hidden=\"true\" tabindex=\"-1\"><\/a><span class=\"at\">    <\/span><span class=\"fu\">volumes<\/span><span class=\"kw\">:<\/span><\/span>\n<span id=\"cb1-18\"><a href=\"#cb1-18\" aria-hidden=\"true\" tabindex=\"-1\"><\/a><span class=\"at\">      <\/span><span class=\"kw\">-<\/span><span class=\"at\"> semaphore_data:\/etc\/semaphore<\/span><\/span>\n<span id=\"cb1-19\"><a href=\"#cb1-19\" aria-hidden=\"true\" tabindex=\"-1\"><\/a><span class=\"at\">      <\/span><span class=\"kw\">-<\/span><span class=\"at\"> semaphore_tmp:\/tmp\/semaphore<\/span><\/span>\n<span id=\"cb1-20\"><a href=\"#cb1-20\" aria-hidden=\"true\" tabindex=\"-1\"><\/a><span class=\"at\">    <\/span><span class=\"fu\">depends_on<\/span><span class=\"kw\">:<\/span><\/span>\n<span id=\"cb1-21\"><a href=\"#cb1-21\" aria-hidden=\"true\" tabindex=\"-1\"><\/a><span class=\"at\">      <\/span><span class=\"kw\">-<\/span><span class=\"at\"> postgres<\/span><\/span>\n<span id=\"cb1-22\"><a href=\"#cb1-22\" aria-hidden=\"true\" tabindex=\"-1\"><\/a><\/span>\n<span id=\"cb1-23\"><a href=\"#cb1-23\" aria-hidden=\"true\" tabindex=\"-1\"><\/a><span class=\"at\">  <\/span><span class=\"fu\">postgres<\/span><span class=\"kw\">:<\/span><\/span>\n<span id=\"cb1-24\"><a href=\"#cb1-24\" aria-hidden=\"true\" tabindex=\"-1\"><\/a><span class=\"at\">    <\/span><span class=\"fu\">image<\/span><span class=\"kw\">:<\/span><span class=\"at\"> postgres:16<\/span><\/span>\n<span id=\"cb1-25\"><a href=\"#cb1-25\" aria-hidden=\"true\" tabindex=\"-1\"><\/a><span class=\"at\">    <\/span><span class=\"fu\">environment<\/span><span class=\"kw\">:<\/span><\/span>\n<span id=\"cb1-26\"><a href=\"#cb1-26\" aria-hidden=\"true\" tabindex=\"-1\"><\/a><span class=\"at\">      <\/span><span class=\"fu\">POSTGRES_USER<\/span><span class=\"kw\">:<\/span><span class=\"at\"> semaphore<\/span><\/span>\n<span id=\"cb1-27\"><a href=\"#cb1-27\" aria-hidden=\"true\" tabindex=\"-1\"><\/a><span class=\"at\">      <\/span><span class=\"fu\">POSTGRES_PASSWORD<\/span><span class=\"kw\">:<\/span><span class=\"at\"> ${DB_PASS}<\/span><\/span>\n<span id=\"cb1-28\"><a href=\"#cb1-28\" aria-hidden=\"true\" tabindex=\"-1\"><\/a><span class=\"at\">      <\/span><span class=\"fu\">POSTGRES_DB<\/span><span class=\"kw\">:<\/span><span class=\"at\"> semaphore<\/span><\/span>\n<span id=\"cb1-29\"><a href=\"#cb1-29\" aria-hidden=\"true\" tabindex=\"-1\"><\/a><span class=\"at\">    <\/span><span class=\"fu\">volumes<\/span><span class=\"kw\">:<\/span><\/span>\n<span id=\"cb1-30\"><a href=\"#cb1-30\" aria-hidden=\"true\" tabindex=\"-1\"><\/a><span class=\"at\">      <\/span><span class=\"kw\">-<\/span><span class=\"at\"> postgres_data:\/var\/lib\/postgresql\/data<\/span><\/span>\n<span id=\"cb1-31\"><a href=\"#cb1-31\" aria-hidden=\"true\" tabindex=\"-1\"><\/a><\/span>\n<span id=\"cb1-32\"><a href=\"#cb1-32\" aria-hidden=\"true\" tabindex=\"-1\"><\/a><span class=\"fu\">volumes<\/span><span class=\"kw\">:<\/span><\/span>\n<span id=\"cb1-33\"><a href=\"#cb1-33\" aria-hidden=\"true\" tabindex=\"-1\"><\/a><span class=\"at\">  <\/span><span class=\"fu\">semaphore_data<\/span><span class=\"kw\">:<\/span><\/span>\n<span id=\"cb1-34\"><a href=\"#cb1-34\" aria-hidden=\"true\" tabindex=\"-1\"><\/a><span class=\"at\">  <\/span><span class=\"fu\">semaphore_tmp<\/span><span class=\"kw\">:<\/span><\/span>\n<span id=\"cb1-35\"><a href=\"#cb1-35\" aria-hidden=\"true\" tabindex=\"-1\"><\/a><span class=\"at\">  <\/span><span class=\"fu\">postgres_data<\/span><span class=\"kw\">:<\/span><\/span><\/code><\/pre>\n<\/div>\n<p>Start and log into <code>http:\/\/localhost:3000<\/code> as admin.<\/p>\n<h2 id=\"key-concepts\">Key Concepts<\/h2>\n<p><strong>Project<\/strong>: isolated space with its inventory, keys, templates.<\/p>\n<p><strong>Inventory<\/strong>: list of hosts. Can be static (direct list) or dynamic (script, AWS, etc).<\/p>\n<p><strong>Key Store<\/strong>: SSH keys, passwords, vault passwords. Used when running playbooks.<\/p>\n<p><strong>Repository<\/strong>: Git repo where your playbooks live. Semaphore pulls and executes.<\/p>\n<p><strong>Task Template<\/strong>: associates a playbook + inventory + keys. This is what runs.<\/p>\n<p><strong>Schedule<\/strong>: a template that runs on cron.<\/p>\n<h2 id=\"typical-flow\">Typical Flow<\/h2>\n<ol type=\"1\">\n<li>Your team has a Git repo with Ansible playbooks.<\/li>\n<li>Create project in Semaphore, pointing at the repo.<\/li>\n<li>Define inventory (production, staging, etc).<\/li>\n<li>Load SSH key with host access.<\/li>\n<li>Create templates: \u201cdeploy web service\u201d, \u201crotate certs\u201d, \u201crestart postgres\u201d.<\/li>\n<li>Team members run templates from UI, with live logs.<\/li>\n<\/ol>\n<p>All with permissions: admin can everything, others only what you assign.<\/p>\n<h2 id=\"permissions-and-rbac\">Permissions and RBAC<\/h2>\n<p>Semaphore has:<\/p>\n<ul>\n<li><strong>Global admin<\/strong>: manage users, settings.<\/li>\n<li><strong>Project owner<\/strong>: manage their project.<\/li>\n<li><strong>Manager<\/strong>: can run + edit templates.<\/li>\n<li><strong>Task runner<\/strong>: only run existing templates.<\/li>\n<li><strong>Guest<\/strong>: read-only.<\/li>\n<\/ul>\n<p>For teams with clear dev\/ops separation, this covers. For complex multi-tenancy, AWX has more granularity.<\/p>\n<h2 id=\"cicd-integration\">CI\/CD Integration<\/h2>\n<p>Semaphore exposes REST API. Common patterns:<\/p>\n<ul>\n<li><strong>Gitea \/ GitHub Actions<\/strong> calls Semaphore API after PR merge.<\/li>\n<li><strong>Repo webhook<\/strong> to Semaphore for dynamic-inventory rebuild.<\/li>\n<li><strong>ChatOps<\/strong>: Slack bot running templates via API.<\/li>\n<li><strong>Monitoring<\/strong>: alerts trigger remediation templates.<\/li>\n<\/ul>\n<p>Example curl:<\/p>\n<div class=\"sourceCode\" id=\"cb2\">\n<pre class=\"sourceCode bash\"><code class=\"sourceCode bash\"><span id=\"cb2-1\"><a href=\"#cb2-1\" aria-hidden=\"true\" tabindex=\"-1\"><\/a><span class=\"ex\">curl<\/span> <span class=\"at\">-X<\/span> POST https:\/\/semaphore.example.com\/api\/project\/1\/tasks <span class=\"dt\">\\<\/span><\/span>\n<span id=\"cb2-2\"><a href=\"#cb2-2\" aria-hidden=\"true\" tabindex=\"-1\"><\/a>  <span class=\"at\">-H<\/span> <span class=\"st\">&quot;Cookie: semaphore=...&quot;<\/span> <span class=\"dt\">\\<\/span><\/span>\n<span id=\"cb2-3\"><a href=\"#cb2-3\" aria-hidden=\"true\" tabindex=\"-1\"><\/a>  <span class=\"at\">-d<\/span> <span class=\"st\">&#39;{&quot;template_id&quot;: 5, &quot;debug&quot;: false}&#39;<\/span><\/span><\/code><\/pre>\n<\/div>\n<h2 id=\"semaphore-vs-awx\">Semaphore vs AWX<\/h2>\n<table>\n<colgroup>\n<col style=\"width: 33%\" \/>\n<col style=\"width: 33%\" \/>\n<col style=\"width: 33%\" \/>\n<\/colgroup>\n<thead>\n<tr class=\"header\">\n<th>Aspect<\/th>\n<th>Semaphore<\/th>\n<th>AWX<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr class=\"odd\">\n<td>Deploy complexity<\/td>\n<td>Simple (Docker)<\/td>\n<td>Complex (Kubernetes recommended)<\/td>\n<\/tr>\n<tr class=\"even\">\n<td>Database<\/td>\n<td>Simple PostgreSQL<\/td>\n<td>PostgreSQL + Redis<\/td>\n<\/tr>\n<tr class=\"odd\">\n<td>RBAC<\/td>\n<td>Basic-medium<\/td>\n<td>Advanced<\/td>\n<\/tr>\n<tr class=\"even\">\n<td>Custom collections<\/td>\n<td>Yes<\/td>\n<td>Yes<\/td>\n<\/tr>\n<tr class=\"odd\">\n<td>Workflows<\/td>\n<td>Limited<\/td>\n<td>Advanced (graph)<\/td>\n<\/tr>\n<tr class=\"even\">\n<td>Notifications<\/td>\n<td>Basic<\/td>\n<td>Advanced<\/td>\n<\/tr>\n<tr class=\"odd\">\n<td>Commercial support<\/td>\n<td>\u2014<\/td>\n<td>Yes (Red Hat)<\/td>\n<\/tr>\n<tr class=\"even\">\n<td>Resource consumption<\/td>\n<td>Low (~500MB RAM)<\/td>\n<td>High (~4GB RAM)<\/td>\n<\/tr>\n<tr class=\"odd\">\n<td>Learning curve<\/td>\n<td>Low<\/td>\n<td>Medium-high<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Semaphore for teams &lt;50 with moderate needs. AWX for large teams with complex requirements.<\/p>\n<h2 id=\"where-it-falls-short\">Where It Falls Short<\/h2>\n<p>Honestly:<\/p>\n<ul>\n<li><strong>Complex multi-step workflows<\/strong>: AWX does better.<\/li>\n<li><strong>Enterprise SSO with complex SAML<\/strong>: Semaphore has basic OIDC.<\/li>\n<li><strong>Multi-organisation<\/strong>: Semaphore has \u201cprojects\u201d, AWX has orgs.<\/li>\n<li><strong>Horizontal scaling<\/strong>: Semaphore runs on one node; AWX distributes.<\/li>\n<li><strong>Fine-grained metrics<\/strong>: AWX has more built-in observability.<\/li>\n<\/ul>\n<h2 id=\"real-cases\">Real Cases<\/h2>\n<p>Patterns we see:<\/p>\n<ul>\n<li><strong>20-50 admin company<\/strong>: Semaphore as centralised runner.<\/li>\n<li><strong>MSP managing 100 clients<\/strong>: one project per client in Semaphore.<\/li>\n<li><strong>Platform engineering team<\/strong>: self-service for dev teams via pre-approved templates.<\/li>\n<li><strong>Compliance<\/strong>: audit log to show who did what when.<\/li>\n<\/ul>\n<h2 id=\"security\">Security<\/h2>\n<p>Operational checklist:<\/p>\n<ul>\n<li><strong>Mandatory HTTPS<\/strong> via reverse proxy (Traefik, Nginx).<\/li>\n<li><strong>Integrated auth<\/strong> with OIDC or LDAP if available.<\/li>\n<li><strong>SSH keys with passphrase<\/strong> or Vault for secrets.<\/li>\n<li><strong>Regular backup<\/strong> of data volume + DB dump.<\/li>\n<li><strong>Monitor<\/strong> failed login attempts.<\/li>\n<li><strong>Update<\/strong> versions \u2014 read changelog.<\/li>\n<\/ul>\n<h2 id=\"hashicorp-vault-integration\">HashiCorp Vault Integration<\/h2>\n<p>Semaphore can query Vault secrets at runtime:<\/p>\n<div class=\"sourceCode\" id=\"cb3\">\n<pre class=\"sourceCode yaml\"><code class=\"sourceCode yaml\"><span id=\"cb3-1\"><a href=\"#cb3-1\" aria-hidden=\"true\" tabindex=\"-1\"><\/a><span class=\"kw\">-<\/span><span class=\"at\"> <\/span><span class=\"fu\">name<\/span><span class=\"kw\">:<\/span><span class=\"at\"> fetch secret<\/span><\/span>\n<span id=\"cb3-2\"><a href=\"#cb3-2\" aria-hidden=\"true\" tabindex=\"-1\"><\/a><span class=\"at\">  <\/span><span class=\"fu\">set_fact<\/span><span class=\"kw\">:<\/span><\/span>\n<span id=\"cb3-3\"><a href=\"#cb3-3\" aria-hidden=\"true\" tabindex=\"-1\"><\/a><span class=\"at\">    <\/span><span class=\"fu\">api_key<\/span><span class=\"kw\">:<\/span><span class=\"at\"> <\/span><span class=\"st\">&quot;{{ lookup(&#39;hashi_vault&#39;, &#39;secret=secret\/data\/api token=VAULT_TOKEN&#39;) }}&quot;<\/span><\/span><\/code><\/pre>\n<\/div>\n<p>With <code>VAULT_TOKEN<\/code> in Semaphore as env var. Secrets never on disk.<\/p>\n<h2 id=\"conclusion\">Conclusion<\/h2>\n<p>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.<\/p>\n<p>Follow us on jacar.es for more on Ansible, automation, and practical DevOps.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Running playbooks from terminal works for 3 people. With 30 you need audit, permissions, and shared UI. Semaphore solves exactly that.<\/p>\n","protected":false},"author":1,"featured_media":601,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[24],"tags":[411,412,192,118,294,410],"class_list":["post-600","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-herramientas","tag-ansible","tag-automation","tag-ci-cd","tag-devops","tag-self-hosted","tag-semaphore"],"translation":{"provider":"WPGlobus","version":"3.0.2","language":"en","enabled_languages":["es","en"],"languages":{"es":{"title":true,"content":true,"excerpt":true},"en":{"title":true,"content":true,"excerpt":true}}},"gutentor_comment":0,"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.4 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Semaphore: Ansible UI When the Team Grows - Jacar<\/title>\n<meta name=\"description\" content=\"Semaphore UI for Ansible: permissions, audit, schedules, and remote execution. When better than AWX\/Tower for mid-size teams.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/jacar.es\/semaphore-ansible-ui\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Semaphore: Ansible UI When the Team Grows - Jacar\" \/>\n<meta property=\"og:description\" content=\"Semaphore UI for Ansible: permissions, audit, schedules, and remote execution. When better than AWX\/Tower for mid-size teams.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/jacar.es\/semaphore-ansible-ui\/\" \/>\n<meta property=\"og:site_name\" content=\"Jacar\" \/>\n<meta property=\"article:published_time\" content=\"2024-03-27T10:00:00+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/jcs-wp-jacar-es.fsn1.your-objectstorage.com\/wp-content\/uploads\/2020\/09\/favicon.png\" \/>\n\t<meta property=\"og:image:width\" content=\"252\" \/>\n\t<meta property=\"og:image:height\" content=\"229\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"javi\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"javi\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"8 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/jacar.es\\\/semaphore-ansible-ui\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/jacar.es\\\/semaphore-ansible-ui\\\/\"},\"author\":{\"name\":\"javi\",\"@id\":\"https:\\\/\\\/jacar.es\\\/#\\\/schema\\\/person\\\/54a7f7b4224b38fafc9866eb3e614208\"},\"headline\":\"Semaphore: Ansible UI When the Team Grows\",\"datePublished\":\"2024-03-27T10:00:00+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/jacar.es\\\/semaphore-ansible-ui\\\/\"},\"wordCount\":1414,\"publisher\":{\"@id\":\"https:\\\/\\\/jacar.es\\\/#organization\"},\"image\":{\"@id\":\"https:\\\/\\\/jacar.es\\\/semaphore-ansible-ui\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/jcs-wp-jacar-es.fsn1.your-objectstorage.com\\\/wp-content\\\/uploads\\\/2024\\\/03\\\/20034208\\\/jwp-1529221-15888.jpg\",\"keywords\":[\"ansible\",\"automation\",\"ci cd\",\"devops\",\"self-hosted\",\"semaphore\"],\"articleSection\":[\"Herramientas\"],\"inLanguage\":\"en-US\"},{\"@type\":[\"WebPage\",\"ItemPage\"],\"@id\":\"https:\\\/\\\/jacar.es\\\/semaphore-ansible-ui\\\/\",\"url\":\"https:\\\/\\\/jacar.es\\\/semaphore-ansible-ui\\\/\",\"name\":\"Semaphore: Ansible UI When the Team Grows - Jacar\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/jacar.es\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/jacar.es\\\/semaphore-ansible-ui\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/jacar.es\\\/semaphore-ansible-ui\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/jcs-wp-jacar-es.fsn1.your-objectstorage.com\\\/wp-content\\\/uploads\\\/2024\\\/03\\\/20034208\\\/jwp-1529221-15888.jpg\",\"datePublished\":\"2024-03-27T10:00:00+00:00\",\"description\":\"Semaphore UI for Ansible: permissions, audit, schedules, and remote execution. When better than AWX\\\/Tower for mid-size teams.\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/jacar.es\\\/semaphore-ansible-ui\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/jacar.es\\\/semaphore-ansible-ui\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/jacar.es\\\/semaphore-ansible-ui\\\/#primaryimage\",\"url\":\"https:\\\/\\\/jcs-wp-jacar-es.fsn1.your-objectstorage.com\\\/wp-content\\\/uploads\\\/2024\\\/03\\\/20034208\\\/jwp-1529221-15888.jpg\",\"contentUrl\":\"https:\\\/\\\/jcs-wp-jacar-es.fsn1.your-objectstorage.com\\\/wp-content\\\/uploads\\\/2024\\\/03\\\/20034208\\\/jwp-1529221-15888.jpg\",\"width\":1200,\"height\":801,\"caption\":\"Panel de control con switches e indicadores LED representando automatizaci\u00f3n de operaciones\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/jacar.es\\\/semaphore-ansible-ui\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Portada\",\"item\":\"https:\\\/\\\/jacar.es\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Semaphore: UI para Ansible cuando el equipo crece\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/jacar.es\\\/#website\",\"url\":\"https:\\\/\\\/jacar.es\\\/\",\"name\":\"Jacar\",\"description\":\"Passion for Technology\",\"publisher\":{\"@id\":\"https:\\\/\\\/jacar.es\\\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/jacar.es\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/jacar.es\\\/#organization\",\"name\":\"Jacar\",\"url\":\"https:\\\/\\\/jacar.es\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/jacar.es\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"https:\\\/\\\/jacar.es\\\/wp-content\\\/uploads\\\/2020\\\/09\\\/favicon.png\",\"contentUrl\":\"https:\\\/\\\/jacar.es\\\/wp-content\\\/uploads\\\/2020\\\/09\\\/favicon.png\",\"width\":252,\"height\":229,\"caption\":\"Jacar\"},\"image\":{\"@id\":\"https:\\\/\\\/jacar.es\\\/#\\\/schema\\\/logo\\\/image\\\/\"},\"sameAs\":[\"https:\\\/\\\/www.linkedin.com\\\/in\\\/javiercanetearroyo\\\/\"]},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/jacar.es\\\/#\\\/schema\\\/person\\\/54a7f7b4224b38fafc9866eb3e614208\",\"name\":\"javi\",\"sameAs\":[\"https:\\\/\\\/jacar.es\"],\"url\":\"https:\\\/\\\/jacar.es\\\/en\\\/author\\\/javi\\\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Semaphore: Ansible UI When the Team Grows - Jacar","description":"Semaphore UI for Ansible: permissions, audit, schedules, and remote execution. When better than AWX\/Tower for mid-size teams.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/jacar.es\/semaphore-ansible-ui\/","og_locale":"en_US","og_type":"article","og_title":"Semaphore: Ansible UI When the Team Grows - Jacar","og_description":"Semaphore UI for Ansible: permissions, audit, schedules, and remote execution. When better than AWX\/Tower for mid-size teams.","og_url":"https:\/\/jacar.es\/semaphore-ansible-ui\/","og_site_name":"Jacar","article_published_time":"2024-03-27T10:00:00+00:00","og_image":[{"width":252,"height":229,"url":"https:\/\/jcs-wp-jacar-es.fsn1.your-objectstorage.com\/wp-content\/uploads\/2020\/09\/favicon.png","type":"image\/png"}],"author":"javi","twitter_card":"summary_large_image","twitter_misc":{"Written by":"javi","Est. reading time":"8 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/jacar.es\/semaphore-ansible-ui\/#article","isPartOf":{"@id":"https:\/\/jacar.es\/semaphore-ansible-ui\/"},"author":{"name":"javi","@id":"https:\/\/jacar.es\/#\/schema\/person\/54a7f7b4224b38fafc9866eb3e614208"},"headline":"Semaphore: Ansible UI When the Team Grows","datePublished":"2024-03-27T10:00:00+00:00","mainEntityOfPage":{"@id":"https:\/\/jacar.es\/semaphore-ansible-ui\/"},"wordCount":1414,"publisher":{"@id":"https:\/\/jacar.es\/#organization"},"image":{"@id":"https:\/\/jacar.es\/semaphore-ansible-ui\/#primaryimage"},"thumbnailUrl":"https:\/\/jcs-wp-jacar-es.fsn1.your-objectstorage.com\/wp-content\/uploads\/2024\/03\/20034208\/jwp-1529221-15888.jpg","keywords":["ansible","automation","ci cd","devops","self-hosted","semaphore"],"articleSection":["Herramientas"],"inLanguage":"en-US"},{"@type":["WebPage","ItemPage"],"@id":"https:\/\/jacar.es\/semaphore-ansible-ui\/","url":"https:\/\/jacar.es\/semaphore-ansible-ui\/","name":"Semaphore: Ansible UI When the Team Grows - Jacar","isPartOf":{"@id":"https:\/\/jacar.es\/#website"},"primaryImageOfPage":{"@id":"https:\/\/jacar.es\/semaphore-ansible-ui\/#primaryimage"},"image":{"@id":"https:\/\/jacar.es\/semaphore-ansible-ui\/#primaryimage"},"thumbnailUrl":"https:\/\/jcs-wp-jacar-es.fsn1.your-objectstorage.com\/wp-content\/uploads\/2024\/03\/20034208\/jwp-1529221-15888.jpg","datePublished":"2024-03-27T10:00:00+00:00","description":"Semaphore UI for Ansible: permissions, audit, schedules, and remote execution. When better than AWX\/Tower for mid-size teams.","breadcrumb":{"@id":"https:\/\/jacar.es\/semaphore-ansible-ui\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/jacar.es\/semaphore-ansible-ui\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/jacar.es\/semaphore-ansible-ui\/#primaryimage","url":"https:\/\/jcs-wp-jacar-es.fsn1.your-objectstorage.com\/wp-content\/uploads\/2024\/03\/20034208\/jwp-1529221-15888.jpg","contentUrl":"https:\/\/jcs-wp-jacar-es.fsn1.your-objectstorage.com\/wp-content\/uploads\/2024\/03\/20034208\/jwp-1529221-15888.jpg","width":1200,"height":801,"caption":"Panel de control con switches e indicadores LED representando automatizaci\u00f3n de operaciones"},{"@type":"BreadcrumbList","@id":"https:\/\/jacar.es\/semaphore-ansible-ui\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Portada","item":"https:\/\/jacar.es\/"},{"@type":"ListItem","position":2,"name":"Semaphore: UI para Ansible cuando el equipo crece"}]},{"@type":"WebSite","@id":"https:\/\/jacar.es\/#website","url":"https:\/\/jacar.es\/","name":"Jacar","description":"Passion for Technology","publisher":{"@id":"https:\/\/jacar.es\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/jacar.es\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/jacar.es\/#organization","name":"Jacar","url":"https:\/\/jacar.es\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/jacar.es\/#\/schema\/logo\/image\/","url":"https:\/\/jacar.es\/wp-content\/uploads\/2020\/09\/favicon.png","contentUrl":"https:\/\/jacar.es\/wp-content\/uploads\/2020\/09\/favicon.png","width":252,"height":229,"caption":"Jacar"},"image":{"@id":"https:\/\/jacar.es\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.linkedin.com\/in\/javiercanetearroyo\/"]},{"@type":"Person","@id":"https:\/\/jacar.es\/#\/schema\/person\/54a7f7b4224b38fafc9866eb3e614208","name":"javi","sameAs":["https:\/\/jacar.es"],"url":"https:\/\/jacar.es\/en\/author\/javi\/"}]}},"_links":{"self":[{"href":"https:\/\/jacar.es\/en\/wp-json\/wp\/v2\/posts\/600","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/jacar.es\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/jacar.es\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/jacar.es\/en\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/jacar.es\/en\/wp-json\/wp\/v2\/comments?post=600"}],"version-history":[{"count":0,"href":"https:\/\/jacar.es\/en\/wp-json\/wp\/v2\/posts\/600\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/jacar.es\/en\/wp-json\/wp\/v2\/media\/601"}],"wp:attachment":[{"href":"https:\/\/jacar.es\/en\/wp-json\/wp\/v2\/media?parent=600"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/jacar.es\/en\/wp-json\/wp\/v2\/categories?post=600"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/jacar.es\/en\/wp-json\/wp\/v2\/tags?post=600"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}