---
title: "How to CI/CD AWS With Github using Jenkins"
lang: "en"
author: "Mohammad Abu Mattar"
canonical: https://mkabumattar.com/post/how-to-ci-cd-aws-with-github-using-jenkins
---

![Blog post image for How to CI/CD AWS With Github using Jenkins - In this post, I will show you how to set up a CI/CD pipeline using Jenkins and GitHub to deploy a simple PHP application to development and production environments on AWS. With this setup, you can deploy your application to AWS with a single click.](/_astro/hero.B1mpyM8T_1WDxSM.webp)

[Home](/)›[Blog](/blog)›[All Categories](/blog/categories)›[CI/CD](/blog/categories/cicd)

Blog

[Prev in CI/CDGitHub Actions vs. GitLab CI for Monorepos: Which One Wins?](/blog/post/github-actions-vs-gitlab-ci-for-monorepos)[Next in CI/CDHow to Setup Jenkins on AWS Using CloudFormation](/blog/post/how-to-setup-jenkins-on-aws-using-cloudformation)

[CI/CD](/blog/categories/cicd)[DevOps](/blog/categories/devops)[AWS](/blog/categories/aws)[Jenkins](/blog/categories/jenkins)[GitHub](/blog/categories/github)

# How to CI/CD AWS With Github using Jenkins

[Mohammad Abu Mattar](/authors/mohammad-abu-mattar)Published: 07 Dec 202213 Mins read12 Mins listen

[Markdown for AI(opens in a new tab)](/post/how-to-ci-cd-aws-with-github-using-jenkins/index.md "Open the plain-Markdown version of this page, for pasting into an AI tool")

TL;DR

In this post, I will show you how to set up a CI/CD pipeline using Jenkins and GitHub to deploy a simple PHP application to development and production environments on AWS. With this setup, you can deploy your application to AWS with a single click.

Series

[Jenkins CI/CD with AWS](/series/jenkins-cicd-with-aws)2/3

[PreviousHow to Install Jenkins on AWS EC2 Instance](/blog/post/install-jenkins-on-aws-ec2-instance)[NextHow to Setup Jenkins on AWS Using CloudFormation](/blog/post/how-to-setup-jenkins-on-aws-using-cloudformation)

All posts in this series (3)

Blog3

1.  [How to Install Jenkins on AWS EC2 Instance](/blog/post/install-jenkins-on-aws-ec2-instance)
2.  [How to CI/CD AWS With Github using JenkinsYou are here](/blog/post/how-to-ci-cd-aws-with-github-using-jenkins)
3.  [How to Setup Jenkins on AWS Using CloudFormation](/blog/post/how-to-setup-jenkins-on-aws-using-cloudformation)

### How to CI/CD AWS With Github using Jenkins

Contents

