Skip to main content

Express AWS Deployment

Introduction

Deploying your Express.js applications to Amazon Web Services (AWS) allows you to leverage one of the most robust and scalable cloud infrastructures available today. AWS provides multiple deployment options for Node.js applications, each with its own advantages depending on your specific needs.

In this guide, we'll explore how to deploy an Express application to three popular AWS services:

  1. Amazon EC2 (virtual machines)
  2. AWS Elastic Beanstalk (platform as a service)
  3. AWS Lambda (serverless)

By the end of this tutorial, you'll understand how to choose the right AWS service for your Express application and deploy it successfully.

Prerequisites

Before getting started, make sure you have:

  • A basic Express.js application ready to deploy
  • An AWS account (free tier is sufficient for this tutorial)
  • Node.js and npm installed locally
  • AWS CLI installed and configured (for some deployment methods)
  • Basic understanding of Express.js

Option 1: Deploy Express to Amazon EC2

Amazon EC2 (Elastic Compute Cloud) provides virtual machines where you can deploy your Express applications with full control over the server environment.

Step 1: Set Up an EC2 Instance

  1. Log in to the AWS Management Console
  2. Navigate to the EC2 service
  3. Click "Launch Instance"
  4. Choose an Amazon Linux or Ubuntu AMI
  5. Select a t2.micro instance (free tier eligible)
  6. Configure security groups to allow HTTP (port 80), HTTPS (port 443), and SSH (port 22)
  7. Create or select an existing key pair for SSH access
  8. Launch the instance

Step 2: Connect to Your EC2 Instance

Use SSH to connect to your instance:

bash
ssh -i /path/to/your-key-pair.pem ec2-user@your-instance-public-dns

For Ubuntu instances, use ubuntu instead of ec2-user.

Step 3: Install Node.js and Dependencies

For Amazon Linux:

bash
# Update package lists
sudo yum update -y

# Install Node.js
curl -fsSL https://rpm.nodesource.com/setup_16.x | sudo bash -
sudo yum install -y nodejs

# Install PM2 globally (process manager)
sudo npm install pm2 -g

For Ubuntu:

bash
# Update package lists
sudo apt update

# Install Node.js
curl -fsSL https://deb.nodesource.com/setup_16.x | sudo -E bash -
sudo apt install -y nodejs

# Install PM2 globally
sudo npm install pm2 -g

Step 4: Transfer and Set Up Your Express Application

You can use Git, SCP, or other methods to transfer your application files:

bash
# If using Git
git clone https://github.com/yourusername/your-express-app.git
cd your-express-app
npm install

Step 5: Run Your Express App with PM2

PM2 helps keep your application running even after you disconnect from SSH:

bash
# Start your application with PM2
pm2 start app.js --name "express-app"

# Make PM2 start on system boot
pm2 startup
sudo env PATH=$PATH:/usr/bin pm2 startup systemd -u ec2-user --hp /home/ec2-user
pm2 save

NGINX can handle SSL termination and serve static files more efficiently:

bash
# Install NGINX
sudo yum install nginx -y # for Amazon Linux
# or
sudo apt install nginx -y # for Ubuntu

# Start and enable NGINX
sudo systemctl start nginx
sudo systemctl enable nginx

Create a config file for your Express app:

bash
sudo nano /etc/nginx/conf.d/express-app.conf

Add the following configuration:

nginx
server {
listen 80;
server_name your-domain.com www.your-domain.com;

location / {
proxy_pass http://localhost:3000; # Assuming Express runs on port 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;
}
}

Test and reload NGINX:

bash
sudo nginx -t
sudo systemctl reload nginx

Option 2: Deploy Express to AWS Elastic Beanstalk

Elastic Beanstalk is AWS's platform-as-a-service offering that handles infrastructure management for you.

Step 1: Prepare Your Express Application

Make sure your Express app has the following structure:

your-express-app/
├── app.js (or index.js)
├── package.json
├── node_modules/
└── other files and folders

Your package.json should have a start script:

json
{
"name": "your-express-app",
"version": "1.0.0",
"scripts": {
"start": "node app.js"
},
"dependencies": {
"express": "^4.17.1"
// other dependencies
}
}

Step 2: Install the Elastic Beanstalk CLI

bash
pip install awsebcli

Step 3: Initialize Elastic Beanstalk in Your Project

Navigate to your project directory and run:

bash
eb init

Follow the prompts to:

  • Select your AWS region
  • Create a new application or choose an existing one
  • Select Node.js as the platform
  • Set up SSH for your instances (optional)

Step 4: Create an Environment and Deploy

bash
eb create express-environment

This command creates a new environment and deploys your application. The process may take a few minutes.

Step 5: Monitor Your Deployment

bash
eb status

Once the deployment is complete, you can open your application:

bash
eb open

Step 6: Update Your Application When Needed

After making changes to your code, deploy the updates:

bash
eb deploy

Option 3: Deploy Express as Serverless with AWS Lambda

For simple APIs or applications with variable traffic, a serverless approach using AWS Lambda can be cost-effective.

Step 1: Install Serverless Framework

bash
npm install -g serverless

Step 2: Set Up a Serverless Express Project

Create a new directory for your serverless project and initialize it:

bash
mkdir serverless-express
cd serverless-express
npm init -y

Install the required dependencies:

bash
npm install express serverless-http aws-serverless-express

Step 3: Create Your Express Application

Create a file named app.js:

javascript
const express = require('express');
const app = express();

