DEV Community

Cover image for Deploying a Node.js App to AWS Elastic Beanstalk with GitHub Actions: A Beginner's Guide
Samuel Owolabi
Samuel Owolabi

Posted on

Deploying a Node.js App to AWS Elastic Beanstalk with GitHub Actions: A Beginner's Guide

Automating Node.js Deployment to AWS Elastic Beanstalk with GitHub Actions

Automating the deployment of your applications can save you time and streamline your development process. This step-by-step guide will walk you through deploying a Node.js application to AWS Elastic Beanstalk and setting up a CI/CD pipeline using GitHub Actions. By the end, you'll have a fully automated workflow that tests and deploys your code every time you push to your main branch.

This tutorial is designed for beginners with a general familiarity with Git, GitHub, and AWS.

You can find the complete code for this tutorial in this GitHub repository.

What is AWS Elastic Beanstalk?

AWS Elastic Beanstalk is a service that makes it easier to deploy and manage applications in the AWS cloud. You simply upload your application, and Elastic Beanstalk automatically handles the deployment details of capacity provisioning, load balancing, auto-scaling, and application health monitoring.

Why use it?

  • Simplicity: It abstracts away the complexity of setting up servers, load balancers, and databases.
  • Scalability: It can automatically scale your application up or down based on demand.
  • Cost-Effective: With the AWS Free Tier, you can run a simple application like the one in this guide at no cost. You only pay for what you use as your application grows.

What is GitHub Actions?

GitHub Actions is a CI/CD (Continuous Integration/Continuous Deployment) platform that allows you to automate your build, test, and deployment pipeline. You can create workflows that build and test every pull request to your repository or deploy merged pull requests to production.

Our Workflow Structure:

  • Event: A trigger that starts the workflow, such as a push to a branch.
  • Jobs: A set of steps that execute on a runner. We will have a test job and a deploy job.
  • Steps: Individual tasks that run commands in a job.

Why Combine Elastic Beanstalk with GitHub Actions?

Combining these two powerful tools creates a seamless CI/CD pipeline. With every push to your repository, GitHub Actions will automatically test your Node.js application and, if the tests pass, deploy it to your Elastic Beanstalk environment. This automation eliminates manual deployment steps, reduces the risk of human error, and allows you to release new features faster.

Prerequisites

Before we start, make sure you have the following set up:

  • An AWS Account: You'll need an account with an IAM user that has permissions for Elastic Beanstalk. We'll create the necessary roles during the tutorial.
  • A GitHub Repository: This is where your Node.js application code will live. For this tutorial, we will be using a pre-configured repository.
  • Node.js: Ensure you have Node.js (version 18 or higher) installed on your local machine.

Let's Get Started!

Step 1: Set Up Your Node.js Application

To get you started quickly, a simple Node.js application using Express and TypeScript has been prepared.

  1. Clone the Repository: Open your terminal and clone the sample application:
   git clone https://github.com/samowolabi/nodejs-elastic-beanstalk-with-githubactions-app.git
   cd nodejs-elastic-beanstalk-with-githubactions-app
Enter fullscreen mode Exit fullscreen mode
  1. Install Dependencies:
   npm install
Enter fullscreen mode Exit fullscreen mode

This project has a straightforward structure:

  • .github/workflows/ci.yml: The GitHub Actions workflow file.
  • src/index.ts: The main application file.
  • test/app.test.js: A simple test file.
  • package.json: Defines project scripts and dependencies.
  • tsconfig.json: The TypeScript configuration file.

Step 2: Set Up AWS Elastic Beanstalk

Now, let's create the environment on AWS where our application will be deployed.

  1. Navigate to Elastic Beanstalk: Log in to your AWS Management Console and go to the Elastic Beanstalk service.

Image showing AWS Elastic Beanstalk Homepage

  1. Create a New Environment:
    • Click on Create Application.
    • Application name: Enter a name, for instance, nodejs-app-eb-gh-app.
    • Platform: Select Node.js. For this guide, "Node.js 18" is used.
    • Application code: Keep Sample application selected for now.
    • Under Presets, select Single instance (which is free-tier eligible).
    • Click Next.

Image showing Select Environment for the newly AWS Elastic Beanstalk Environment to be created

Image showing Enter Application Name for the newly AWS Elastic Beanstalk Environment to be created

Image showing Select Platform and Application Code for the newly AWS Elastic Beanstalk Environment to be created

  1. Configure Service Access: This screen is crucial for granting Elastic Beanstalk the necessary permissions.
  • Service role: This role allows Elastic Beanstalk to manage other AWS resources on your behalf.

    • If you don't have one, select Create and use new service role.
    • A new window will open to create an IAM role. The role will be pre-configured. Simply click Create role.
    • Back on the Elastic Beanstalk screen, refresh the dropdown and select the new role (aws-elasticbeanstalk-service-role).
  • EC2 instance profile: This role grants permissions to the EC2 instances that will run your application.

    • Click Create and use new instance profile.
    • In the new window, name your role (e.g., aws-elasticbeanstalk-ec2-new-role).
    • The necessary policies (AWSElasticBeanstalkWebTier, etc.) will be attached automatically. Click Create role.
    • Return to the Elastic Beanstalk screen, refresh, and select the newly created instance profile.

Image showing screen to configure Service Access on Create Application

  1. Review and Launch:
    • You can skip the networking, database, and tags setup for this simple deployment by clicking Skip to review.
    • On the Review page, look over your configurations and click Submit.

AWS will now start building your environment. This process can take a few minutes. Once it's complete, you can access the provided domain, and you will see the default sample application page.

Image showing AWS Elastic Beanstalk launched Environment

Bonus: Setting Up Environment Variables

