<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0">
<channel>
<title>Coder Legion - Recent posts tagged aws-ec2</title>
<link>https://coderlegion.com/tag/aws-ec2</link>
<description>Powered by Question2Answer</description>
<item>
<title>Developer Journar Day5:  How to Launch and Configure an Amazon EC2 Instance (From Scratch)</title>
<link>https://coderlegion.com/19274/developer-journar-day5-how-to-launch-and-configure-an-amazon-ec2-instance-from-scratch</link>
<description>&lt;p&gt;When you start working with cloud computing on AWS, one of the first major milestones is understanding how EC2 instances work. In simple terms, it’s like spinning up your own server on the internet in just a few minutes.&lt;/p&gt;
&lt;p&gt;In this article, I’ll walk you through how to create and launch an EC2 instance that works as a basic web server.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt; What is an EC2 instance?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;An instance in Amazon Web Services, specifically within the Amazon EC2 service, is a virtual machine that you can configure based on your needs: CPU, memory, storage, and operating system.&lt;/p&gt;
&lt;p&gt;Think of it as renting a computer in the cloud that you can start, stop, and customize anytime.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;⚙️ Step 1: Create the instance&lt;/strong&gt;&lt;br&gt;
The first step is to go to the EC2 dashboard and click “Launch Instance.”&lt;/p&gt;
&lt;p&gt;Here you define some key settings:&lt;/p&gt;
&lt;p&gt;️ Instance name&lt;/p&gt;
&lt;p&gt;You can assign a descriptive name such as:&lt;/p&gt;
&lt;p&gt;“My Web Server”&lt;/p&gt;
&lt;p&gt;This helps you easily identify it later.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt; Step 2: Choose the AMI&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;An Amazon Machine Image is basically the base image used to create your server.&lt;/p&gt;
&lt;p&gt;In this case, we use Amazon Linux, a lightweight and optimized OS for cloud environments.&lt;br&gt;
&lt;strong&gt;&lt;br&gt;
️ Step 3: Instance type&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;This defines the computing power of your virtual machine.&lt;br&gt;
For this example:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;t3.micro&lt;/li&gt;
&lt;li&gt;1 vCPU&lt;/li&gt;
&lt;li&gt;1 GB RAM&lt;br&gt;
Free Tier eligible This is perfect for learning and small projects.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt; Step 4: Key pair (SSH access)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;To securely connect to your instance, you need a key pair:&lt;/p&gt;
&lt;p&gt; Public key: stored in the instance&lt;br&gt;
 Private key: kept on your machine&lt;br&gt;
This enables secure SSH access.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt; Step 5: Network settings&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Here you control how your instance is accessed.&lt;/p&gt;
&lt;p&gt;In this setup:&lt;/p&gt;
&lt;p&gt;HTTPS traffic is allowed from the internet&lt;br&gt;
A Security Group is used to manage inbound rules&lt;/p&gt;
&lt;p&gt;This is what makes your server accessible from a browser.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt; Step 6: Storage configuration&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;You assign virtual disk storage (EBS):&lt;/p&gt;
&lt;p&gt;8 GB&lt;br&gt;
gp3 volume type Enough for a basic web server setup.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt; Step 7: User Data script (bootstrapping the server)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The base AMI only includes the operating system, so no web server is installed by default.&lt;/p&gt;
&lt;p&gt;To fix this, we use User Data, which allows us to run a script at launch time that:&lt;/p&gt;
&lt;p&gt;Installs a web server (like Apache or Nginx)&lt;br&gt;
Starts and enables the service automatically&lt;br&gt;
Prepares the instance to serve web content&lt;/p&gt;
&lt;p&gt;&lt;strong&gt; Step 8: Launch the instance&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Once everything is configured:&lt;br&gt;
 Click “Launch Instance”&lt;/p&gt;
