Deploy Code from Github Projects to Digital Ocean with Github Actions

Even simple projects can benefit from using Github, and the addition of Github Actions makes pushing your projects directly to a Digital Ocean Droplet (or other staging server) simple.

You don’t need AWS, multiple subscription services, or an IDE to handle making your projects publicly accessible.

This process will get your code out to a server in an easily repeatable process in order to collaborate with others quickly and easily in a pseudo-live environment.

Testing something in a team? Using a staging server like this is a very simple way to get your code out in the wild (or maybe a nature preserve is a more apt analogy) to highlight all those problems you didn’t even know you had while happily coding away on your development laptop.

Prototyping for a client? This is the easiest way to push to a server you control and understand in order to explain how things are going to look and work.

The Basic Process

The process is straight forward and essentially works in two steps:

  1. Create a release from Github
  2. A YAML file runs a described set of actions (ever deployed a Docker container? yeah, its basically that), in this case leveraging a community developed SCP plugin (thanks, seriously the Github community is an amazing resource)

Seems simple enough. There are a few nuances to getting a basic app over to Digital Ocean that I could not easily Google my way out of. I find myself routinely wanting to do this without all the overhead (and expense) that other DevOps tools (however truly awesome they are tbf) introduces. I tried to figure out how it worked twice in a row six months apart – so I figured I should probably write this down somewhere that may be of some use.


  1. A server you can access via SCP on port 22
  2. SSH private/public keys are installed and functioning properly (i.e – you can log in to your server)
  3. Basic understanding of Github push/pull and creating new releases

Let’s start with the code:

name: Deployment
runs-on: ubuntu-latest
name: Checkout Master
uses: actions/checkout@master
name: SCP Files
# You may pin to the exact commit or the version.
# uses: appleboy/scp-action@b476d5806f2a4c1ed5902a87fa91b0623cac7258
uses: appleboy/scp-action@master
host: ${{ secrets.REMOTE_HOST }}
username: ${{ secrets.REMOTE_USER }}
key: ${{ secrets.SSH_KEY }}
passphrase: ${{ secrets.SSH_KEY_PASSPHRASE }}
target: ${{ secrets.REMOTE_APP_DIR }}
source: '.'
rm: true
view raw deploy.yaml hosted with ❤ by GitHub


I actually won’t go line by line here, it is so straightforward. This packages up your code in a tar ball, shoots it over to your server, unpacks it, cleans up, and then is finished.

Step 1: Github Interface – Actions

From your Github project, click on ‘Actions’

As you can see, you have a few possibilities to pre-populate and can probably find a whole host of things to do, and honestly if you know what you need there is approximately zero chance of you stumbling across this blog post.

Just click ‘create new workflow’, drop the above code in (or modify it per your preferences) and move along.

Step 2: Github Interface – Map your Secrets to your Digital Ocean Environment

From your Github project, click on Settings / Secrets:

Each of the variables that are passed to the SCP handler need to be, obviously, derived from your staging server / Digital Ocean environment. They are also pretty self-explanatory, if they are not then more Stackoverflow posts are in your immediate future I’m afraid.

  • REMOTE_APP_DIR: /filepath/to/that/directory/you/want/your/code_or_applicaiton/in
  • REMOTE_HOST: the IP address of your Digital Ocean Droplet or server
  • REMOTE_USER: the user name you use to manage your staging server (please tell me it isn’t root)
  • SSH_KEY: you are using SSH right. We’ll come back to this one
  • SSH_KEY_PASSPHRASE: the password you used when you set up your public/private key pair in PuTTYgen or however you did that

Wait, this is easy why did you even bother to write this up?

Easy business right? Well if you are like me and completely dense about SSH, it took a few tries to actually get connected because I can’t ever remember the format of how tools want to see the keys.

The format of the key is where I hit my stumbling block, and basically the reason for this post. My knowledge of most things is pretty shallow and, specifically, my knowledge of how public and private keys work with the myriad of tools out there is at some level below shallow.

Here is what worked:

  1. Open PuTTYgen
  2. Click Load Existing Key
  3. Enter your passphrase
  4. Click Conversions
  5. Select Export OpenSSH key (force new file format)
  6. Save the file
  7. Ctrl-V the result (below) into the Github UI
This is the format that the SCP integration seems to want.

Step 3: … actually, that is pretty much it.

That should do it. The YAML will trigger the action every time you push a Release from Master and tag it with the tag format you specify.

Since we are using this as a staging server, I chose to just blow out the target directory (the last line in the YAML) every time.

However, once you have this working you can start to tailor it to your specific use case or deployment / project scenario.

We hope this was at least somewhat useful, and at a minimum I’ll probably look back at in in six months when I try and figure out what SSH key format to use…

Bonus Tip

If you are new to this, and given how fast things change in this industy I maintain that we are all new to everything all the time, you might not realize that you don’t have to keep pushing a new tag and release out to test your deployment script.

Just click on the re-run jobs button:

Yup that one, the one in red.

Thanks for reading and happy coding.