[Home](#home)[Home](#home)[Home](#home)

## [Introduction](#introduction)

In a previous post, I showed you how to set up Jenkins on an AWS EC2 instance. You can read that post [here](/blog/post/install-jenkins-on-aws-ec2-instance).

In this post, I will show you how to set up a CI/CD pipeline using Jenkins and GitHub to deploy a simple PHP application to development and production environments on AWS. With this setup, you can deploy your application to AWS with a single click.

## [Prerequisites](#prerequisites)

-   AWS CLI installed and configured
-   IAM user with the following permissions:
    -   AmazonVPCFullAccess
    -   AmazonEC2FullAccess

## [Set up the AWS infrastructure for the development and production environments](#set-up-the-aws-infrastructure-for-the-development-and-production-environments)

### [Create a VPC](#create-a-vpc)

#### [Step 1: Create the VPC](#step-1-create-the-vpc)

To create a VPC, run the following command:

Terminal window

```
1# Create a VPC2AWS_VPC=$(aws ec2 create-vpc \3  --cidr-block 10.0.0.0/16 \4  --query 'Vpc.VpcId' \5  --output text)6
7# Add a name tag to the VPC8aws ec2 create-tags \9  --resources $AWS_VPC \10  --tags Key=Name,Value=environments-vpc
```

#### [Step 2: Enable DNS hostname support and DNS support on the VPC](#step-2-enable-dns-hostname-support-and-dns-support-on-the-vpc)

To enable DNS hostname support and DNS support on your custom VPC, run the following command:

Terminal window

```
1# Modify your custom VPC and enable DNS hostname support, and DNS support2# Enable DNS hostnames3aws ec2 modify-vpc-attribute \4  --vpc-id $AWS_VPC \5  --enable-dns-hostnames "{\"Value\":true}"6
7# Enable DNS support8aws ec2 modify-vpc-attribute \9  --vpc-id $AWS_VPC \10  --enable-dns-support "{\"Value\":true}"
```

#### [Step 3: Create a public subnet](#step-3-create-a-public-subnet)

To create a public subnet, run the following command:

Terminal window

```
1# Create a public subnet2AWS_PUBLIC_SUBNET=$(aws ec2 create-subnet \3  --vpc-id $AWS_VPC \4  --cidr-block 10.0.1.0/24 \5  --query 'Subnet.SubnetId' \6  --output text)7
8# Add a name tag to the public subnet9aws ec2 create-tags \10  --resources $AWS_PUBLIC_SUBNET \11  --tags Key=Name,Value=environments-public-subnet
```

#### [Step 4: Enable auto-assign public IP on the subnet](#step-4-enable-auto-assign-public-ip-on-the-subnet)

To enable auto-assign public IP on the subnet, run the following command:

Terminal window

```
1# Enable auto-assign public IP on the subnet2aws ec2 modify-subnet-attribute \3  --subnet-id $AWS_PUBLIC_SUBNET \4  --map-public-ip-on-launch
```

#### [Step 5: Create an internet gateway](#step-5-create-an-internet-gateway)

To create an internet gateway, run the following command:

Terminal window

```
1# Create an Internet Gateway2AWS_INTERNET_GATEWAY=$(aws ec2 create-internet-gateway \3  --query 'InternetGateway.InternetGatewayId' \4  --output text)5
6# Add a name tag to the Internet Gateway7aws ec2 create-tags \8  --resources $AWS_INTERNET_GATEWAY \9  --tags Key=Name,Value=environments-internet-gateway
```

#### [Step 6: Attach the internet gateway to your VPC](#step-6-attach-the-internet-gateway-to-your-vpc)

To attach the internet gateway to your VPC, run the following command:

Terminal window

```
1# Attach the Internet Gateway to the VPC2aws ec2 attach-internet-gateway \3  --internet-gateway-id $AWS_INTERNET_GATEWAY \4  --vpc-id $AWS_VPC
```

#### [Step 7: Create a route table](#step-7-create-a-route-table)

To create a route table, run the following command:

Terminal window

```
1# Create a route table2AWS_ROUTE_TABLE=$(aws ec2 create-route-table \3  --vpc-id $AWS_VPC \4  --query 'RouteTable.RouteTableId' \5  --output text)6
7# Add a name tag to the route table8aws ec2 create-tags \9  --resources $AWS_ROUTE_TABLE \10  --tags Key=Name,Value=environments-route-table
```

#### [Step 8: Create a custom route table association](#step-8-create-a-custom-route-table-association)

To associate the route table with the public subnet, run the following command:

Terminal window

```
1# Create a custom route table association2aws ec2 associate-route-table \3  --subnet-id $AWS_PUBLIC_SUBNET \4  --route-table-id $AWS_ROUTE_TABLE
```

#### [Step 9: Add a default route to the internet gateway](#step-9-add-a-default-route-to-the-internet-gateway)

To add a default route that sends outbound traffic through the internet gateway, which is what makes the subnet public, run the following command:

Terminal window

```
1# Associate the subnet with route table, making it a public subnet2aws ec2 create-route \3  --route-table-id $AWS_ROUTE_TABLE \4  --destination-cidr-block 0.0.0.0/0 \5  --gateway-id $AWS_INTERNET_GATEWAY
```

#### [Step 10: Create a security group](#step-10-create-a-security-group)

To create a security group, run the following command:

Terminal window

```
1# Create a security group2AWS_SECURITY_GROUP=$(aws ec2 create-security-group \3  --group-name aws-security-group \4  --description "AWS Security Group" \5  --vpc-id $AWS_VPC \6  --query 'GroupId' \7  --output text)8
9# Add a name tag to the security group10aws ec2 create-tags \11  --resources $AWS_SECURITY_GROUP \12  --tags Key=Name,Value=environments-security-group
```

#### [Step 11: Add inbound rules to the security group](#step-11-add-inbound-rules-to-the-security-group)

To add inbound rules to the security group, run the following command:

Terminal window

```
1# Add inbound rules to the security group2
3# Add SSH rule4aws ec2 authorize-security-group-ingress \5  --group-id $AWS_SECURITY_GROUP \6  --protocol tcp \7  --port 22 \8  --cidr 0.0.0.0/0 \9  --output text10
11# Add HTTP rule12aws ec2 authorize-security-group-ingress \13  --group-id $AWS_SECURITY_GROUP \14  --protocol tcp \15  --port 80 \16  --cidr 0.0.0.0/0 \17  --output text18
19# Add HTTPS rule20aws ec2 authorize-security-group-ingress \21  --group-id $AWS_SECURITY_GROUP \22  --protocol tcp \23  --port 443 \24  --cidr 0.0.0.0/0 \25  --output text
```

### [Create two EC2 instances](#create-two-ec2-instances)

#### [Step 1: Get the latest AMI ID for Amazon Linux 2](#step-1-get-the-latest-ami-id-for-amazon-linux-2)

To get the latest AMI ID for Amazon Linux 2, run the following command:

Terminal window

```
1# Get the latest AMI ID for Amazon Linux 22AWS_AMI=$(aws ec2 describe-images \3  --owners 'amazon' \4  --filters 'Name=name,Values=amzn2-ami-hvm-2.0.*' \5  'Name=state,Values=available' \6  --query 'sort_by(Images, &CreationDate)[-1].[ImageId]' \7  --output 'text')
```

#### [Step 2: Create a key pair](#step-2-create-a-key-pair)

To create a key pair, run the following command:

Terminal window

```
1# Create a key pair2aws ec2 create-key-pair \3  --key-name aws-key-pair \4  --query 'KeyMaterial' \5  --output text > aws-key-pair.pem6
7# Change the permission of the key pair8chmod 400 aws-key-pair.pem
```

#### [Step 3: Create a user data script](#step-3-create-a-user-data-script)

To create a user data script, run the following command:

```
1# Create a userdata script2cat <<EOF > userdata.sh3#!/bin/bash4
5# update the system6sudo yum update -y7
8# install httpd9sudo yum install -y httpd10
11# start httpd12sudo systemctl start httpd13
14# enable httpd15sudo systemctl enable httpd16
17# at first, we will enable amazon-linux-extras so that we can specify the PHP version that we want to install.18sudo amazon-linux-extras enable php7.4 -y19
20# install php21sudo yum install -y php php-{pear,cgi,common,curl,mbstring,gd,mysqlnd,gettext,bcmath,json,xml,fpm,intl,zip,imap}22
23# install MariaDB24sudo yum install -y mariadb-server25
26# start MariaDB27sudo systemctl start mariadb28
29# enable MariaDB30sudo systemctl enable mariadb31
32# we will now secure MariaDB.33sudo mysql_secure_installation <<EOF234y351216123612161237y38y39y40y41EOF242
43# change the ownership of the /var/www directory to the apache user and group.44sudo chown -R apache:apache /var/www45
46# this will give read, write, and execute permissions to the owner, group, and others.47sudo chmod -R 775 /var/www48
49# this is for the wp-config.php file50sudo chmod -R 755 /var/www/html51
52# restart MariaDB53sudo systemctl restart mariadb54
55# restart httpd56sudo systemctl restart httpd57EOF
```

#### [Step 4: Create the EC2 instances](#step-4-create-the-ec2-instances)

To create the two EC2 instances, one for production and one for development, run the following command:

Terminal window

```
1# Create an EC2 Instance2AWS_EC2_INSTANCE_PROD=$(aws ec2 run-instances \3  --image-id $AWS_AMI \4  --count 1 \5  --instance-type t2.micro \6  --key-name aws-key-pair \7  --security-group-ids $AWS_SECURITY_GROUP \8  --subnet-id $AWS_PUBLIC_SUBNET \9  --user-data file://userdata.sh \10  --query 'Instances[0].InstanceId' \11  --output text)12
13AWS_EC2_INSTANCE_DEV=$(aws ec2 run-instances \14  --image-id $AWS_AMI \15  --count 1 \16  --instance-type t2.micro \17  --key-name aws-key-pair \18  --security-group-ids $AWS_SECURITY_GROUP \19  --subnet-id $AWS_PUBLIC_SUBNET \20  --user-data file://userdata.sh \21  --query 'Instances[0].InstanceId' \22  --output text)23
24
25# Add a name tag to the EC2 Instance26aws ec2 create-tags \27  --resources $AWS_EC2_INSTANCE_PROD \28  --tags Key=Name,Value=environments-prod29
30aws ec2 create-tags \31  --resources $AWS_EC2_INSTANCE_DEV \32  --tags Key=Name,Value=environments-dev
```

#### [Step 5: Create the Elastic IPs](#step-5-create-the-elastic-ips)

To create an Elastic IP for each instance, run the following command:

Terminal window

```
1# Create an Elastic IP2AWS_ELASTIC_IP_PROD=$(aws ec2 allocate-address \3  --domain vpc \4  --query 'AllocationId' \5  --output text)6
7AWS_ELASTIC_IP_DEV=$(aws ec2 allocate-address \8  --domain vpc \9  --query 'AllocationId' \10  --output text)11
12# Add a name tag to the Elastic IP13aws ec2 create-tags \14  --resources $AWS_ELASTIC_IP_PROD \15  --tags Key=Name,Value=environments-prod16
17aws ec2 create-tags \18  --resources $AWS_ELASTIC_IP_DEV \19  --tags Key=Name,Value=environments-dev
```

#### [Step 6: Associate the Elastic IPs with the EC2 instances](#step-6-associate-the-elastic-ips-with-the-ec2-instances)

To associate each Elastic IP with its EC2 instance, run the following command:

Terminal window

```
1# Associate the Elastic IP with the EC2 Instance2aws ec2 associate-address \3  --instance-id $AWS_EC2_INSTANCE_PROD \4  --allocation-id $AWS_ELASTIC_IP_PROD5
6aws ec2 associate-address \7  --instance-id $AWS_EC2_INSTANCE_DEV \8  --allocation-id $AWS_ELASTIC_IP_DEV
```

#### [Step 7: Get the public IP addresses of the EC2 instances](#step-7-get-the-public-ip-addresses-of-the-ec2-instances)

To get the public IP address of each EC2 instance, run the following command:

Terminal window

```
1# Get the public IP address of the EC2 Instance2AWS_PUBLIC_IP_PROD=$(aws ec2 describe-instances \3  --instance-ids $AWS_EC2_INSTANCE_PROD \4  --query 'Reservations[0].Instances[0].PublicIpAddress' \5  --output text)6
7AWS_PUBLIC_IP_DEV=$(aws ec2 describe-instances \8  --instance-ids $AWS_EC2_INSTANCE_DEV \9  --query 'Reservations[0].Instances[0].PublicIpAddress' \10  --output text)
```

## [Set up a simple PHP application](#set-up-a-simple-php-application)

### [Create a GitHub repository](#create-a-github-repository)

#### [Step 1: Create a GitHub repository](#step-1-create-a-github-repository)

To create a GitHub repository, run the following command:

Terminal window

```
1# Create a GitHub repository2curl -u $GITHUB_USERNAME https://api.github.com/user/repos -d '{"name":"quick-test-jenkins"}'
```

Or create the repository from the GitHub website. Go to [Create a new repository](https://github.com/new) and use these values.

-   Repository name: quick-test-jenkins
-   Description: Quick Test Jenkins
-   Public/Private: Private
-   Initialize this repository with a README: No
-   Add .gitignore: None
-   Add a license: None

#### [Step 2: Clone the GitHub repository](#step-2-clone-the-github-repository)

To clone the GitHub repository, run the following command:

Terminal window

```
1# Clone the GitHub repository2git clone git@github.com:MKAbuMattar/quick-test-jenkins.git3
4# Change directory5cd quick-test-jenkins
```

#### [Step 3: Create a new branch](#step-3-create-a-new-branch)

To create a new branch, run the following command:

Terminal window

```
1# Create a new branch2git checkout -b devlopment
```

### [Create a simple PHP application](#create-a-simple-php-application)

#### [Step 1: Create the structure of the application](#step-1-create-the-structure-of-the-application)

To create the structure of the application, run the following command:

Terminal window

```
1# Create the structure of the application2mkdir -p app/{config,controllers,views} assets/{css}
```

#### [Step 2: Create the `env.php` file](#step-2-create-the-envphp-file)

To create the `env.php` file, run the following command:

app/config/env.php

```
1<?php2
3// Define the environment4define('URL', $_SERVER['HTTP_HOST']);5define('DEV_DNS', 'DEVLOPMENT_DNS');6define('PROD_DNS', 'PRODUCTION_DNS');7define('DEV', 'DEVLOPMENT_IP');8define('PROD', 'PRODUCTION_IP');9
10// check the environment11if (URL == PROD_DNS || URL == PROD) {12    define('ENV', 'PROD');13} elseif (URL == DEV_DNS || URL == DEV) {14    define('ENV', 'DEV');15} else {16    define('ENV', 'LOCAL');17}18
19
20// Define the database21switch (ENV) {22  case 'PROD':23    define( 'DB_NAME', 'PROD_PHP');24    define( 'DB_USER', 'PROD_USER' );25    define( 'DB_PASSWORD', '161216' );26    define( 'DB_HOST', 'localhost' );27  break;28  case 'DEV':29    define( 'DB_NAME', 'DEV_PHP');30    define( 'DB_USER', 'DEV_USER' );31    define( 'DB_PASSWORD', '121612' );32    define( 'DB_HOST', 'localhost' );33  break;34  default:35    define( 'DB_NAME', '');36    define( 'DB_USER', '' );37    define( 'DB_PASSWORD', '' );38    define( 'DB_HOST', '' );39  break;40}
```

#### [Step 3: Create the `connection.php` file](#step-3-create-the-connectionphp-file)

To create the `connection.php` file, run the following command:

app/config/connection.php

```
1<?php2
3// Include the env.php file4require_once 'env.php';5
6// Create a connection to the database7try {8  $conn = new PDO("mysql:host=".DB_HOST.";dbname=".DB_NAME, DB_USER, DB_PASSWORD);9  $conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);10} catch (PDOException $e) {11  echo "Connection failed: " . $e->getMessage();12}
```

#### [Step 4: Create the controller file](#step-4-create-the-controller-file)

To create the controller file, run the following command:

app/controllers/index.php

```
1<?php2
3// Include the connection.php file4require_once 'app/config/connection.php';5
6// Get the data from the database7$query = "SELECT * FROM `users`";8$stmt = $conn->prepare($query);9$stmt->execute();10$users = $stmt->fetchAll(PDO::FETCH_ASSOC);11
12// close the connection13$conn = null;
```

#### [Step 5: Create the view file](#step-5-create-the-view-file)

To create the view file, run the following command:

app/views/index.php

```
1<!DOCTYPE html>2<html>3  <head>4    <meta charset="utf-8" />5    <meta name="viewport" content="width=device-width, initial-scale=1" />6    <title><?php echo ENV; ?> | My Site</title>7    <link rel="stylesheet" href="./assets/css/normalize.css" />8    <link rel="stylesheet" href="./assets/css/main.css" />9  </head>10  <body>11    <header>12      <h1>My Site</h1>13
14      <nav>15        <ul>16          <li><a href="./index.php">Home</a></li>17        </ul>18      </nav>19    </header>20
21    <main>22      <h2>Home</h2>23      <p>Welcome to my site!</p>24      <p>25        <?php echo "Environment: " . ENV; ?>26      </p>27    </main>28
29    <footer>30      <p>My Site &copy; 2022</p>31    </footer>32  </body>33</html>
```
