Deploying to AWS with Travis via ssh
Published: 2020-05-10 19:59:16

## Introduction

The goal of this post is to provide a sample solution for setting up CICD from a GitHub repo to an AWS ec2 instance using Travis—I hope someone debugging this problem finds this useful. 

I recently worked on a small personal project for a Discord bot, which I deployed on an AWS ec2 instance. My workflow for deploying my GitHub repo to my ec2 instance wasn't that onerous for a personal project—ssh to my ec2 instance, cd to repo, git pull, and restart pm2. 

But it had a problem: any time a contributor made a pull request, _I_ had to deploy the updated master using the workflow above. That approach works fine for one person, but makes less sense for a group of contributors. I needed a deployment methodology that would essentially recreate the steps above, but would do so anytime a pull request was merged to master. That sounded to me like I needed lightweight CICD tooling.

There are many tools to help set up CICD deployment to an AWS ec2 instance (Jenkins, Travis, CircleCI among them). I to setup a custom deployment on Travis, mainly because Travis is hosted and wouldn't require me to set up another ec2 and s3 instances. 

Below, I'll describe how I executed this problem in brief. My solution is an adaptation from [Thomas Parisot](https://oncletom.io/2016/travis-ssh-deploy/), so great thanks to him. He writes in greater depth about why his solution solves for security concerns with ssh'ing to ec2 from Travis, and I strongly consider anyone solving this problem to visit his blog as well.

## Execution

### 1) Set up an ssh key for Travis
- If you don't already have the Travis CLI tooling, use `$ brew install travis`
- Make sure you have a `.travis.yml` file in the root directory of your project repo. 
- While in your root directory of your project repo, execute the following:
```sh
$ ssh-keygen -t rsa -b 4096 -C 'build@travis-ci.org' -f ./deploy_rsa
$ travis encrypt-file deploy_rsa --add
$ ssh-copy-id -i deploy_rsa.pub ec2-user@<your-ec2-instance>
$ rm -f deploy_rsa deploy_rsa.pub
$ git add deploy_rsa.enc
```

### 2) Set up your Travis custom deployment
- The commands above will add most of what you need to your `.travis.yml` file. We will make changes, though, so that the encrypted `deploy_rsa` key gets added to `./tmp/` so that it doesn't accidentally get deployed:
```yml
before_deploy:
- openssl aes-256-cbc -K $encrypted_<...>_key -iv $encrypted_<...>_iv -in deploy_rsa.enc -out /tmp/deploy_rsa -d
- eval "$(ssh-agent -s)"
- chmod 600 /tmp/deploy_rsa
- ssh-add /tmp/deploy_rsa
``` 

- Now that Travis is configures ssh in its `before_deploy` lifecycle, we will tell it what to do in its `deploy` lifecycle. We want it to ssh to our ec2 instance and execute a deployment script:
```yml
deploy:
  provider: script
  skip_cleanup: true
  script: ssh ec2-user@<your-ec2-instance> 'bash ./deploy.sh'
  on:
    branch: master
```

### 3) Write a deploy script for Travis to execute
- The final step is to add a deployment shell script in the root directory of your ec2 instance. After a successful build, travis will ssh to your ec2 instance and call `bash ./deploy.sh`. So the last step is to add a `deploy.sh` script in the root directory of your ec2 instance. 

- Your deployment script will look unique from mine, but I'll provide mine below as guidepost. 

- As stated in my intro, I want mine to `cd` to my previously deployed repo, `git pull` to get the latest, `yarn` to add any missing dependencies, and `pm2 restart all` to re-start my Node server.
```sh
echo "Changing directory to ~/cupbot"
cd cupbot
echo "Pulling from git"
git pull
echo "Yarn'ing"
yarn
echo "Restarting pm2 instances"
pm2 restart all
```

## Conclusion

I hope this was useful to anyone looking to deploy from a GitHub repo to an AWS ec2 instance. If you get stuck or need help, please don't hesitate to comment or reach out. The discord bot repo I deployed is available [here](https://github.com/gortron/cupbot) as well.