Your Node.js application might require environment variables. You can set them up in the Elastic Beanstalk console:

  1. Go to your environment's page.
  2. Click Configuration > Software > Edit.
  3. Under Environment properties, add your key-value pairs (e.g., NODE_ENV = production). Elastic Beanstalk automatically provides the PORT variable.

Image showing setting Environment Properties (env) for the launched AWS Elastic Beanstalk Environment

Step 3: Configure the CI/CD Pipeline with GitHub Actions

Now it's time to connect your GitHub repository to your new Elastic Beanstalk environment.

  1. Get AWS Access Keys: The GitHub Actions workflow needs credentials to deploy to your AWS account.
  • In the AWS IAM console, navigate to Users and select your IAM user.
  • Go to the Security credentials tab and click Create access key.
  • Select Third-party service, acknowledge the recommendation, and proceed.
  • You will be provided with an Access key ID and a Secret access key. Copy these immediately, as you won't be able to see the secret key again.

Image showing how to create access key to receive Access Key ID and Secret Access Key Environment Properties (env) for the user on IAM Console

Note: Ensure your IAM user has the necessary permissions. For this deployment, the following policies are recommended: elasticbeanstalk:*, s3:*, ec2:*, iam:PassRole, and logs:*.

  1. Add Credentials to GitHub Secrets:
    • In your GitHub repository, go to Settings > Secrets and variables > Actions.
    • Click New repository secret and add the following:
      • AWS_ACCESS_KEY_ID: Your AWS access key ID.
      • AWS_SECRET_ACCESS_KEY: Your AWS secret access key.

Image showing how to add Credentials to GitHub Repository Secret

  1. Understand the Workflow File: Open the .github/workflows/ci.yml file in your repository. Let's break down what it does:
   name: CI/CD

   on:
     push:
       branches: [ main, master ]
     pull_request:
       branches: [ main, master ]

   jobs:
     test:
       runs-on: ubuntu-latest

       strategy:
         matrix:
           node-version: [18.x, 20.x]

       steps:
       - name: Checkout code
         uses: actions/checkout@v4

       - name: Setup Node.js ${{ matrix.node-version }}
         uses: actions/setup-node@v4
         with:
           node-version: ${{ matrix.node-version }}
           cache: 'npm'

       - name: Install dependencies
         run: npm ci

       - name: Run tests
         run: npm test

       - name: Build project
         run: npm run build

     deploy:
       needs: test
       runs-on: ubuntu-latest
       if: github.ref == 'refs/heads/main' && github.event_name == 'push'

       steps:
       - name: Checkout code
         uses: actions/checkout@v4

       - name: Setup Node.js
         uses: actions/setup-node@v4
         with:
           node-version: '20.x'
           cache: 'npm'

       - name: Install dependencies
         run: npm ci

       - name: Build project
         run: npm run build

       - name: Generate deployment package
         run: |
           zip -r deploy.zip . -x '*.git*' 'node_modules/.cache/*' 'src/*' 'test/*' '*.md' '.env*'

       - name: Deploy to Elastic Beanstalk
         uses: einaregilsson/beanstalk-deploy@v22
         with:
           aws_access_key: ${{ secrets.AWS_ACCESS_KEY_ID }}
           aws_secret_key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
           application_name: nodejs-app-eb-gh-app
           environment_name: Nodejs-app-eb-gh-app-env
           version_label: ${{ github.sha }}
           region: us-east-1
           deployment_package: deploy.zip
Enter fullscreen mode Exit fullscreen mode
  • on: This workflow triggers on a push or pull_request to the main or master branches.
  • jobs:
    • test: This job runs on two Node.js versions (18.x and 20.x). It checks out your code, installs dependencies, and runs your tests (npm test) and build script (npm run build).
    • deploy: This job depends on the test job succeeding (needs: test). It only runs on a push to the main branch. It performs the build again, zips the necessary files into deploy.zip, and then uses the beanstalk-deploy action to push the package to your Elastic Beanstalk environment.

Important: Update the application_name, environment_name, and region in the deploy job to match your Elastic Beanstalk setup.

Step 4: Deploy the Application

Now for the magic moment!

  1. Push to Main: Commit any changes you've made and push them to your main branch.
   git add .
   git commit -m "feat: setup CI/CD and deploy to Elastic Beanstalk"
   git push origin main
Enter fullscreen mode Exit fullscreen mode
  1. Monitor the Workflow: Go to the Actions tab in your GitHub repository. You will see your workflow running. Click on it to see the test and deploy jobs in action.

Image showing Github Actions Workflow, on this screenshot, test and deployment is successful

  1. Verify Deployment: Once the deploy job is complete, navigate back to your Elastic Beanstalk environment's URL. You should now see the message: "Hello, TypeScript with Express!".

Image showing how to retrieve your launched AWS Elastic Beanstalk Environment Domain

Image showing accessed domain to confirm that our Node JS is deployed successfully on AWS Elastic Beanstalk

Conclusion and Troubleshooting

Congratulations! You have successfully set up a fully automated CI/CD pipeline. Every time you push a change to your main branch, GitHub Actions will test your code and deploy it to AWS Elastic Beanstalk.

Common Issues:

  • Deployment Fails: Double-check that your AWS credentials in GitHub Secrets are correct and that the IAM user has the required permissions. Verify that the application and environment names in your ci.yml file match your Elastic Beanstalk setup exactly.
  • Build/Test Failures: Run npm test and npm run build locally to debug any issues before pushing.
  • Check Logs: The first place to look for errors is the GitHub Actions log. For environment-specific issues, check the logs in your AWS Elastic Beanstalk console (Logs > Request Logs > Last 100 Lines).

This automated workflow is a fundamental practice in modern web development that will significantly improve your development and release process.


A practical guide by Samuel Owolabi

Top comments (0)