How to Deploy a Node.js Application on AWS EC2: Complete Step by Step Guide
By Braincuber Team
Published on March 9, 2026
We watched a dev team spend 3 weeks trying to deploy a Node.js API on AWS because nobody told them about security group inbound rules. The app ran fine inside the EC2 console. But from a browser? Nothing. Just a blank timeout. Port 3000 was open on the server but blocked by the firewall. That is a $4,700 developer-hours mistake for a 2-minute configuration change. This complete tutorial walks you through every step — from launching your EC2 instance to serving your app on port 80 with Caddy reverse proxy.
What You'll Learn:
- How to launch and configure an AWS EC2 instance (free tier)
- How to install Node.js and npm on Ubuntu Linux
- How to configure security groups and inbound/outbound rules
- How to deploy your Node.js/Express app and make it accessible
- How to set up Caddy as a reverse proxy (port 3000 to port 80)
EC2 vs. Lambda: Pick the Right One Before You Start
AWS gives you two main options for running backend code. Pick the wrong one and you will either overpay or under-deliver.
| Aspect | AWS EC2 | AWS Lambda |
|---|---|---|
| What It Is | Virtual server (full OS) running 24/7 | Serverless function execution on demand |
| Best For | Complex monolithic apps, APIs needing persistent connections | Simple functions, event-driven tasks, no consistent uptime needed |
| Free Tier | t2.micro / t3.micro (750 hrs/month for 12 months) | 1M free requests + 400,000 GB-seconds/month |
| Control | Full OS access, install anything, SSH in anytime | No OS access, limited runtime, 15-min max execution |
| Scaling | Manual (or auto-scaling groups) | Automatic, scales to thousands concurrently |
This tutorial covers EC2 — the right choice for Node.js/Express APIs, full-stack apps, and anything that needs a persistent server running with WebSockets, cron jobs, or background workers.
What You Need Before Starting
AWS Account (Free Tier)
Sign up at aws.amazon.com if you do not have one. The free tier gives you 750 hours/month of t2.micro or t3.micro for 12 months. That is enough to run one Node.js app 24/7 for free.
A Node.js/Express App
Any Express API will work. This tutorial uses a simple demo app. Your app should have a package.json with a start script and run on port 3000 (or any port you configure).
Basic Linux Knowledge
You will use terminal commands like cd, sudo apt, nano, and git clone. Nothing advanced — if you can navigate a terminal, you are fine.
Basic Networking Concepts
Ports, IP addresses, HTTP vs HTTPS, firewalls. Understanding inbound vs outbound rules is the single most common point of failure for first-time deployers.
Step by Step Guide: Deploy Node.js on AWS EC2
Launch an EC2 Instance on AWS
Log into your AWS console and search for EC2. Click Launch Instance. Give it a name (e.g., "nodejs-api-server"). Select Ubuntu as the operating system. Choose t2.micro or t3.micro as the instance type (free tier eligible). For key pair, you can create one for SSH or opt out if you plan to use EC2 Instance Connect (browser-based console). Leave the default VPC and subnet settings. Click Launch Instance.
Connect to Your Instance and Install Node.js
Once your instance is running, click Connect and use EC2 Instance Connect to open a browser-based terminal. Run the following commands to update packages and install Node.js:
# Update system packages
sudo apt update
# Install Node.js and npm
sudo apt install nodejs npm
# Verify installation
node --version
npm --version
Clone and Run Your Node.js Application
Clone your application from GitHub (or upload it via SCP). Install dependencies with npm install, then start the app with npm start. You should see a success message in the terminal. But if you try to access the app via the EC2 public IP on port 3000, you will get a timeout. That is expected — the firewall is blocking it.
# Clone your app from GitHub
git clone https://github.com/your-username/your-nodejs-app.git
# Navigate into the project directory
cd your-nodejs-app
# Install dependencies
npm install
# Start the application
npm start
Configure Security Group Inbound Rules
This is where 90% of first-time deployers get stuck. Go back to the EC2 Dashboard → Security Groups. Select the security group attached to your instance. Click Edit Inbound Rules → Add Rule. Set type to Custom TCP, port to 3000, source to 0.0.0.0/0 (anywhere). Save the rule. Wait 1-2 minutes, then access your app at http://[your-ec2-ip]:3000.
Inbound vs. Outbound Rules
Inbound rules control who can access your EC2 instance (SSH, HTTP, HTTPS, custom ports). Outbound rules control what your EC2 instance can send out. If your app is running but the browser times out, it is always an inbound rule problem. We have seen dev teams debug their code for days when it was a 30-second firewall fix.
Install and Configure Caddy as a Reverse Proxy
Nobody wants to type :3000 after your IP address. Caddy is a beginner-friendly web server that acts as a reverse proxy — it routes traffic from port 80 (default HTTP) to your app on port 3000. Install Caddy, edit its config file, add the reverse_proxy directive, and restart the service.
# Install Caddy
sudo apt install caddy
# Verify Caddy is running
caddy run
# Edit the Caddyfile configuration
sudo nano /etc/caddy/Caddyfile
# Inside the :80 block, add this line:
# reverse_proxy :3000
# Save the file (Ctrl+O, Enter, Ctrl+X)
# Restart Caddy to apply changes
sudo systemctl restart caddy
Verify Your App Is Live and Add Inbound Rule for Port 80
Make sure your security group has an HTTP (port 80) inbound rule set to 0.0.0.0/0. Then navigate to http://[your-ec2-public-ip] in your browser — no port suffix needed. Your Node.js app should be live. Caddy is forwarding all port 80 traffic to your app on port 3000 behind the scenes.
The Caddyfile: What Your Config Should Look Like
# Basic Caddyfile for reverse proxy
:80 {
reverse_proxy :3000
}
# With a custom domain (Caddy auto-provisions SSL):
# yourdomain.com {
# reverse_proxy :3000
# }
What to Do After Deployment
| Next Step | Why It Matters | How |
|---|---|---|
| Add a Custom Domain | Nobody remembers an IP address; DNS gives you a human-readable URL | Point your domain's A record to your EC2 public IP in Route 53 or your DNS provider |
| Enable HTTPS with Caddy | Caddy auto-provisions SSL certificates from Let's Encrypt — zero config | Replace :80 with yourdomain.com in the Caddyfile; add HTTPS inbound rule (port 443) |
| Use PM2 as Process Manager | npm start dies when you close the terminal; PM2 keeps it alive 24/7 | npm install -g pm2, then pm2 start app.js, then pm2 startup |
| Set Up Elastic IP | EC2 public IP changes on reboot; Elastic IP makes it permanent | Allocate an Elastic IP from EC2 dashboard and associate it with your instance |
Do Not Use npm start in Production
When you close your SSH session or EC2 Instance Connect tab, npm start dies. Your app goes offline instantly. Use PM2 (process manager) to keep your Node.js app running as a background daemon. Run pm2 start app.js and then pm2 startup to auto-restart on reboot. We have seen production APIs go down at 2 AM because someone forgot this step.
Why Caddy Instead of Nginx?
Caddy = Auto SSL, simple config, 3-line Caddyfile, built-in HTTPS
Nginx = More control, higher performance ceiling, 30+ line config file
Verdict = Use Caddy if you want zero-config SSL and a fast setup
Verdict = Use Nginx if you need granular load balancing or handle 10K+ concurrent connections
Frequently Asked Questions
Is AWS EC2 free for deploying Node.js apps?
Yes, for 12 months. AWS offers 750 hours per month of t2.micro or t3.micro instances under the free tier. That is enough to run one Node.js application 24/7 for an entire year at zero cost.
Why can I not access my Node.js app from a browser after deploying on EC2?
Almost always a security group issue. Your app is running on the server but the EC2 firewall is blocking incoming traffic on your app's port (usually 3000). Add an inbound rule in your security group for Custom TCP on port 3000 with source 0.0.0.0/0.
What is a reverse proxy and why do I need Caddy?
A reverse proxy forwards client requests from one port to another. Caddy listens on port 80 (default HTTP port) and forwards traffic to your Node.js app on port 3000. This way users access your app via a clean URL without the :3000 suffix. Caddy also auto-provisions free SSL certificates.
How do I keep my Node.js app running after closing the terminal?
Use PM2, a Node.js process manager. Install it globally with npm install -g pm2, start your app with pm2 start app.js, and run pm2 startup to auto-restart on system reboot. Without PM2, your app dies the moment you close the SSH session.
Should I use Caddy or Nginx as a reverse proxy?
Use Caddy for simplicity: auto SSL, 3-line config, beginner-friendly. Use Nginx if you need granular load balancing, custom caching rules, or handle over 10,000 concurrent connections. For most Node.js APIs and small-to-medium apps, Caddy is the better choice.
Need Help Deploying Your Backend on AWS?
We have deployed and managed over 80 production Node.js applications on AWS for D2C brands. From EC2 setup to CI/CD pipelines, load balancing, and auto-scaling — let us handle your infrastructure so you can focus on building your product.
