Deploy a Next.js Application to AWS EC2 Instance using AWS CodePipeline
AWS CodePipeline is a continuous integration and continuous delivery (CI/CD) service that automates the build, test, and deployment phases of your software release process. In this blog post, we’ll walk you through the steps to set up a CI/CD pipeline using AWS CodePipeline for deploying a Next.js app on an EC2 instance. By the end of this guide, you’ll have an automated workflow that pushes updates to your app from source code changes to the live environment.
Prerequisites:
1 ) An EC2 instance ( Ubuntu 20 ) with Node.js installed and configured to run the Next.js app. ( Follow below mentioned steps to create next.j sample app )
Before we proceed with setting up AWS CodePipeline, let’s ensure that we have our Next.js application code ready and organized in a directory structure. If you already have your Next.js app on GitHub, you might have already created this directory. If not, follow the steps below to create the necessary directory structure for your Next.js app :
mkdir Pipeline-Demo-Next.js
npm install
# Check Version
node -v
npm -v
npm init -y
# Create Project
npx create-next-app@latest
#Follow steps..
#As you can see, in the above cmd i have given " aws-codepipeline-next.js-demo-app app " name
cd aws-codepipeline-next.js-demo-app
#Modify next.config.js File
/** @type {import('next').NextConfig} */
const nextConfig = {output: 'export',}
module.exports = nextConfig
npm i serve
npm run build
# Yeahhhhh.... out file is here
#Test Your App with
npx serve out
PM2 is a production process manager for Node.js applications that makes it easy to manage and deploy your Node.js apps in a production environment. With PM2, you can keep your applications running continuously, enable them to auto-restart in case of crashes, and manage them effortlessly as daemon processes. Installing PM2 globally allows you to access its commands from any location on your server, making it a powerful tool for maintaining the stability and availability of your Node.js applications. To install the latest version of PM2, run the following command in your terminal:
sudo npm install pm2@latest -g
#Create one Shell script
sudo vi start-app.sh
#!/bin/bash
npx serve out
As we prepare to deploy our Next.js app on the EC2 instance, we need to ensure that the startup script, start-app.sh
, has the necessary execution permissions. This script will be responsible for starting our Next.js app on the server.
#Granting Execution Permission to the Startup Script :
sudo chmod +x start-app.sh
# Launching the Next.js App with PM2:
pm2 start start-app.sh
# Check Logs with
pm2 logs 0
Let’s Start with AWS-Codepipeline
1. Create IAM Role for EC2 and AWS CodeDeploy
AWS service roles are used to grant permissions to an AWS service so it can access AWS resources. The policies that you attach to the service role determine which AWS resources the service can access and what it can do with those resources.
Let’s navigate to our AWS Management Console and search for IAM service. Now create a new role for EC2 and AWS CodeDeploy:

Please select : AmazonS3FullAccess


One More IAM role we need to create with
Follow the same steps :
Policy nameTypeAttached as AWSCodeDeployRole

Create a CodePipeline using Github, CodeBuild and CodeDeploy
AWS CodePipeline is a continuous integration and continuous delivery (CI/CD) AWS service that allows you to automate the release process for your application or service. Every time you commit a code change to your source(GitHub, AWS CodeCommit, etc), CodePipeline automatically builds, tests, and deploys your code based on the release process models you define while initializing your CodePipeline. This enables you to rapidly and reliably deliver features and updates.
In the following sections, we will go through the CI/CD pipeline stages:
Step 1: CodePipeline
Step 2: Code Source (CodeCommit or Github)
Step 3: CodeBuild and Build Specification (buildspec.yaml) File
Step 4: CodeDeploy and Application Specification (appspec.yml ) File
Step 5: Adding Shell Script on Server
Step 1: CodePipeline
Let’s navigate to CodePipeline via AWS Management Console and click on Create pipeline:

Step 2: Code Source (CodeCommit or Github)
AWS offers five options to provide the source code for the pipeline: AWS CodeCommit, Amazon ECR, Amazon S3, Bitbucket Cloud (beta) and Github. AWS CodeCommit and GitHub are relatively similar; in this post, we will integrate AWS CodePipeline with GitHub.


Step 3: CodeBuild and Build Specification (buildspec) File
We will now proceed to defining the build provider. AWS offers two options for build provider: AWS CodeBuild and Jenkins.
AWS CodeBuild is a fully managed continuous integration service that compiles source code, runs tests, and produces software packages ready to deploy.
Jenkins is an open source automation tool written in Java with plugins built for continuous integration purpose. If you’re not sure which one to use, check out this article: AWS CodePipeline vs. Jenkins CI Server.
For this post, we will select AWS CodeBuild as our build provider and where we will be prompt to select a project:


We are going to mention Project dependencies and building cmd :
version: 0.2
phases:
install:
runtime-versions:
nodejs: latest
commands:
# Install project dependencies
- node -v
- npm i
build:
commands:
# Build the Next.js app
- npm run build
artifacts:
files:
- '**/*'
# We are keeping our artifacts in S3 bucket