&lt;p&gt;AWS handles the rest: provisioning, setup, and booting your virtual machine.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt; Step 9: Access your server&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;After a couple of minutes, the instance will be in a running state.&lt;/p&gt;
&lt;p&gt;Then:&lt;/p&gt;
&lt;p&gt;Copy the public IP address&lt;br&gt;
Open a browser&lt;br&gt;
Paste the IP&lt;/p&gt;
&lt;p&gt;And you’ll see your web server running &lt;/p&gt;
&lt;p&gt;&lt;strong&gt; Conclusion&lt;/strong&gt;&lt;br&gt;
Launching an EC2 instance is one of the first essential steps in understanding cloud computing on AWS.&lt;/p&gt;
&lt;p&gt;With just a few clicks, you can deploy a fully functional virtual server ready to host applications, APIs, or websites.&lt;/p&gt;
&lt;p&gt;If you want, I can also help you next with:&lt;/p&gt;
&lt;p&gt;adding AWS architecture diagrams&lt;br&gt;
explaining VPC, subnets, and security groups visually&lt;br&gt;
or turning this into a “Cloud Engineer roadmap series” post&lt;/p&gt;
&lt;p&gt;Just tell me &lt;/p&gt;
</description>
<category>Tutorials</category>
<guid isPermaLink="true">https://coderlegion.com/19274/developer-journar-day5-how-to-launch-and-configure-an-amazon-ec2-instance-from-scratch</guid>
<pubDate>Sat, 30 May 2026 07:38:57 +0000</pubDate>
</item>
<item>
<title>You’re Running EC2 Instances That Do Nothing</title>
<link>https://coderlegion.com/9859/youre-running-ec2-instances-that-do-nothing</link>
<description>&lt;p&gt;Somewhere in your account, EC2 instances are running with no traffic, no purpose, and no owner.&lt;br&gt;
They exist only because nobody had the audacity to delete them.&lt;/p&gt;
&lt;h3 id=&quot;they-were-never-meant-to-survive&quot;&gt;They Were Never Meant to Survive&lt;/h3&gt;
&lt;p&gt;These instances were born from lies.  &lt;/p&gt;
&lt;p&gt;They were launched for a “temporary test.”&lt;br&gt;
They survived three reorgs.&lt;br&gt;
They outlived the engineer who created them.&lt;/p&gt;
&lt;p&gt;Now they sit there.&lt;br&gt;
Running.&lt;br&gt;
Billing.&lt;br&gt;
Judging you silently.  &lt;/p&gt;
&lt;p&gt;Who approved them?&lt;br&gt;
Who needs them?&lt;br&gt;
Who even knows they exist?  &lt;/p&gt;
&lt;p&gt;AWS charges you for your ignorance.  &lt;/p&gt;
&lt;h3 id=&quot;idle-does-not-mean-free&quot;&gt;Idle Does Not Mean Free&lt;/h3&gt;
&lt;p&gt;You tell yourself idle instances aren’t that expensive.&lt;br&gt;
That is a lie you repeat to sleep better.&lt;/p&gt;
&lt;p&gt;CPU at 1%.&lt;br&gt;
Disk doing nothing.&lt;br&gt;
Network flatlined.  &lt;/p&gt;
&lt;p&gt;You're still being charged.&lt;/p&gt;
&lt;p&gt;Compute.&lt;br&gt;
Storage.&lt;br&gt;
Attached volumes.&lt;br&gt;
Elastic IPs you forgot about.  &lt;/p&gt;
&lt;p&gt;Idle infrastructure resources are not free.&lt;br&gt;
They are active waste.  &lt;/p&gt;
&lt;p&gt;You don’t get a discount for ignorance.&lt;br&gt;
AWS bills uptime, not intention.  &lt;/p&gt;
&lt;p&gt;How many instances would vanish if “no traffic” was a deletion rule?  &lt;/p&gt;
&lt;p&gt;If the answer scares you, good.  &lt;/p&gt;
&lt;h3 id=&quot;fear-is-cheaper-than-discipline&quot;&gt;Fear Is Cheaper Than Discipline&lt;/h3&gt;
&lt;p&gt;Nobody logs into them.&lt;br&gt;
Nobody updates them.&lt;br&gt;
Nobody monitors them.  &lt;/p&gt;
&lt;p&gt;But nobody deletes them either.  &lt;/p&gt;
&lt;p&gt;Because deleting the wrong instance is dangerous.&lt;br&gt;
Because breaking something is problematic.&lt;br&gt;
Because wasting money is quiet.  &lt;/p&gt;
&lt;p&gt;So you choose fear over discipline.&lt;br&gt;
You choose silence over ownership.  &lt;/p&gt;
&lt;p&gt;If you can’t explain what breaks when it’s terminated, you already lost control.&lt;/p&gt;
&lt;h3 id=&quot;this-is-not-technical-debt-it-s-financial-carelessness-&quot;&gt;This Is Not Technical Debt. It’s Financial Carelessness.&lt;/h3&gt;
&lt;p&gt;You wouldn’t keep routing traffic to unhealthy instances.&lt;br&gt;
You wouldn’t run production with broken readiness checks.&lt;br&gt;
You wouldn’t ignore failing health checks.  &lt;/p&gt;
&lt;p&gt;But you ignore idle EC2 because the damage arrives monthly, not instantly.  &lt;/p&gt;
&lt;p&gt;That doesn’t make it harmless.&lt;br&gt;
It makes it dangerous.  &lt;/p&gt;
&lt;p&gt;You are not “scaling responsibly.”&lt;br&gt;
You are leaking money because nobody owns cleanup.  &lt;/p&gt;
&lt;p&gt;So here’s the uncomfortable truth:&lt;/p&gt;
&lt;p&gt;If you’re afraid to delete EC2 instances, you don’t understand your own system.&lt;br&gt;
If you don’t review EC2 costs monthly, you are guessing.&lt;br&gt;
If you accept idle infrastructure, you are choosing waste.  &lt;/p&gt;
&lt;p&gt;Now decide.&lt;/p&gt;
&lt;p&gt;Keep paying for servers nobody needs.&lt;br&gt;
Or admit the mess and clean it up.&lt;/p&gt;
&lt;h4 id=&quot;ps&quot;&gt;PS&lt;/h4&gt;
&lt;p&gt;This was my attempt at a post in the form of a short dramatic story. If you liked this, read the others blogs as well at &lt;a rel=&quot;nofollow&quot; href=&quot;http://costlyfy.com/blog&quot;&gt;costlyfy.com&lt;/a&gt;&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/9859/youre-running-ec2-instances-that-do-nothing</guid>
<pubDate>Sat, 17 Jan 2026 02:39:35 +0000</pubDate>
</item>
<item>
<title>Deploy a Next.js App on AWS EC2 with Docker, NGINX, and Automate with GitHub Actions.</title>
<link>https://coderlegion.com/5757/deploy-a-next-js-app-on-aws-ec2-with-docker-nginx-and-automate-with-github-actions</link>
<description>&lt;p&gt;Next.js is a powerful React framework that provides server-side rendering, static site generation, and API routes. Deploying a Next.js app on an AWS EC2 instance allows for better control and customization of the hosting environment. This guide will walk you through the process of setting up a Next.js application on AWS EC2 using Docker and NGINX while automating deployment with GitHub Actions.&lt;/p&gt;
&lt;p&gt;Before following this Next.js tutorial, we recommend that you first consult Build and Deploy a ReactJS App to AWS EC2 with Docker, NGINX, and Automate with GitHub Actions. This guide is a continuation of the series on React deployment, focusing solely on Next.js-specific updates. The basic steps remain the same, and you can refer to the previous article for more details.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Table of Contents&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Setting Up the &lt;strong&gt;Project&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Dockerizing&lt;/strong&gt; the NextJS application&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Setting up &lt;strong&gt;NGINX&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Automating deployment with GitHub Actions on &lt;strong&gt;AWS EC2&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;&lt;p&gt;Note that you can find the link of final source code in the&lt;br&gt;
&lt;a rel=&quot;nofollow&quot; href=&quot;http://%20https://github.com/kilamaelie/Deploy-a-Next.js-App-on-AWS-EC2-with-Docker-NGINX-and-Automate-with-GitHub-Actions&quot;&gt;https://github.com/kilamaelie/Deploy-a-Next.js-App-on-AWS-EC2-with-Docker-NGINX-and-Automate-with-GitHub-Actions&lt;/a&gt;&lt;br&gt;
repository.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;Step 1. Setting Up the Project&lt;/strong&gt;&lt;br&gt;
Open your terminal and navigate to the directory where you want to create the project, for the purpose of this tutorial we’ll create a directory with a name &lt;code&gt;next-tutorial-app&lt;/code&gt; or you can name it anything depending on your project name. This folder is considered as the &lt;code&gt;root&lt;/code&gt; directory for our application which contains all folders and files structures.&lt;/p&gt;
&lt;p&gt;Then, we will change our directory into the &lt;code&gt;next-tutorial-app&lt;/code&gt; folder and all other parts of configuration files or folders will be in this folder.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;gt; mkdir next-tutorial-app
&amp;gt; cd next-tutorial-app
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Inside the &lt;code&gt;next-tutorial-app&lt;/code&gt; folder, to create a new Next project runs the following command using create-next-app@latest&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;npx create-next-app@latest # website is our app-name or folder name 
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let’s change the directory into website as our app-name for NextJs application and start development server.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cd website # app-name
npm run dev # start the development server
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Step 2: Dockerizing the Next.js App&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Create a &lt;code&gt;Dockerfile&lt;/code&gt; in the root directory of your website folder:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;FROM node:23.10.0-alpine

