DevOps Automation – Ansible+Semaphore is Indispensable!

Semaphore 2.x is in current release and much of the information regarding the install process below is no longer relevant as the package has been significantly refactored. The developers have made it much easier to install: See the install directions here:

I deviated a bit, but got it up and running in less than 5 minutes. Here’s how:

As root:

#cd /usr/bin
#mv semaphore_linux_amd64 semaphore
#chmod a+x semaphore
#semaphore -setup


Note that I already had mysqld running on the server.

As Spire Digital delves deeper in DevOps, I have had the opportunity to test drive a number of automation technologies – Puppet and Chef, of course.  But the open-source, python-based ansible project is far and away my preferred technology for automating server configuration and initial web app deployments and configuration.  It even handles could-based instance provisioning!  One of it’s best features is that it needs no client agent running on the target server – everything is done through ssh using key-based authentication.  We run redhat-flavored VMs (amazon-linux-ami) so installing ansible goes like this:

#sudo yum install epel-release
#sudo yum-config-manager --enable epel
#sudo yum install ansible

And then you have all of ansible’s cli tools available to issue ad-hoc commands via ansible or run playbooks using ansible-playbook.  It gets even better with a GUI.  And while I think that the ansible tower GUI is reasonably priced (especially when compared to puppet’s GUI), I found the semaphore project on github to be lean and very useful – it’s not yet well documented, so you do have to deal with some guesswork or hope the developers will answer questions on the github board for the project, but once you get everything configured and understand how it works, it’s great!

The semaphore application is a node.js app that normally runs under vagrant or docker – I skipped the vagrant/docker, and just set it up as a node.js app directly on a fresh dedicated server.  Two gotchas:

1. need to npm install some modules for dependencies:
async body-parser connect-redis express jade logtrail morgan passport.socketio bcrypt bugsnag cookie-parser express-session less-middleware mongoose passport serve-static validator

2. need to copy lib/credentials.default.json to lib/credentials.json

Then spin it up running node bin/semaphore.js  –  it will bind to port 80 by default, but you can change that in lib/config.js by changing the exports.port variable.  Point a browser at your install and log in!

What does semaphore do?  So basically it runs playbooks for you.  And here’s how:  Put your playbooks in a git repository (we use bitbucket)  There are only 2 top-level navigation items in semaphore:  Playbooks (which point to the git project)  and Identities (which are private/public ssh keypairs)  You enter keys for the git repository as an identity, then you enter the URL to your repo containing your playbooks and associate it with the right identity.


Semaphore does not use ansible’s default hosts file, so you’ll need to enter hosts and host groups directly into semaphore.

Now you need to enter a Job.  A job is a playbook in your repo – for example if you want to run a playbook from your repository that lives in a subdirectory of the project called “project-deploy” you would enter project-deploy/software-deploy.yaml  as the “Play” (“Name” can be whatever.)



When you click on run for that job, semaphore pulls down the repo into a temp folder and runs ansible-playbook on the .yaml file that you specified – you can monitor the output of the job by going to tasks > see outputtasksCapture

*Protip – semaphore will use the same ssh keypair for fetching the git repo as it will for connecting to the remote host, so you need to be sure that the public key for your git account is also in the authorized_keys file on your target host. You may also need to add an ssh config file to /root/.ssh/config that looks like this:

Host *
  StrictHostKeyChecking no
  CheckHostIp no
  PasswordAuthentication no
  PreferredAuthentications publickey

*Protip2 – semaphore downloads git repos into /root/ as configured in vagrant or docker that works fine, but if you’re working on an install outside of a VM, you need to run semaphore as root.

Here’s an example playbook that ensures a server has everything we need to run our app:

- hosts: testservers
# set the php version that needs to run on the server here
# and ansible will pull in the relevant vars file for that version
# it does not matter if php is currently on the image as this playbook
# completely uninstalls any version and replaces it with the version
# specified here.
# [email protected] - 05/13/15
phpversion: 55
- software-vars-php{{ phpversion }}.yaml
gather_facts: true
remote_user: ec2-user
become: yes

- name: Install EPEL repo.
yum: name={{ repo_package }} state=latest

- name: enable EPEL.
shell: yum-config-manager --enable {{ repo_name }}

- name: clean up any existing php.
yum: name=php* state=absent

- name: clean up any existing php54.
yum: name=php54* state=absent

- name: clean up any existing php55.
yum: name=php55* state=absent

- name: clean up any existing php56.
yum: name=php56* state=absent

- name: Next - update all core packages
yum: name=* state=latest

- name: Then, install required system packages.
yum: name={{ item }} state=latest
with_items: "{{ system_packages }}"

- name: Now, install required npm packages.
npm: name={{ item }} global=yes
with_items: "{{ npm_packages }}"

- name: Install apache security configuration file.
copy: src=conf/x-secure.conf dest=/etc/httpd/conf.d/x-secure.conf

