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:
- Amazon EC2 (virtual machines)
- AWS Elastic Beanstalk (platform as a service)
- 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
- Log in to the AWS Management Console
- Navigate to the EC2 service
- Click "Launch Instance"
- Choose an Amazon Linux or Ubuntu AMI
- Select a t2.micro instance (free tier eligible)
- Configure security groups to allow HTTP (port 80), HTTPS (port 443), and SSH (port 22)
- Create or select an existing key pair for SSH access
- Launch the instance
Step 2: Connect to Your EC2 Instance
Use SSH to connect to your instance:
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:
# 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:
# 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:
# 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:
# 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
Step 6: Set Up NGINX as a Reverse Proxy (Optional but Recommended)
NGINX can handle SSL termination and serve static files more efficiently:
# 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:
sudo nano /etc/nginx/conf.d/express-app.conf
Add the following configuration:
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:
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:
{
"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
pip install awsebcli
Step 3: Initialize Elastic Beanstalk in Your Project
Navigate to your project directory and run:
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
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
eb status
Once the deployment is complete, you can open your application:
eb open
Step 6: Update Your Application When Needed
After making changes to your code, deploy the updates:
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
npm install -g serverless
Step 2: Set Up a Serverless Express Project
Create a new directory for your serverless project and initialize it:
mkdir serverless-express
cd serverless-express
npm init -y
Install the required dependencies:
npm install express serverless-http aws-serverless-express
Step 3: Create Your Express Application
Create a file named app.js
:
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
:
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
:
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
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
mkdir books-api
cd books-api
npm init -y
npm install express cors helmet morgan dotenv
Create an app.js
file:
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
node app.js
Test the API with curl or Postman:
# 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
eb init
# Follow the prompts
eb create books-api-production
Step 5: Configure Environment Variables (if needed)
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:
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:
-
Amazon EC2 - Best for:
- Applications requiring full control over the infrastructure
- Complex applications with specific server configuration needs
- Long-running applications with consistent traffic
-
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
-
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:
- Using EC2 for maximum control, where we set up our own server environment with Node.js, PM2, and optional NGINX
- Using Elastic Beanstalk for managed infrastructure, which automatically handles capacity provisioning, load balancing, and scaling
- 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
- Official Express.js Documentation
- AWS Documentation for Node.js
- PM2 Documentation
- Serverless Framework Documentation
Exercises
- Deploy a simple "Hello World" Express application to EC2 and set up a custom domain name for it.
- Modify the Books API example to use DynamoDB instead of in-memory storage and deploy it to Elastic Beanstalk.
- Create a serverless Express application that connects to an external API and deploy it to AWS Lambda.
- Set up a CI/CD pipeline using AWS CodePipeline to automatically deploy your Express application whenever you push to your GitHub repository.
- 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! :)