Step 4: CodeDeploy and Application Specification(appspec.yml ) File
AWS CodeDeploy is a fully managed deployment service that automates software deployments to a variety of compute services such as Amazon EC2, AWS Fargate, AWS Lambda, and your on-premises servers. You can update your application with little to no downtime during deployment process. For this post, we will use AWS CodeDeploy as our deploy provider.




We are going to with :
Deployment type : In-place

Select Instance Which we have configure with next.js





DO NOT refresh your browser tab if you don’t see your Application name and Deployment group that you just created when you click on textbox for each, it will remove all the data you’ve entered so far for your pipeline. Instead, click on Previous (which will take you back to Add build stage) and then click Next and come back to Add deploy stage. You will now be able to select the Application name and Deployment group that you just created.
Here, we will briefly discuss the application specification file is. AppSpec file is a YAML-formatted or JSON-formatted used by CodeDeploy to manage a deployment and to determine what it should install onto your instances from your application revision in Amazon S3 or GitHub and which lifecycle event hooks to run in response to deployment lifecycle events. For more information, check out AWS CodeDeploy user guide and EC2/On-Premises deployment AppSpec example.
For my application, the appspec.yml is as follows:
version: 0.0
os: linux
files:
- source: /
destination: /home/ubuntu/Pipeline-Demo-Next.js/aws-codepipeline-next.js-demo-app
overwrite: true
file_exists_behavior: OVERWRITE
permissions:
- object: /home/ubuntu/Pipeline-Demo-Next.js/aws-codepipeline-next.js-demo-app/scripts
pattern: "**"
owner: ubuntu
group: ubuntu
mode: 777
type :
- file
hooks:
BeforeInstall:
AfterInstall:
ApplicationStart:
- location: scripts/app_start.sh
timeout: 2500
runas: ubuntu
Step 4: Add Shell Script on GitHub & Server.
And the three simple bash scripts used above are as follows:
1 ) app_start.sh
# Keep this shell script in github ( script/ app_start.sh )
#!/bin/bash
cd /home/ubuntu/Pipeline-Demo-Next.js/aws-codepipeline-next.js-demo-app && /bin/sh deploy.sh
2 ) deploy.sh
# Keep this shell script inside Server ( /home/ubuntu/Pipeline-Demo-Next.js/aws-codepipeline-next.js-demo-app/deploy.sh )
#!/bin/bash
/usr/bin/pm2 restart start-app.sh
#/home/ubuntu/.nvm/versions/node/v20.4.0/bin/pm2 restart start-app.sh
#Keep this shell script on Server
3 ) start-app.sh
#Keep this shell script inside server ( /home/ubuntu/Pipeline-Demo-Next.js/aws-codepipeline-next.js-demo-app/start-app.sh )
#!/bin/bash
npx serve /home/ubuntu/Pipeline-Demo-Next.js/aws-codepipeline-next.js-demo-app/out
#Keep this shell script on Server


There are several reason why you would get this error. For me, my deployment failed because I hadn’t installed the CodeDeploy agent on my EC2 instance. The CodeDeploy agent is a software package that, when installed and configured on an instance, makes it possible for that instance to be used in CodeDeploy deployments. Here is a more detailed article on troubleshooting EC2/On-Premises Deployment Issues
Step 1 : First Attach IAM Role to EC2 Instance : Next.js

Step 2 : Now connect to your EC2 instance by following instructions in this article and install/reinstall the CodeDeploy agent on your EC2 instance:
sudo apt-get update -y
sudo apt install ruby-full -y
sudo apt install wget -y
cd /home/ubuntu
wget https://aws-codedeploy-ap-south-1.s3.ap-south-1.amazonaws.com/latest/install
chmod +x ./install
sudo ./install auto
sudo service codedeploy-agent status Or sudo service codedeploy-agent start
If everything goes well during your deployment stage, you will see all six events with “succeeded” status:

Few times my deployment failed and I spent a good amount of time searching for errors and their solutions on Google and reading AWS documentations. Then, here came the best part:

Access your Next.js Application on EC2 Public DNS :
You can access your EC2 instance on EC2 Public DNS (IPv4) located under Description in EC2 Management Console, looks something like this:
http://ec2-52-66-243-137.ap-south-1.compute.amazonaws.com:3000/

Copy/paste your Public DNS (IPv4) on another tab and append port :3000 at the end of the DNS address (since our Next.js app is using port 3000 by default). As you will see this will not work and there is nothing to show on browser and the browser connection will timeout.

Access the EC2 Public DNS, http://ec2-52-66-243-137.ap-south-1.compute.amazonaws.com:3000/
again and you should be able to see your app content now.

If you like this post, or you are stuck at any point in the above sections and have any questions, feel free to ask them below or message them to me on LinkedIn. I’d be more than happy to help you out.
Thank you for reading! if I have made a mistake somewhere or missed an essential point, please definitely let me know in the comments. 🙏