- name: And, restart httpd services.
service: name=httpd state=restarted

- name: Almost done - now enable httpd service at boot.
shell: chkconfig httpd on

- name: Finally, enable mysqld service at boot.
shell: chkconfig mysqld on

And here is the associated variables file:

repo_package: epel-release
repo_name: epel
- git
- httpd24
- httpd24-tools
- httpd24-devel
- mod24_ssl
- php55
- php55-bcmath
- php55-cli
- php55-common
- php55-dba
- php55-devel
- php55-gd
- php55-imap
- php55-intl
- php55-ldap
- php55-mbstring
- php55-mcrypt
- php55-mysqlnd
- php55-odbc
- php55-pdo
- php55-pecl-jsonc
- php55-pecl-jsonc-devel
- php55-pecl-memcached
- php55-pecl-oauth
- php55-pecl-redis
- php55-pecl-ssh2
- php55-pgsql
- php55-pspell
- php55-soap
- php55-tidy
- php55-xml
- php55-xmlrpc
- mysql55-server
- redis
- npm
- nodejs
- mongodb
- bower
- npmlog
- node-uuid


Git yourself some semaphore here:

18 thoughts on “DevOps Automation – Ansible+Semaphore is Indispensable!

  1. Hi Dear,

    thank you very much for your post, without it will be impossible install semaphore.
    Despite your “precious” post I have some problems.
    I created a repository on bitbucket, I exchange the SSH keys and I can push every change through my local server that guest SEMAPHORE. I copied the same keys on semaphore my and I can’t download the playbook through it.
    I have this error:
    runner.js:237 Permission denied (publickey).

    runner.js:237 fatal: Could not read from remote repository.

    Can I help me? Thanks in advance

  2. Is there any way we can change the directory where semaphore downloads the playbooks and run it .I don’t want /root as the working directory for semaphore.

  3. @Sumit /root/ is hardcoded all over the place in the lib/runner.js file. It would be nice if that were a variable that could be set in config.js .

  4. Hi,

    semaphore isn’t loading and hangs at “Loading…”. I get the following error:

    GET / 304 73.554 ms – –
    GET /vendor/requirejs/require.js 304 36.077 ms – –
    LESS File error : ‘../vendor/fontawesome/less/font-awesome.less’ wasn’t found. Tried – /opt/semaphore/public/vendor/fontawesome/less/font-awesome.less,../vendor/fontawesome/less/font-awesome.less
    LESS File : /opt/semaphore/public/css/semaphore.less 13:0

    I don’t habe a vendor directory within my semaphore root.

  5. Hi,

    I tried installing it on the Ubuntu 14.04 and though I see No errors,

    On the Browser it is just stuck at Loading

    Please help!

    1. It seems I missed an important matter. So what I did so far:

      – installed ansible via epel
      – git clone to /opt/semaphore (semaphore root)
      – within semaphore root I installed the modules for dependencies via npm install as you mentioned at step “1.” (after installation a node_modules has been created within semaphore root
      – copied lib/credentials.default.json to lib/credentials.json

  6. Hi,

    Could you give a little more detail? I’m using debian 8 for my tests and would love to know how you got this working.



  7. just in case someone else is facing intallation in a single machine (not using docker) this is what i did in a brand new ubuntu 14.04 server:
    – Cloned semaphore under /opt
    – Installed ansible 1.9.1 (followed the instructions in
    – run playbooks/playbook.yml locally
    – chown -R semphore:semaphore /opt/semaphore
    – Edited /opt/semaphore/runit_semaphore/run so it has the HOME env set in the command line to /root .it would look like:

    cd /opt/semaphore/
    HOME=/root PORT=3000 node bin/semaphore.js`

    Then it worked, i can add credentials, playbooks, hosts & run playbooks

  8. Thank you for your explanation about how Semaphore works.

    What I don’t understand yet is how Ansible can connect from another EC2 and run root commands, like apt or Yum, if you only have the ec2-user to connect before change the sshd_config.

  9. Hi,
    How would you get this flying on a Debian7 server.
    Also some more details how you installed it would be appreciated.
    Especially where did you get the following files lib/credentials.default.json


    1. That’s been deprecated in the refactoring of code for the current release. Now the install process asks you to provide a uname / passwd interactively.

  10. Nice chunk of software but I miss the following:

    – Task execution cancelation
    – Task duration during execution
    – Removing added keys in GUI ( now I do it in DB directly )
    – Cleanup of old run tasks from Dashboard history ( Did not figure out yet how to do that )

    And last but not least I am still struggling to fid where to set which ansible,conf file semaphore uses. This is a key part here as I have some extra configs like ssh timeout that need to be present else the execution fails cause of ssh timeout ( I have some more settings but not worth explaining them here and now ).

    Thank you in advanced!


Leave a Reply

Your email address will not be published. Required fields are marked *