WORKDIR /app

COPY ./package*.json ./

# Install dependencies
RUN yarn

# Copy all files
COPY . .

# Expose the listening port
EXPOSE 3000
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, create a &lt;code&gt;.dockerignore&lt;/code&gt; file to exclude unnecessary files:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;node_modules
.next
.DS_Store
dist
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In your project’s &lt;code&gt;root&lt;/code&gt; directory as &lt;code&gt;next-tutorial-app&lt;/code&gt;, create a file named &lt;code&gt;docker-compose.yml&lt;/code&gt;. This file will contain the configuration for your multi-container application.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;services:
  website:
    build:
      context: ./website
      dockerfile: Dockerfile
    command: yarn dev
    ports:
      - &quot;3000:3000&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So to test it, just go in your terminal, navigate to the directory containing the &lt;code&gt;docker-compose.yml&lt;/code&gt; file and run:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker-compose up
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Kill the task in the terminal where docker-compose up is running in order to stop the. To remove the containers and their associated resources, run:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker-compose rm -v
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Step 3: Setting Up NGINX as a Reverse Proxy in Docker&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;In the root of your project directory, create a Nginx directory named &lt;code&gt;nginx&lt;/code&gt; then create a configuration file named &lt;code&gt;nginx.conf&lt;/code&gt; . So inside nginx.conf file adds the following configuration:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;server {
     listen 80;
     server_name localhost; 
     #server_name can add your domain or Ip address for your server in the production
 
    location / {
        proxy_pass http://website:3000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;
     }
 }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;in the same directory as your Nginx, create a &lt;code&gt;Dockerfile&lt;/code&gt; which defines how to build a custom Nginx Docker Image:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# Use an official Nginx image as the base image
FROM nginx:latest

