Install Composer with Ansible, the lean way

June 7th, 2016 by Philip Iezzi 3 min read
cover image

Every PHP developer needs Composer and as a webhosting company at Onlime GmbH, sure we had to provide Composer binary to every customer, deploying it to every webserver. But how come the recommended Composer installation for Linux/Unix/macOS is so clunky, only providing the latest composer.phar through an installer?

Sure, installers are fine, but not for a sysadmin who likes to keep things simple and fully manage his infrastructure with Ansible. Installing Composer should be nothing more than deploying the latest composer.phar, period. But the author of Composer somehow forgot to provide us a download URL for the latest stable version. (Sorry Jordi Boggiano, don't want to blame you - maybe I just overlooked it and should have asked you via DM. But writing that small Ansible playbook was still faster than looking any further.)

So, I would like to present you a super simple way of grabbing the latest Composer version, download and deploy composer.phar.

Luckily, the author of Composer provides us with a nice JSON that contains all version information (ok, that's nice!):

We're only interested in stable version:

{
  "stable": [
    {
      "path": "/download/1.1.2/composer.phar",
      "version": "1.1.2",
      "min-php": 50300
    }
  ]
}

So here is my Ansible playbook, that grabs the stable version from getcomposer.org/versions and resolves the download URL from there, then deploys composer.phar:

install-composer.yml
---
- hosts: webservers
  
  tasks:
    # Install Composer the lightweight way (without using installer)
    # https://getcomposer.org/download
    - name: Composer | Grab release information
      uri:
        url: https://getcomposer.org/versions
        body_format: json
      register: composer_releases

    - set_fact:
        composer_version: '{{ composer_releases.json.stable.0.version }}'
        composer_download_url: 'https://getcomposer.org{{ composer_releases.json.stable.0.path }}'
      when: not ansible_check_mode # composer_releases is not registered

    - name: Composer | Install Composer {{ composer_version }}
      get_url:
        url: '{{ composer_download_url }}'
        dest: /usr/local/bin/composer.phar
        mode: 0755
      when: not ansible_check_mode # composer_releases is not registered

    - name: Composer | Symlink composer.phar
      file:
        src: composer.phar
        dest: /usr/local/bin/composer
        state: link
      when: not ansible_check_mode # composer_releases is not registered

You could then run this Ansible playbook as follows, limiting it to a single server:

$ ansible-playbook install-composer.yml -l myhost -D

done. That was easy.

UPDATE 2021-08-22:

I never looked into this again, as above solution was working perfectly fine for the last years. Also, I am upgrading Composer with a frequent cronjob using composer -q self-update, which also works flawlessly. But in the meantime, the authors of Composer published this FAQ:

How do I install Composer programmatically?

That solution still looks to clunky in my eyes. But on the Composer download page, you'll now finally find a direct link to the latest stable version, including the sha256:

So, forget about this whole article (hey, it dates back to 2016!) and replace above Ansible playbook by this simple one:

install-composer.yml
- hosts: webservers
  
  vars:
    composer_url: https://getcomposer.org/download/latest-stable/composer.phar

  tasks:
    # Install Composer the lightweight way (without using installer)
    # https://getcomposer.org/download
    - name: Composer | Install Composer latest-stable
      get_url:
        url: '{{ composer_url }}'
        checksum: 'sha256:{{ composer_url }}.sha256sum'
        dest: /usr/local/bin/composer.phar
        mode: 0755

    - name: Composer | Symlink composer.phar
      file:
        src: composer.phar
        dest: /usr/local/bin/composer
        state: link

I still keep this article online, as it shows how easy it is to parse a JSON with Ansible, even from a remote location.