Push to GitHub Triggers Push to Remote
Tags: github, actions, deploy, automation
Published: 2021-06-29 04:55:31

Hi,  
Today I would like to go over how I changed things up a bit and am now able to push my site updates to GitHub, which then pushes the updates to the live production server. This should allow me to add checks within GitHub to ensure my site it updated only if everything is correct. Though I won't go into that here today. I will be focusing on the GitHub Action.

## The Idea
Again the basic idea is pretty simple. I will push updates to my GitHub repo. This will then cause GitHub to trigger an action that will push the updates to my live production site server. In this case I will be using the [actions/checkout](https://github.com/marketplace/actions/checkout) instead of pushing directly to the production server. Less risk of mistakes, if you have checks in place on GitHub.

### Requirements
- Actions must be done by unprivileged users.
- Connect over SSH

## Getting Everything we Need

### SSH

1. We need to generate a new ssh key pair. For simplicity I went with the standard **rsa** with **4096**.

```shell
ssh-keygen -t rsa -b 4096 -C "[identifier]@linode" -f linode
```

This creates two files. **linode** the private key. The one we need to keep really safe. And **linode.pub** the public key that we usually share.  
Things are going to be a little different here since we are actually going to put the private key into GitHub as a **repository** secret. And add the public key to the remote, linode, server.

Before we do that we also need to get some information about the destination server. We need the information that would normally be stored in the **known_hosts** file when we connect to a remote server using standard **ssh**

We can get this information with:
```shell
ssh-keyscan -t rsa [host address/IP address]
```
You should see that I used `-t rsa` here because my **ssh** keys are also `rsa`.

-----

2. Add these **ssh** details to our GitHub repo.
We have to open our repo on GitHub and add our secrets to the repo we will be pushing to.

Access **Settings** -> **Secrets** and create the following two secrets. Using the **New Respository Secret** button.

Name: LINODE_KEY  
Contents:
```shell
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAACFwAAAAdzc2gtcn
--snip--
-----END OPENSSH PRIVATE KEY-----
```

I know this looks odd but, Github will keep this safe. And I would use a unique key anyway. Just in case you need to burn it in the future.

Next we need to add the second secret.

Name: LINODE_KNOWN_HOSTS  
Contents: This will be the output you get from the `ssh-keyscan` command listed earlier.

-----
3. We next need to add the contents of `linode.pub` to the remote server's `authorized_keys` under `.ssh` for the user we plan to connect as. There are lots of guides online for this.


### GitHub Action

At this point we can start putting the GitHub Action together. We do this under `.github/workflows/`

```yaml
name: Linode Push Update

on:
  push:
    branches:
      - master

jobs:
  build:
    name: Build
    runs-on: ubuntu-latest
    steps:
    - name: Prepare ssh keys
      uses: shimataro/ssh-key-action@v2
      with:
        key: ${{ secrets.LINODE_KEY }}
        known_hosts: ${{ secrets.LINODE_KNOWN_HOSTS }}
        
    - name: Checkout the Repo
      uses: actions/checkout@v2
      with:
        ssh-key: ${{ secrets.LINODE_KEY }}
        fetch-depth: 0
        ref: master
    - name: Push to Linode
      run: |
        git config user.name github-actions
        git config user.email github-actions@github.com
        git remote add prod ssh://[username]@[host]:/var/repos/[remote-repo-name].git
        git push prod
```

Most of this is pretty straight forward. But I was missing an important step initially. That is the use to of the **shimataro/ssh-key-action**. This action is needed as it will add our secret **ssh** data so that we authenticate when we connect to the remote server. It adds the **LINODE_KEY** and the **LINODE_KNOWN_HOSTS** information.

If you are wondering about the **remote-repo-name.git** this is because it should be created as a **bare** git repo. If you want to know more about how I created it and the **post-receive** script that is eventually triggered. Take a look at my previous post [here]({% something %)

Using this approach I was able to reuse my previously written **post-receieve** hook script on the remote server to update the live site. So I didn't need to change anything on the remote server.

## Closing

I hope that was interesting and helps others.