app.get('/', (req, res) => {
res.json({ message: 'Hello from Express on AWS Lambda!' });
});

app.get('/api/users', (req, res) => {
res.json([
{ id: 1, name: 'User 1' },
{ id: 2, name: 'User 2' }
]);
});

// Export for serverless use
module.exports = app;

Step 4: Create a Lambda Handler

Create a file named lambda.js:

javascript
const serverless = require('serverless-http');
const app = require('./app');

module.exports.handler = serverless(app);

Step 5: Create a Serverless Configuration

Create a file named serverless.yml:

yaml
service: serverless-express-app

provider:
name: aws
runtime: nodejs16.x
stage: dev
region: us-east-1

functions:
app:
handler: lambda.handler
events:
- http:
path: /
method: ANY
- http:
path: /{proxy+}
method: ANY

Step 6: Deploy to AWS Lambda

bash
serverless deploy

After deployment, the Serverless Framework will output the URL of your API Gateway endpoint, which you can use to access your Express application.

Real-World Example: Creating a Production-Ready Express API on AWS

Let's put it all together by creating a simple Express API for a book management system and deploying it to AWS Elastic Beanstalk.

Step 1: Create the Express Application

bash
mkdir books-api
cd books-api
npm init -y
npm install express cors helmet morgan dotenv

Create an app.js file:

javascript
const express = require('express');
const cors = require('cors');
const helmet = require('helmet');
const morgan = require('morgan');
require('dotenv').config();

const app = express();
const port = process.env.PORT || 3000;

// Middleware
app.use(cors());
app.use(helmet());
app.use(morgan('combined'));
app.use(express.json());

// In-memory database for demo
const books = [
{ id: 1, title: 'The Great Gatsby', author: 'F. Scott Fitzgerald' },
{ id: 2, title: '1984', author: 'George Orwell' },
{ id: 3, title: 'To Kill a Mockingbird', author: 'Harper Lee' }
];

// Routes
app.get('/', (req, res) => {
res.json({ message: 'Welcome to the Books API!' });
});

// Get all books
app.get('/api/books', (req, res) => {
res.json(books);
});

// Get a single book
app.get('/api/books/:id', (req, res) => {
const book = books.find(b => b.id === parseInt(req.params.id));
if (!book) return res.status(404).json({ message: 'Book not found' });
res.json(book);
});

// Add a new book
app.post('/api/books', (req, res) => {
const { title, author } = req.body;

if (!title || !author) {
return res.status(400).json({ message: 'Title and author are required' });
}

const newBook = {
id: books.length + 1,
title,
author
};

books.push(newBook);
res.status(201).json(newBook);
});

// Start server
app.listen(port, () => {
console.log(`Server running on port ${port}`);
});

module.exports = app; // For testing or serverless deployment

Step 2: Test Locally

bash
node app.js

Test the API with curl or Postman:

bash
# Get all books
curl http://localhost:3000/api/books

# Add a new book
curl -X POST http://localhost:3000/api/books \
-H "Content-Type: application/json" \
-d '{"title": "The Hobbit", "author": "J.R.R. Tolkien"}'

Step 3: Prepare for Elastic Beanstalk Deployment

Create a .ebignore file to specify files to exclude from deployment:

node_modules
.git
.env
*.log

Create a .npmrc file to ensure only production dependencies are installed:

production=true

Create a Procfile to specify how to start the application:

web: node app.js

Step 4: Deploy to Elastic Beanstalk

bash
eb init
# Follow the prompts
eb create books-api-production

Step 5: Configure Environment Variables (if needed)

bash
eb setenv DB_URL=your_database_url SECRET_KEY=your_secret_key

Step 6: Test the Deployed API

Once deployed, you can test the API using the provided Elastic Beanstalk URL:

bash
curl http://books-api-production.us-east-1.elasticbeanstalk.com/api/books

Choosing the Right AWS Deployment Option

When deciding which AWS service to use for your Express application, consider:

  1. Amazon EC2 - Best for:

    • Applications requiring full control over the infrastructure
    • Complex applications with specific server configuration needs
    • Long-running applications with consistent traffic
  2. AWS Elastic Beanstalk - Best for:

    • Teams that want to focus on code, not infrastructure
    • Applications that follow standard patterns
    • Scenarios where easy scaling and management are priorities
  3. AWS Lambda with API Gateway - Best for:

    • APIs with variable or unpredictable traffic
    • Microservices
    • Functions that execute quickly (under 15 minutes)
    • Minimizing costs for low-traffic applications

Summary

In this guide, we explored three main approaches to deploying Express.js applications on AWS:

  1. Using EC2 for maximum control, where we set up our own server environment with Node.js, PM2, and optional NGINX
  2. Using Elastic Beanstalk for managed infrastructure, which automatically handles capacity provisioning, load balancing, and scaling
  3. Using AWS Lambda for a serverless approach, which is ideal for APIs and functions with variable traffic

Each approach has its strengths, and the right choice depends on your specific requirements, team expertise, and application characteristics.

Additional Resources

Exercises

  1. Deploy a simple "Hello World" Express application to EC2 and set up a custom domain name for it.
  2. Modify the Books API example to use DynamoDB instead of in-memory storage and deploy it to Elastic Beanstalk.
  3. Create a serverless Express application that connects to an external API and deploy it to AWS Lambda.
  4. Set up a CI/CD pipeline using AWS CodePipeline to automatically deploy your Express application whenever you push to your GitHub repository.
  5. Add authentication to your API using Amazon Cognito and test it after deployment.


If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)