# Remove any existing config files
RUN rm /etc/nginx/conf.d/*
# Copy the custom Nginx configuration
COPY nginx.conf /etc/nginx/conf.d/
# Expose port 80 for Nginx
EXPOSE 80
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Before testing in development, let’s update our &lt;code&gt;docker-compose&lt;/code&gt; file by adding the Nginx service&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;services:
  website:
    build:
      context: ./website
      dockerfile: Dockerfile
    ports:
    - 3000:3000
    
  nginx:
    build:
     context: ./nginx
     dockerfile: Dockerfile
    ports:
      - &quot;80:80&quot;
    depends_on:
      - website
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Also update the &lt;code&gt;Dockerfile&lt;/code&gt; for the next app in the website directory&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# Stage 1: Install Dependencies
ARG NODE=node:20-alpine 
FROM ${NODE} AS deps

RUN apk add --no-cache libc6-compat

WORKDIR /app

COPY package*.json ./
RUN npm install

# Stage 2: Build
FROM ${NODE} AS builder

WORKDIR /app

COPY --from=deps /app/node_modules ./node_modules
COPY . .

RUN npm run build

# Stage 3: Production Runner
FROM ${NODE} AS runner

WORKDIR /app

ENV NODE_ENV production
ENV PORT 3000
ENV NEXT_TELEMETRY_DISABLED 1

# Install PM2 globally
RUN npm install -g pm2

# Create a non-root user
RUN addgroup --system --gid 1001 nodegroup
RUN adduser --system --uid 1001 appuser

# Copy necessary files
COPY --from=builder /app/public ./public
COPY --from=builder /app/package.json ./package.json
COPY --from=builder --chown=appuser:nodegroup /app/.next/standalone ./
COPY --from=builder --chown=appuser:nodegroup /app/.next/static ./.next/static

USER appuser

EXPOSE 3000

# Start the application using PM2
CMD [&quot;pm2-runtime&quot;, &quot;node&quot;, &quot;--&quot;, &quot;server.js&quot;]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Before testing, ensure that output: '&lt;code&gt;standalone'&lt;/code&gt; is set in the &lt;code&gt;next.config.js&lt;/code&gt; file to optimize the build for Docker deployment.&lt;/p&gt;
&lt;p&gt;To test if everything works, open a terminal, navigate to your root directory, and run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker-compose up  #
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then let’s testing at &lt;a rel=&quot;nofollow&quot; href=&quot;http://localhost:80&quot;&gt;http://localhost:80&lt;/a&gt; or &lt;a rel=&quot;nofollow&quot; href=&quot;http://127.0.0.1:80&quot;&gt;http://127.0.0.1:80&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Kill the task in the terminal&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker-compose rm -v
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, let’s create &lt;code&gt;docker-compose.ci&lt;/code&gt; and &lt;code&gt;docker-compose.prod&lt;/code&gt; files for the production and workflow purpose in the root directory of the project&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Docker-compose.ci

services:
  website:
    container_name: website
    build:
      context: ./website
      dockerfile: Dockerfile
      cache_from:
        - '${NEXT_APP_WEBSITE_IMAGE}'
    image: '${NEXT_APP_WEBSITE_IMAGE}'
    env_file:
      - ./.env
    ports:
      - '3000:3000'

  nginx:
    container_name: nginx
    build:
      context: ./nginx
      dockerfile: Dockerfile
      cache_from:
        - '${NEXT_APP_NGINX_IMAGE}'
    image: '${NEXT_APP_NGINX_IMAGE}'
    ports:
      - '80:80'
    restart: always
    depends_on:
      - website
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;Docker-compose.prod

services:
  website:
    container_name: website
    image: '${NEXT_APP_WEBSITE_IMAGE}'
    env_file: .env
    ports:
      - '3000:3000'

  nginx:
    container_name: nginx
    image: '${NEXT_APP_NGINX_IMAGE}'
    ports:
      - '80:80'
    depends_on:
      - website
    restart: always
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So for this tutorial will use Github packages for hosting the images.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 4: Automating Deployment with GitHub Actions&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Create a GitHub Actions workflow file at &lt;code&gt;.github/workflows/deploy.yml&lt;/code&gt; in the root of the project.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;name: Continuous Integration and Delivery

on: 
  push:
    branches: [main]
env:
  NEXT_APP_WEBSITE_IMAGE: ghcr.io/$(echo $GITHUB_REPOSITORY | tr '[:upper:]' '[:lower:]')/website
  NEXT_APP_NGINX_IMAGE: ghcr.io/$(echo $GITHUB_REPOSITORY | tr '[:upper:]' '[:lower:]')/nginx
  REGISTRY: ghcr.io
jobs:
  build:
    name: Build Docker Images
    runs-on: ubuntu-latest
    steps:
      - name: Checkout main
        uses: actions/checkout@v3

      - name: Set environment variables
        run: |
          echo &quot;NEXT_APP_WEBSITE_IMAGE=$(echo ${{env.NEXT_APP_WEBSITE_IMAGE}} )&quot; &amp;gt;&amp;gt; $GITHUB_ENV
          echo &quot;NEXT_APP_NGINX_IMAGE=$(echo ${{env.NEXT_APP_NGINX_IMAGE}} )&quot; &amp;gt;&amp;gt; $GITHUB_ENV
      - name: Log in to GitHub Packages
        env:
          PERSONAL_ACCESS_TOKEN: ${{ secrets.PERSONAL_ACCESS_TOKEN }}
        run: echo ${PERSONAL_ACCESS_TOKEN} | docker login ghcr.io -u ${{ secrets.NAMESPACE }} --password-stdin

      - name: Build images
        run: |
          docker compose -f docker-compose.ci.yml build
      - name: Push images
        run: |
          docker push ${{ env.NEXT_APP_WEBSITE_IMAGE }}
          docker push ${{ env.NEXT_APP_NGINX_IMAGE }}
  deploy:
    name: Deploy to AWS EC2
    runs-on: ubuntu-latest
    needs: build
    if: github.ref == 'refs/heads/main'
    steps:
      - name: Checkout main
        uses: actions/checkout@v3
      - name: Add environment variables to .env
        run: |
          echo NEXT_APP_WEBSITE_IMAGE=${{ env.NEXT_APP_WEBSITE_IMAGE }} &amp;gt;&amp;gt; .env
          echo NEXT_APP_NGINX_IMAGE=${{ env.NEXT_APP_NGINX_IMAGE }} &amp;gt;&amp;gt; .env
          echo NAMESPACE=${{ secrets.NAMESPACE }} &amp;gt;&amp;gt; .env
          echo PERSONAL_ACCESS_TOKEN=${{ secrets.PERSONAL_ACCESS_TOKEN }} &amp;gt;&amp;gt; .env
      - name: Add the private SSH key to the ssh-agent
        env:
          SSH_AUTH_SOCK: /tmp/ssh_agent.sock
        run: |
          mkdir -p ~/.ssh
          ssh-agent -a $SSH_AUTH_SOCK &amp;gt; /dev/null
          ssh-keyscan github.com &amp;gt;&amp;gt; ~/.ssh/known_hosts
          ssh-add - &amp;lt;&amp;lt;&amp;lt; &quot;${{ secrets.PRIVATE_KEY }}&quot;
      - name: Deploy images on AWS EC2
      
        env:
          SSH_AUTH_SOCK: /tmp/ssh_agent.sock

        run: |
          scp -o StrictHostKeyChecking=no -r ./.env ./docker-compose.prod.yml ${{secrets.AWS_HOST_USER}}@${{ secrets.AWS_EC2_IP_ADDRESS }}:
          ssh -o StrictHostKeyChecking=no ${{secrets.AWS_HOST_USER}}@${{ secrets.AWS_EC2_IP_ADDRESS }} &amp;lt;&amp;lt; EOF
              docker-compose down --rmi all -v
              docker login ghcr.io -u ${{secrets.NAMESPACE}} -p ${{secrets.PERSONAL_ACCESS_TOKEN}}
              docker pull $WEBSITE_IMAGE
              docker pull $NGINX_IMAGE 
              docker-compose --env-file=.env -f docker-compose.prod.yml up -d
              docker logout
          EOF
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Please make sure your on &lt;code&gt;main branch&lt;/code&gt; because the workflow’s can only trigger on the &lt;code&gt;main&lt;/code&gt; branch other you can it to your preferences.&lt;/p&gt;
&lt;p&gt;Workflow successfully finished :&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://coderlegion.com/?qa=blob&amp;amp;qa_blobid=4617544689212946738&quot; alt=&quot;workflow&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://coderlegion.com/?qa=blob&amp;amp;qa_blobid=1806442423346209046&quot; alt=&quot;website&quot;&gt;&lt;/p&gt;
&lt;p&gt;  By following these steps, you have successfully deployed a Next.js application on AWS EC2 using Docker and NGINX, with automated deployments using GitHub Actions. You can further enhance this setup by integrating SSL certificates with Let’s Encrypt and using AWS services like RDS or S3 for storage.&lt;/p&gt;
&lt;p&gt;If you would like to improve your skills, click on the following link on &lt;a rel=&quot;nofollow&quot; href=&quot;https://www.patreon.com/kilamaelie/shop/master-react-app-deployment-aws-ec2-53-1089307?utm_medium=clipboard_copy&amp;amp;utm_source=copyLink&amp;amp;utm_campaign=productshare_creator&amp;amp;utm_content=join_link&quot;&gt;Master React App Deployment: AWS EC2, Route 53, SSL &amp;amp; GitHub Actions,A comprehensive manual which walks you through the deployment process, leveraging the power of Docker, AWS EC2, Route 53, SSL encryption and GitHub actions to build a robust CI/CD pipeline&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Keep exploring, stay curious and keep building on this foundation to create even more sophisticated and powerful projects. Happy coding!&lt;/p&gt;
&lt;p&gt;Thanks for reading through and I hope you liked what you read here. Feel free to connect with me on &lt;a rel=&quot;nofollow&quot; href=&quot;https://kilamaelie.dev&quot;&gt;portfolio&lt;/a&gt;,&lt;a rel=&quot;nofollow&quot; href=&quot;https://www.linkedin.com/in/kilamaelie/&quot;&gt;LinkedIn&lt;/a&gt;, &lt;a rel=&quot;nofollow&quot; href=&quot;https://x.com/kilamaelie&quot;&gt;twitter&lt;/a&gt; and &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/kilamaelie&quot;&gt;GitHub.&lt;/a&gt;&lt;/p&gt;
</description>
<category>CI/CD Pipelines</category>
<guid isPermaLink="true">https://coderlegion.com/5757/deploy-a-next-js-app-on-aws-ec2-with-docker-nginx-and-automate-with-github-actions</guid>
<pubDate>Mon, 29 Sep 2025 12:54:42 +0000</pubDate>
</item>
<item>
<title>Deploy a ReactJS App to AWS EC2 with Docker, NGINX, and Automate with GitHub Actions part One</title>
<link>https://coderlegion.com/3478/deploy-a-reactjs-app-to-aws-ec2-with-docker-nginx-and-automate-with-github-actions-part-one</link>
<description>&lt;p&gt;In today’s digital landscape, master the art of building, deploying and automating ReactJS Apps using Docker, NGINX and GitHub actions on AWS EC2. Dive into this comprehensive guide and transform your coding journey into an adventure of innovation, efficiency and cutting-edge technologies.&lt;/p&gt;
&lt;p&gt;Table of Contents&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Prerequisites&lt;/li&gt;
&lt;li&gt;Setting Up the Project&lt;/li&gt;
&lt;li&gt;Dockerizing the ReactJS application&lt;/li&gt;
&lt;li&gt;Setting up NGINX&lt;/li&gt;
&lt;li&gt;Automating deployment with GitHub Actions on AWS EC2&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;1. Prerequisites&lt;/strong&gt;&lt;br&gt;
Before diving into this project, which involves several technologies and concepts, you need a solid grounding in the following areas to ensure successful learning and implementation such as:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Basic Web development: A good understanding of HTML, CSS and&lt;br&gt;
JavaScript is essential, as ReactJS is a JavaScript library for&lt;br&gt;
building user interfaces.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Git and version control: A good knowledge of Git and version control&lt;br&gt;
concepts will help you manage your code base and collaborate&lt;br&gt;
effectively.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Docker: Understanding containerization for docker is crucial to&lt;br&gt;
packaging your application and its dependencies in isolated&lt;br&gt;
containers&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;NGINX: A basic knowledge of NGINX as a web server and reverse proxy&lt;br&gt;
will be necessary to set up the server environment.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Remember, while these requirements are essentials, you don’t need to be an expert in every area. You can learn and develop your expertise as you go along. What’s more, official documentation, online tutorials and communities can provide invaluable support as you learn.&lt;/p&gt;
&lt;p&gt;Note that you can find the link of final source code in the &lt;a rel=&quot;nofollow&quot; href=&quot;https://coderlegion.com/?qa=blob&amp;amp;qa_blobid=9034001942458065209&quot;&gt;build and deploy-reactApp to-aws ec2 via github-actions&lt;/a&gt; repository.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2. Setting Up the Project&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;This involves several steps which including the installation, project structure and other basic configuration, here’s a step-by-step guide helping you get started :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Install Node.js and npm:&lt;br&gt;
Before you begin, make sure Node.js and npm ( Node Package Managers) are installed on your system. You can download them from the official website: &lt;a rel=&quot;nofollow&quot; href=&quot;https://coderlegion.com/3479/deploy-a-reactjs-app-to-aws-ec2-with-docker-nginx-and-automate-with-github-actions-part-two&quot;&gt;https://nodejs.org&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;ul&gt;
&lt;li&gt;Create a New Project:&lt;br&gt;
Open your terminal and navigate to the directory where you want to create the project, for the purpose of this tutorial we’ll create a directory with a name &lt;code&gt;react-tutorial-app&lt;/code&gt; or you can name it anything depending on your project name. This folder is considered as the root directory for our application which contains all folders and files structures.&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;&lt;p&gt;In software development, “project structure” provides a clear and&lt;br&gt;
logical layout that helps developers understand and navigate the&lt;br&gt;
codebase more easily. A well-designed project structure promotes&lt;br&gt;
maintainability, collaboration, and efficient development.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Then, we will change our directory into the react-tutorial-app folder and all other parts of configuration files or folders will be in this folder.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;mkdir react-tutorial-app
cd react-tutorial-app
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Inside the react-tutorial-app folder, to create a new React project runs the following command using create-react-app and for more details on how create-react-app works and other staff, please visit the official website: [https://create-react-app.dev/][3]&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;npx create-react-app your-app-name # website is our app-name or folder name 
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;create-react-app&lt;/code&gt; is a command-line tool that allows you to quickly and easily set up a new &lt;code&gt;Reactjs&lt;/code&gt; Application, this boilerplate setup generates a basic project structure, including essential files and configuration needed to start building a React application.&lt;/p&gt;
&lt;p&gt;Let’s change the directory into website as our &lt;code&gt;app-name&lt;/code&gt; for React application.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cd website # app-name 
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To start the development server and preview your React app, use the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;npm start
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;&lt;p&gt;&lt;em&gt;This command will initiate the development server, which will compile your React code, bundle assets, and start a local web server to serve&lt;br&gt;
your application. It will also open your app in your default web&lt;br&gt;
browser automatically.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Once the development server is up and running, you can access your React app by visiting &lt;code&gt;http://localhost:3000&lt;/code&gt; in your web browser. So well done ???? for creating a React application and setting up the project.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3. Dockerizing the ReactJS application&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Docker provides a standardized way to package and distribute applications, making it easier to deploy and manage across different environments. In this section, we’ll containerize our ReactJS application using Docker.&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;&lt;em&gt;If you haven’t already, install Docker on your machine by following the instructions for your operating system:&lt;br&gt;
&lt;a rel=&quot;nofollow&quot; href=&quot;https://docs.docker.com/get-docker/&quot;&gt;https://docs.docker.com/get-docker/&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In your React app’s root directory, create a file named Dockerfile. This file defines the instructions to build your Docker image.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# Use an official Node.js runtime as the base image

FROM node:19.6.0-alpine
# Set the working directory within the container
WORKDIR /website

# Copy package.json and package-lock.json to the container
COPY package*.json ./

# Install dependencies
RUN npm install

# Copy the rest of the application code to the container
COPY . .

# Build the React app
EXPOSE 3000
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Since in this project will have more than one container , then we ‘ll need to use &lt;code&gt;docker-compose&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Docker-compose&lt;/strong&gt; : allows you to define and run multiple Docker containers as a single service, making it easier to manage complex applications.&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;&lt;em&gt;If you haven’t already, you’ll need to install Docker Compose. Follow the installation instructions for your operating system:&lt;br&gt;
[https://docs.docker.com/compose/install/][4]&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In your project’s root directory as &lt;code&gt;react-tutorial-app&lt;/code&gt;, create a file named &lt;code&gt;docker-compose.yml&lt;/code&gt;. This file will contain the configuration for your multi-container application.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;services:
  website:
    build:
      context: ./website
      dockerfile: Dockerfile
    command: npm start
    ports:
      - &quot;3000:3000&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This defines only one service website but a bit later more will be added. So in order to test it, just go in your terminal, navigate to the directory containing the &lt;code&gt;docker-compose.yml&lt;/code&gt; file and run:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker-compose up
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Docker Compose will build the required images and start the defined containers. You’ll see logs from both services in the terminal and also depending on your configuration, you can access your ReactJS app at &lt;code&gt;http://localhost:3000&lt;/code&gt; . Kill the task in the terminal where &lt;code&gt;docker-compose up&lt;/code&gt; is running in order to stop the. To remove the containers and their associated resources, run:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker-compose rm -v
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;4. Setting up NGINX&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;NGINX is a reverse proxy to serve the built static files of your React application. This setup is commonly used to improve performance and manage routing in production environments.&lt;/p&gt;
&lt;p&gt;In the root of your project directory, create a Nginx directory named &lt;code&gt;nginx&lt;/code&gt; then create a configuration file named nginx.conf . So inside &lt;code&gt;nginx.conf&lt;/code&gt; file adds the following configuration:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;server {
     listen 80;
     server_name localhost; 
     #server_name can add your domain or Ip address for your server in the production
 
     location / {
         root /usr/share/nginx/html/website;
         try_files $uri $uri/ /index.html;
     }
 }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;in the same directory as your Nginx, create a &lt;code&gt;Dockerfile&lt;/code&gt; which defines how to build a custom Nginx Docker Image:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# Use an official Nginx image as the base image
FROM nginx:latest

# Remove any existing config files
RUN rm /etc/nginx/conf.d/*

# Copy the custom Nginx configuration
COPY nginx.conf /etc/nginx/conf.d/

# Expose port 80 for Nginx
EXPOSE 80
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Before testing in development, let’s update our docker-compose file by adding the Nginx service&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;services:
website:
  build:
    context: ./website
    dockerfile: Dockerfile
  volumes:
   - website:/website/build/  # build files will be added at this directory !!!

nginx:
  build:
   context: ./nginx
   dockerfile: Dockerfile
  ports:
    - &quot;80:80&quot;
  volumes:
     - website:/usr/share/nginx/html/website # Copy React App's build files to the Nginx directory

volumes:
   website:
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And also update the &lt;code&gt;Dockerfile&lt;/code&gt; for the react app in the website directory&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# Use an official Node.js runtime as the base image

FROM node:19.6.0-alpine
# Set the working directory within the container
WORKDIR /website

# Copy package.json and package-lock.json to the container
COPY package*.json ./

# Install dependencies
RUN npm install

# Copy the rest of the application code to the container
COPY . .

# Build the React app
RUN npm run build

# Build the React app
EXPOSE 3000
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For the purpose of testing if everything works, we’ll open a terminal and navigate to your &lt;code&gt;root&lt;/code&gt; directory. Run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker-compose up  # 
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then let’s testing at &lt;a rel=&quot;nofollow&quot; href=&quot;http://localhost:80&quot;&gt;http://localhost:80&lt;/a&gt; or &lt;a rel=&quot;nofollow&quot; href=&quot;http://127.0.0.1:80&quot;&gt;http://127.0.0.1:80&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Kill the task in the terminal where the container is running. To remove the container and its associated resources, run:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker-compose rm -v
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, let’s create &lt;code&gt;docker-compose.ci&lt;/code&gt; and &lt;code&gt;docker-compose.prod&lt;/code&gt; files for the production and workflow purpose in the root directory of the project&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Docker-compose.ci&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;services:
  website:
    build:
      context: ./website
      dockerfile: Dockerfile
    cache_from:
        - '${WEBSITE_IMAGE}'
    image: '${WEBSITE_IMAGE}'
    ports:
      - &quot;3000:3000&quot;
    volumes:
      - website:./website/build/  # build files will be added at this directory !!!

  nginx:
    build:
     context: ./nginx
     dockerfile: Dockerfile
    cache_from:
        - '${NGINX_IMAGE}'
    image: '${NGINX_IMAGE}'
    ports:
      - &quot;80:80&quot;
    volumes:
      - website:/usr/share/nginx/html/website # Copy React App's build files to the Nginx directory
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;Docker-compose.prod&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;services:
  website:
    container_name: 'website'
    image: '${WEBSITE_IMAGE}'
    ports:
      - &quot;3000:3000&quot;
    volumes:
      - website:./website/build/  # build files will be added at this directory !!!
  
  nginx:
    container_name: 'nginx'
    image: '${NGINX_IMAGE}'
    ports:
      - &quot;80:80&quot;
    volumes:
      - website:/usr/share/nginx/html/website # Copy React App's build files to the Nginx directory

volumes:
  website:
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So for this tutorial will use Github packages for hosting the images.&lt;/p&gt;
&lt;p&gt;[GitHub Package Registry][5] is a package hosting service provided by GitHub. It allows you to publish, share, and manage software packages directly within your GitHub repositories.&lt;/p&gt;
&lt;p&gt;It lets you host your software, either publicly or privately, for use in your projects on GitHub.&lt;/p&gt;
&lt;p&gt;Click on the link for the &lt;a rel=&quot;nofollow&quot; href=&quot;https://coderlegion.com/3479/deploy-a-reactjs-app-to-aws-ec2-with-docker-nginx-and-automate-with-github-actions-part-two&quot;&gt;part two&lt;/a&gt;&lt;/p&gt;
</description>
<category>CI/CD Pipelines</category>
<guid isPermaLink="true">https://coderlegion.com/3478/deploy-a-reactjs-app-to-aws-ec2-with-docker-nginx-and-automate-with-github-actions-part-one</guid>
<pubDate>Wed, 25 Jun 2025 17:01:32 +0000</pubDate>
</item>
<item>
<title>Deploy a ReactJS App to AWS EC2 with Docker, NGINX, and Automate with GitHub Actions part two</title>
<link>https://coderlegion.com/3479/deploy-a-reactjs-app-to-aws-ec2-with-docker-nginx-and-automate-with-github-actions-part-two</link>
<description>&lt;p&gt;&lt;strong&gt;AWS Setup&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Let’s start by setting up an EC2 instance to deploy our application. To do this, and you’ll need to open an &lt;a rel=&quot;nofollow&quot; href=&quot;https://aws.amazon.com/&quot;&gt;AWS&lt;/a&gt; account (if you don’t already have one).&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;If you don’t know how to set up AWS EC2 , please visit this link which&lt;br&gt;
will guide you through how to : &lt;a rel=&quot;nofollow&quot; href=&quot;https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/get-set-up-for-amazon-ec2.html&quot;&gt;launch EC2&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Once we’ve finished configuring AWS EC2 and the instance is up and running, we can install Docker on it.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;So connect via SSH into the instance using your Key Pair as :

$ ssh -i your-key-pair.pem ec2-user@&amp;lt;PUBLIC-IP-ADDRESS&amp;gt;

#example 
# ssh -i ~./ssh/react-tutorial.perm ec2-user@54.201.189.94
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After accessing the instance, start by updating the server package and installing the latest version of Docker and &lt;code&gt;Docker-compose&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[ec2-user]$ sudo yum update -y
[ec2-user]$ sudo yum install -y docker
[ec2-user]$ sudo service docker start
[ec2-user]$ sudo curl -L https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m) -o /usr/local/bin/docker-compose
[ec2-user]$ sudo chmod +x /usr/local/bin/docker-compose

[ec2-user]$ docker --version
Docker version 20.10.23, build 7155243

[ec2-user]$ docker-compose --version
Docker Compose version v2.18.1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Add the &lt;code&gt;ec2-user&lt;/code&gt; to the docker &lt;code&gt;group&lt;/code&gt; so that you can use it without running the Docker command with sudo :&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[ec2-user]$ sudo usermod -a -G docker ec2-user
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next, let’s generate the SSH KEY&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[ec2-user]$ ssh-keygen -t rsa
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;&lt;p&gt;Please! save the Key without setting any password&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Next, copy the public key into the authorized_keys file and set the appropriate authorizations.:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[ec2-user]$ cat ~/.ssh/id_rsa.pub 
# Copy this public key into ~/.ssh/authorized_keys
[ec2-user]$ vi ~/.ssh/authorized_keys
# After adding the public key into authorized_key then exits  from vi text editor 
# Then add these commands are used to change the permissions of these files 
[ec2-user]$ chmod 600 ~/.ssh/authorized_keys
[ec2-user]$ chmod 600 ~/.ssh/id_rsa
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, copy the contents of the private key&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[ec2-user]$ cat ~/.ssh/id_rsa

# Copy the private key somewhere for later use
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;5. Automating Deployment with GitHub Actions to AWS EC2&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;It is an integrated continuous integration and continuous deployment (CI / CD) platform provided by GitHub .&lt;/p&gt;
&lt;p&gt;Since our workflow will use GitHub’s core features (GitHub packages), GitHub requires you to create an access token, which will be used as a GitHub user ID for all your interactions.&lt;/p&gt;
&lt;p&gt;Go to the &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/settings/tokens&quot;&gt;Personal access tokens area&lt;/a&gt; in the Developer settings of your GitHub profile and click Generate new token.&lt;br&gt;
&lt;img src=&quot;https://coderlegion.com/?qa=blob&amp;amp;qa_blobid=15261576398792202104&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;To configure &lt;a rel=&quot;nofollow&quot; href=&quot;https://docs.github.com/en/actions&quot;&gt;GitHub Actions&lt;/a&gt;, start by adding a new directory called &lt;code&gt;.github&lt;/code&gt; to the root of your project, then within this directory, add another directory called &lt;code&gt;workflows&lt;/code&gt;. &lt;br&gt;
Now to configure the workflow, which is a set of one or more jobs, create a new file in the workflows directory called &lt;code&gt;main.yml&lt;/code&gt; . &lt;br&gt;
You can also run the following command in your root directory.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;mkdir .github &amp;amp;&amp;amp; cd .github
mkdir workflows &amp;amp;&amp;amp; cd workflows
touch main.yml
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;main.yml&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;name: Continuous Integration and Delivery

on:
  push:
    branches: [main]

env:
  #
  WEBSITE_IMAGE: ghcr.io/$(echo $GITHUB_REPOSITORY | tr '[:upper:]' '[:lower:]')/website
  NGINX_IMAGE: ghcr.io/$(echo $GITHUB_REPOSITORY | tr '[:upper:]' '[:lower:]')/nginx
  REGISTRY: ghcr.io

jobs:
  build:
    name: Build the Docker Image
    runs-on: ubuntu-latest

    steps:
      - name: checkout main
        uses: actions/checkout@v3

      - name: Set environment variables to .env
        run: |
          echo &quot;WEBSITE_IMAGE=$(echo ${{env.WEBSITE_IMAGE}} )&quot; &amp;gt;&amp;gt; $GITHUB_ENV
          echo &quot;NGINX_IMAGE=$(echo ${{env.NGINX_IMAGE}} )&quot; &amp;gt;&amp;gt; $GITHUB_ENV
      - name: Log in to GitHub Packages
        env:
          PERSONAL_ACCESS_TOKEN: ${{ secrets.PERSONAL_ACCESS_TOKEN }}
        run: echo ${PERSONAL_ACCESS_TOKEN} | docker login ghcr.io -u ${{ secrets.NAMESPACE }} --password-stdin

      - name: Pull images
        run: |
          docker pull ${{ env.WEBSITE_IMAGE }} || true
          docker pull ${{ env.NGINX_IMAGE }} || true
      - name: Build images
        run: |
          docker compose -f docker-compose.ci.yml build
      - name: Push images
        run: |
          docker push ${{ env.WEBSITE_IMAGE }}
          docker push ${{ env.NGINX_IMAGE }}
  checking-secrets:
    name: Checking secrets
    runs-on: ubuntu-latest
    needs: build
    outputs:
      secret_key_exists: ${{steps.check_secrets.outputs.defined}}
    steps:
      - name: Check for Secrets availabilities
        id: check_secrets
        shell: bash
        run: |
          if [[ -n &quot;${{ secrets.PRIVATE_KEY }}&quot; &amp;amp;&amp;amp; -n &quot;${{secrets.AWS_EC2_IP_ADDRESS}}&quot; &amp;amp;&amp;amp; -n &quot;${{secrets.AWS_HOST_USER}}&quot; ]]; then
            echo &quot;defined=true&quot; &amp;gt;&amp;gt; $GITHUB_OUTPUT;
          else
            echo &quot;defined=false&quot; &amp;gt;&amp;gt; $GITHUB_OUTPUT;
          fi
  deploy:
    name: Deploy to AWS EC2
    runs-on: ubuntu-latest
    needs: checking-secrets
    if: needs.checking-secrets.outputs.secret_key_exists == 'true'
    steps:
      - name: Checkout main
        uses: actions/checkout@v3

      - name: Add environment variables to .env
        run: |
          echo WEBSITE_IMAGE=${{ env.WEBSITE_IMAGE }} &amp;gt;&amp;gt; .env
          echo NGINX_IMAGE=${{ env.NGINX_IMAGE }} &amp;gt;&amp;gt; .env
          echo NAMESPACE=${{ secrets.NAMESPACE }} &amp;gt;&amp;gt; .env
          echo PERSONAL_ACCESS_TOKEN=${{ secrets.PERSONAL_ACCESS_TOKEN }} &amp;gt;&amp;gt; .env
      - name: Add the private SSH key to the ssh-agent
        env:
          SSH_AUTH_SOCK: /tmp/ssh_agent.sock
        run: |
          mkdir -p ~/.ssh
          ssh-agent -a $SSH_AUTH_SOCK &amp;gt; /dev/null
          ssh-keyscan github.com &amp;gt;&amp;gt; ~/.ssh/known_hosts
          ssh-add - &amp;lt;&amp;lt;&amp;lt; &quot;${{ secrets.PRIVATE_KEY }}&quot;
      - name: Deploy images on AWS EC2
        env:
          SSH_AUTH_SOCK: /tmp/ssh_agent.sock

        run: |
          scp -o StrictHostKeyChecking=no -r ./.env ./docker-compose.prod.yml ${{secrets.AWS_HOST_USER}}@${{ secrets.AWS_EC2_IP_ADDRESS }}:
          ssh -o StrictHostKeyChecking=no ${{secrets.AWS_HOST_USER}}@${{ secrets.AWS_EC2_IP_ADDRESS }} &amp;lt;&amp;lt; EOF
              docker-compose down --rmi all -v 
              docker login ghcr.io -u ${{secrets.NAMESPACE}} -p ${{secrets.PERSONAL_ACCESS_TOKEN}}
              docker pull $WEBSITE_IMAGE
              docker pull $NGINX_IMAGE 
              docker-compose --env-file=.env -f docker-compose.prod.yml up -d
              docker logout
          EOF
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Find the complete &lt;a rel=&quot;nofollow&quot; href=&quot;https://gist.github.com/kilamaelie/d08bd6493e8b4a430bf5ca2f166ac6ad&quot;&gt;gist&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;So, in the &lt;code&gt;main.yml&lt;/code&gt; we define :&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;set the environment variables&lt;/li&gt;
&lt;li&gt;Three jobs to run:&lt;br&gt;
 a. build job consist of:&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;Set various environment variables&lt;/li&gt;
&lt;li&gt;Login in the Github package by using the PERSONAL_ACCESS_TOKEN created&lt;/li&gt;
&lt;li&gt;Pull images for caching, build the images and push to Github Registry&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;  b. checking-secret consist of :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;checking if the deploy variables are existing&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;&lt;p&gt;Notes about the secrets&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;secrets.PERSONAL_ACCESS_TOKEN&lt;/li&gt;
&lt;li&gt;secrets.NAMESPACE&lt;/li&gt;
&lt;li&gt;secrets.PRIVATE_KEY&lt;/li&gt;
&lt;li&gt;secret.AWS_EC2_IP_ADDRESS&lt;/li&gt;
&lt;li&gt;secrets.AWS_HOST_USER&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;All of the secrets need to be set in your repository’s &lt;a rel=&quot;nofollow&quot; href=&quot;https://help.github.com/en/actions/configuring-and-managing-workflows/creating-and-storing-encrypted-secrets#creating-encrypted-secrets&quot;&gt;secrets&lt;/a&gt; (Settings &amp;gt; Secrets) and use your Github username or your organization name as your NAMESPACE and your personal access token as PERSONAL_ACCESS_TOKEN .&lt;/p&gt;
&lt;p&gt;  c. deploy job consist of:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Add the environment variable to .env file which will be created on the AWS EC2 instance.&lt;/li&gt;
&lt;li&gt;Add the private key to ssh-agent for password less.&lt;/li&gt;
&lt;li&gt;Deploy the build the images on AWS EC2 instance.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Once you are done, commit and push your code to the Github to trigger the workflow to run, so now you should see the images in the Github Packages.&lt;/p&gt;
&lt;p&gt;Please make sure your on &lt;code&gt;main branch&lt;/code&gt; because the workflow’s can only trigger on the &lt;code&gt;main&lt;/code&gt; branch other you can it to your preferences.&lt;/p&gt;
&lt;p&gt;Workflow successfully finished :&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://coderlegion.com/?qa=blob&amp;amp;qa_blobid=17531408084622768069&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Once all our jobs have been executed, navigate to the IP of your instance, and you should see the React application running :&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://coderlegion.com/?qa=blob&amp;amp;qa_blobid=12091261597270377422&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt; And there you have it, this guide has equipped you with the skills you need to successfully build, deploy and automate ReactJS applications using Docker, NGINX and GitHub Actions on AWS EC2.&lt;/p&gt;
&lt;p&gt;If you would like to improve your skills, click on the following link on &lt;a rel=&quot;nofollow&quot; href=&quot;https://www.patreon.com/kilamaelie/shop/master-react-app-deployment-aws-ec2-53-1089307?utm_medium=clipboard_copy&amp;amp;utm_source=copyLink&amp;amp;utm_campaign=productshare_fan&amp;amp;utm_content=join_link&quot;&gt;Master React App Deployment: AWS EC2, Route 53, SSL &amp;amp; GitHub Actions,A comprehensive manual which walks you through the deployment process, leveraging the power of Docker, AWS EC2, Route 53, SSL encryption and GitHub actions to build a robust CI/CD pipeline&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Keep exploring, stay curious and keep building on this foundation to create even more sophisticated and powerful projects. Happy coding!&lt;/p&gt;
&lt;p&gt;Thanks for reading through and I hope you liked what you read here. Feel free to connect with me on &lt;a rel=&quot;nofollow&quot; href=&quot;https://www.linkedin.com/in/kilamaelie/&quot;&gt;LinkedIn&lt;/a&gt;, &lt;a rel=&quot;nofollow&quot; href=&quot;https://twitter.com/kilamaelie&quot;&gt;twitter&lt;/a&gt; and &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/kilamaelie&quot;&gt;GitHub&lt;/a&gt;&lt;/p&gt;
</description>
<category>CI/CD Pipelines</category>
<guid isPermaLink="true">https://coderlegion.com/3479/deploy-a-reactjs-app-to-aws-ec2-with-docker-nginx-and-automate-with-github-actions-part-two</guid>
<pubDate>Wed, 25 Jun 2025 17:01:06 +0000</pubDate>
</item>
</channel>
</rss>