Create CI/CD with Github Actions + AWS EC2, CodeDeploy and S3

Suparerk Yodcharoen
Published in
7 min readJul 7, 2020


What’s gonna happen? (TLDR)

  • When you push or merge into specific branch (staging, master etc.) Github Actions will trigger CI Pipeline (Build & Test). If passed it will trigger CD Pipeline (Deployment).
  • All of this are automated by Github Actions and AWS CodeDeploy.


You’ll need an AWS account that can do the following

  • Launch EC2 Instance
  • Create S3 Bucket
  • Create IAM account
  • Create IAM Role


  1. Create IAM Role for EC2 instance & CodeDeploy
  2. Launch EC2 Instance for our application
  3. Create S3 bucket for our application revision
  4. Setup our project for CodeDeploy, PM2 and Github Workflows
  5. Setup CodeDeploy
  6. Create IAM account
  7. Push code to Github, setup secrets key and test

Let’s get started!

1. Create IAM Role for EC2 instance & CodeDeploy

  • From AWS Console, navigate to Identity and Access Management (IAM).
  • Select Access management thenRole.
  • Select Create role.

Create Role for EC2 instance

This role will allow EC2 to communicates with CodeDeploy

  • Select EC2 as a use case, then click Next: Permission
  • From search box, searching for AmazonEC2RoleforAWSCodeDeploy and select it.
  • then searching for AutoScalingNotificationAccessRole and select it.
  • click Next: Tags Give it a tags you desire or you can leave it blank and click Next: Review
  • Give it a name CodeDeployInstanceRole or any name you want.

Create Role for CodeDeploy

This role will allow CodeDeploy to communicates with EC2,

  • From create role screen, scroll down and select CodeDeploy as a use case, then click Next: Permission
  • You’ll see it’s already add required permission for us. click Next: Tags
  • Give it a tags you desire or you can leave it blank and click Next: Review
  • Give it a name CodeDeployServiceRole or any name you want.

Now we have CodeDeployInstanceRole and CodeDeployServiceRole.

2. Launch EC2 Instance for our application

  • From AWS Console, navigate to EC2. and click Launch Instance

In this article i’ll use Ubuntu Server 18.04 LTS as a machine image.

  • Search for Ubuntu then click Select on Ubuntu Server 18.04 LTS
  • Select your desire instance type (t2.micro would be enough for a small application) and then click Next: Configure Instance Details .
  • Looking for IAM role and select CodeDeployInstanceRole . Role that we just created.
  • Scroll down and looking for User data , copy and paste script below.


  • Replace bucket-name and region-identifier with your region. For a list of bucket names and region identifiers, see Resource Kit Bucket Names by Region. For example if you’re using ap-southeast-1 (Singapore) this line of code will be wget
sudo apt-get update
sudo apt-get install ruby
sudo apt-get install wget
cd /home/ubuntu
chmod +x ./install
sudo ./install auto
sudo service codedeploy-agent start
curl -sL | sudo -E bash -
sudo apt-get install -y nodejs
sudo npm install pm2 -g

This script will install CodeDeploy Agent, NodeJS and PM2 on our instance in launch time.

  • Click Next: Add Storage and give your desire storage size
  • Click Next: Add Tags you need to add tags for CodeDeploy to identify which is what.

example, if you have two instance running the same project but one instance is for production and another one for staging, you may add tags that define which instance is what such as env=staging name=aws-codedeploy

  • Click Next: Configure Security Group . We’ll run our application on port 3000, we have to add HTTP and TCP Port 3000 to security group so we can access this port from outside world.

You may setup nginx for reverse proxy and remove unwanted rule later.

  • Click Review and Launch

Now we have EC2 Instance running and ready for deployment.

3. Create S3 bucket for our application revision

This bucket will store our application in CodeDeploy process before deploy to EC2

  • From AWS Console, navigate to S3 , then click Create bucket
  • Give it a name aws-codedeploy-deployments or any name you like and don’t for get to selectBlock all public access this is important. click Create bucket

Now we have our deployments bucket that will store application revision. Let’s move to our code.

4. Setup our project for CodeDeploy, PM2 and Github Workflows

You’ll have to create following files


Let’s start with ecosystem.config.js

Create ecosystem.config.js at your root folder

We’ll serve our application with serve on port 3000

Next, appspec.yml

Create appspec.yml at your root folder.

Keep in mind that All keys/properties and indent are case-sensitive for YAML file.

This AppSpec file tells CodeDeploy where to get source and where to deploy with permission of who.

Hooks will run during lifecycle event of deployment. Each hook is executed once per deployment.

See AppSpec Reference and Hooks Reference for more information.

Next, script

Create at ./scripts

This script will run on ApplicationStart that we have declare above in appspec.yml this will start reload our pm2 process automatically.

Create ci-cd.yml at ./.github/workflows/

You may change appname deploy-group s3-bucket and s3-filename to match your configuration

This workflows will running on push and pull request in staging branch

If test succeeds it will start to build and deploy our app using AWS CLI

In AWS Deploy push step. it will upload our project to S3 bucket.

In AWS Create Deployment step. It create deployment in CodeDeploy to deploy our app.

Now let’s move to AWS Console and setup our CodeDeploy

5. Setup CodeDeploy

  • From AWS Console, navigate to CodeDeploy then Applications
  • Click Create application , give it a name and choose EC2/On-premises and click Create application
  • inside our application click Create deployment group give it a name (in this case we name it after our stage that is staging). Select role CodeDeployServiceRole that we just created above.
  • In Development type. select In-place just for development but in a real world you may choose Blue/green and setup EC2 Auto Scaling group (you don’t want your app to be down right?).
  • In Environment configuration. select Amazon EC2 instances and type tags that you defined when you launch instance, CodeDeploy will identify it automatically
  • In Deployment settings. select CodeDeployDefault.OneAtATime
  • In Load balancer. deselect Enable load balancing and click Create deployment group

Now we’re almost ready Let’s create IAM account for our Github.

6. Create IAM account

  • From AWS Console, navigate to IAM and User and click Add user . select Programmatic access then click Next: Permission
  • Add this two permission to this user then click Next: Tags
  • You can leave it blank and click Next: Review and Create user
  • Save your credential in safe place this is important. we’ll use it later.

Now we done setup our CodeDeploy let’s push our project to Github.

7. Push code to Github, setup secrets key and test

  • Create repository.
  • Commit and push our code up to master.
  • In our repository click Settings add our IAM key that we create above.
  • checkout new branch name it staging and push it to Github.
  • get some coffee and watch actions running. if you seeing this result below, you are going in the right way.
  • From our CodeDeploy in AWS Console. you should see deployments just like below

Congratulations ! our CI/CD is now working.

You now can access your web app via IPv4 Public IP (you can find it from your EC2 Instance page in the description)

Next time you push or make pull request to staging branch, it will automatically run CI Pipeline & CD Pipeline for you.

You can create multiple development stage or have multiple pipeline that suit your work or even multiple instance for different stage.

Web Application | Software | IoT



Suparerk Yodcharoen

Web Developer | Professional Dreamer