Heroku Deployment#

This guide shows you how to use Semaphore to set up deployment to Heroku for an application or microservice written in any language.

For this guide you will need:

Connect CI and deployment pipelines with a promotion#

Start by defining a promotion at the end of your semaphore.yml file:

# .semaphore/semaphore.yml
  - name: Deploy to Heroku
    pipeline_file: heroku.yml

This defines a simple deployment pipeline which can be triggered manually on every revision on every branch. You can generally define as many pipelines for a project as you need using a variety of options and conditions. For designing custom delivery pipelines, consult the promotions reference documentation.

Define Heroku deployment#

In this example we're going to configure Heroku deployment using SSH Git transport.

Create a deploy key#

Create a new SSH key with no passphrase which Semaphore will use to authenticate with Heroku:

$ ssh-keygen -t rsa -b 4096 -C "semaphore@heroku.com"
Generating public/private rsa key pair.
Enter file in which to save the key (/Users/marko/.ssh/id_rsa): /Users/marko/.ssh/id_rsa_semaphore_heroku
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /Users/joe/.ssh/id_rsa_semaphore_heroku.
Your public key has been saved in /Users/joe/.ssh/id_rsa_semaphore_heroku.pub.
The key fingerprint is:
SHA256:8ujVmyIhyAAMaaDpyE+xty5mVDyzK2YrX4OrJxgkj80 semaphore@heroku.com
The key's randomart image is:
+---[RSA 4096]----+
|*.               |
|++               |
|=  ..            |
|*.  o=           |
|+X +..= S        |
|o E.+.o+ .       |
|...o =o.o .      |
|.o O+oo..  o     |
| .@++... .o      |

Next we need to make the private key id_rsa_semaphore_heroku available on Semaphore, and add the corresponding public key id_rsa_semaphore_heroku.pub to Heroku.

Store private SSH key in a Semaphore secret#

Create a new Semaphore secret using the sem CLI:

$ sem create secret demoapp-heroku \
  --file /Users/joe/.ssh/id_rsa_semaphore_heroku:/home/semaphore/.ssh/id_rsa_semaphore_heroku
Secret 'demoapp-heroku' created.

You can verify the existence of your new secret:

$ sem get secrets
NAME             AGE
demoapp-heroku   26s

You can also verify the content of your secret:

$ sem get secret demoapp-heroku
apiVersion: v1beta
kind: Secret
  name: demoapp-heroku
  id: a4f08e2c-166f-4a01-97e2-1b961719454f
  create_time: "1543748243"
  update_time: "1543748243"
  env_vars: []
  - path: /home/semaphore/.ssh/id_rsa_semaphore_heroku
    content: LS0tLS1CRUdJTiBPUEV...

The content of secrets is base64-encoded, and we see that our file will be mounted in Semaphore jobs on desired path. All good.

Add your public key to Heroku#

Add the public SSH key to Heroku using heroku keys:add:

$ heroku keys:add
? Which SSH key would you like to upload?
❯ /Users/joe/.ssh/id_rsa_semaphore_heroku.pub

You can do the same through the Heroku user interface, in the "SSH Keys" section of your Account Settings. For more information consult Heroku documentation.

Define the deployment pipeline#

Finally let's define what happens in our heroku.yml pipeline:

# .semaphore/heroku.yml
version: v1.0
name: Heroku deployment
    type: e1-standard-2
    os_image: ubuntu1804

  - name: Deploy
        - name: demoapp-heroku
        - name: HEROKU_REMOTE
          value: https://git.heroku.com/semaphore-demoapp.git
        - name: HEROKU_APP_NAME
          value: heroku-app-name
      - name: Push code
          - checkout --use-cache
          - ssh-keyscan -H heroku.com >> ~/.ssh/known_hosts
          - chmod 600 ~/.ssh/id_rsa_semaphore_heroku
          - ssh-add ~/.ssh/id_rsa_semaphore_heroku
          - git config --global url.ssh://git@heroku.com/.insteadOf https://git.heroku.com/
          - git remote add heroku $HEROKU_REMOTE
          - git push heroku -f $SEMAPHORE_GIT_BRANCH:master
          - heroku run --app $HEROKU_APP_NAME rake db:migrate
          - heroku ps:restart

Note: change the value of HEROKU_APP_NAME to match your application's name as it is registered on Heroku.

Note: For deploying to Heroku, it is required that you use checkout with the --use-cache option in order to avoid the shallow clone of your GitHub repository.

Note: In order to invoke commands on a remote Heroku application, HEROKU_API_KEY environment variable should be set on Semaphore. The API key can be found by logging in to Heroku website and navigating to your Account Settings. Clicking on the Reveal button next to the API Key textbox will reveal your API key.


  • By mounting the demoapp-heroku secret we make the private SSH key available inside the pipeline block.
  • Using ssh-keyscan we specify that heroku.com is a trusted domain and bypass an interactive confirmation step which would block our job.
  • We need to manually add our private SSH key to local SSH agent.
  • We want to always use SSH Git transport.
  • Using force-push ensures we can deploy any amended Git branch without issues.

Verify it works#

Push a new commit on any branch and open Semaphore to watch a new workflow run. If all goes well you'll see the "Promote" button next to your initial pipeline. Click on it to launch deployment, and open the "Push code" job to observe its' output.

Next steps#

Congratulations! You have automated deployment of your application to Heroku. Here’s some recommended reading: