If you have a Node.js application running locally, you can deploy it on an AWS EC2 server and make it accessible through the internet.
In this guide, we will:
- Create an AWS EC2 instance
- Connect to the server using SSH
- Install Node.js
- Run a Node.js application
- Use PM2 to keep the application running
- Install NGINX
- Configure NGINX as a reverse proxy
- Configure the AWS firewall
- Access the Node.js application using the EC2 public IP
By the end, the architecture will look like this:
User
|
| HTTP Request
↓
NGINX :80
|
| Proxy
↓
Node.js :3000
1. Create an EC2 Instance
Go to the AWS Console and open EC2.
Create a new instance.
For this tutorial, you can use:
AMI: Ubuntu
Instance type: t2.micro or t3.micro
Storage: 8 GB or more
When creating the instance, make sure you create or select an SSH key pair.
Download the .pem file and keep it safe.
You will need it to connect to the server.
2. Configure the Security Group
The EC2 security group works like a firewall.
Add these inbound rules:
| Type | Port | Source |
|---|---|---|
| SSH | 22 | My IP |
| HTTP | 80 | Anywhere |
| HTTPS | 443 | Anywhere |
For testing, you can use 0.0.0.0/0 for HTTP.
For SSH, it is better to allow only your own IP instead of opening port 22 to everyone.
3. Connect to EC2 Using SSH
After the instance starts, copy its public IPv4 address.
It will look something like:
13.234.XX.XX
Open your terminal and move to the directory containing your .pem file.
On Linux or macOS:
chmod 400 my-key.pem
Then connect:
ssh -i my-key.pem ubuntu@YOUR_EC2_PUBLIC_IP
Example:
ssh -i my-key.pem ubuntu@13.234.XX.XX
If everything works, you are now inside your EC2 server.
4. Update the Server
First update the package list:
sudo apt update
Then upgrade existing packages:
sudo apt upgrade -y
5. Install Node.js
The easiest way is to use NodeSource.
First install curl:
sudo apt install curl -y
Then install Node.js.
For example:
curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash -
Install Node.js:
sudo apt install nodejs -y
Check the installation:
node -v
And:
npm -v
You should see the installed Node.js and npm versions.
6. Get Your Node.js Application
There are several ways to put your application on the EC2 server.
For example, if your project is on GitHub:
git clone https://github.com/USERNAME/REPOSITORY.git
Enter the project:
cd REPOSITORY
Install dependencies:
npm install
If your application requires environment variables, create your .env file:
nano .env
Add your environment variables and save the file.
7. Run the Node.js Server
Suppose your Node.js application contains:
const express = require("express");
const app = express();
app.get("/", (req, res) => {
res.send("Hello from AWS EC2!");
});
app.listen(3000, () => {
console.log("Server running on port 3000");
});
Start it:
node server.js
You should see:
Server running on port 3000
Your application is now running on:
http://YOUR_EC2_PUBLIC_IP:3000
However, we don't want users to access the application using port 3000.
This is where NGINX comes in.
8. Why Do We Need NGINX?
Instead of exposing your Node.js application directly, we can put NGINX in front of it.
The user sends a request to:
http://YOUR_EC2_PUBLIC_IP
NGINX receives the request on port 80.
NGINX then forwards the request internally to:
http://localhost:3000
The flow becomes:
Browser
|
| :80
↓
NGINX
|
| :3000
↓
Node.js
This is called a reverse proxy.
9. Install NGINX
Install NGINX:
sudo apt install nginx -y
Check its status:
sudo systemctl status nginx
If it is running, you should see something similar to:
Active: active (running)
You can also enable NGINX to start automatically when the server boots:
sudo systemctl enable nginx
10. Configure NGINX as a Reverse Proxy
NGINX configuration files are usually stored in:
/etc/nginx/
For our application, create a new configuration:
sudo nano /etc/nginx/sites-available/nodeapp
Add:
server {
listen 80;
server_name _;
location / {
proxy_pass http://localhost:3000;
}
}
Save the file.
11. Enable the Configuration
Create a symbolic link:
sudo ln -s /etc/nginx/sites-available/nodeapp /etc/nginx/sites-enabled/
The default NGINX configuration can cause conflicts, so remove it:
sudo rm /etc/nginx/sites-enabled/default
Before restarting NGINX, test the configuration:
sudo nginx -t
You should see:
syntax is ok
test is successful
Now restart NGINX:
sudo systemctl restart nginx
12. Keep Node.js Running with PM2
There is one problem.
If you run:
node server.js
and close your SSH connection, the application can stop.
We need a process manager.
Install PM2:
sudo npm install -g pm2
Start your application:
pm2 start server.js --name nodeapp
Check the process:
pm2 status
You should see:
nodeapp online
Save the PM2 process list:
pm2 save
Configure PM2 to start automatically after a server reboot:
pm2 startup
PM2 will give you a command.
Copy and run that command.
Then run:
pm2 save
Now your Node.js application can automatically restart after a server reboot.
13. Access Your Application
Open your browser and visit:
http://YOUR_EC2_PUBLIC_IP
For example:
http://13.234.XX.XX
The request flow is now:
Internet
|
↓
AWS EC2
|
↓
NGINX :80
|
↓
Node.js :3000
You don't need to expose port 3000 publicly.
NGINX communicates with Node.js internally through:
localhost:3000
14. Important AWS Security Group Configuration
At this point, your EC2 security group should have something similar to:
SSH 22 Your IP
HTTP 80 0.0.0.0/0
HTTPS 443 0.0.0.0/0
You do not need to expose port 3000 to the internet.
This is an important difference:
Public:
Internet → NGINX :80
Private:
NGINX → Node.js :3000
15. Useful NGINX Commands
Check NGINX status:
sudo systemctl status nginx
Start NGINX:
sudo systemctl start nginx
Stop NGINX:
sudo systemctl stop nginx
Restart NGINX:
sudo systemctl restart nginx
Test configuration:
sudo nginx -t
16. Useful PM2 Commands
Check applications:
pm2 status
View logs:
pm2 logs
Restart application:
pm2 restart nodeapp
Stop application:
pm2 stop nodeapp
Delete application:
pm2 delete nodeapp
17. Common Problems
NGINX shows 502 Bad Gateway
A 502 Bad Gateway usually means NGINX cannot reach your Node.js application.
Check whether Node.js is running:
pm2 status
You can also test the application directly from the EC2 server:
curl http://localhost:3000
If this doesn't return your application response, fix the Node.js application first.
NGINX configuration error
Run:
sudo nginx -t
It will tell you where the configuration problem is.
Cannot access the EC2 IP
Check your AWS security group.
Make sure port 80 is allowed.
Also check NGINX:
sudo systemctl status nginx
Node.js application stopped
Check PM2:
pm2 status
Then check logs:
pm2 logs nodeapp
18. Final Architecture
After completing everything, your deployment looks like this:
INTERNET
|
|
Public IP :80
|
↓
┌─────────┐
│ NGINX │
│ :80 │
└────┬────┘
|
| Reverse Proxy
↓
┌─────────┐
│ Node.js │
│ :3000 │
└─────────┘
|
↓
Your App
The important idea is simple:
NGINX handles incoming HTTP requests, while Node.js handles your application logic.
You can later add a domain name and HTTPS on top of this setup using Let's Encrypt and Certbot.
Conclusion
You now have a Node.js application running on an AWS EC2 server with NGINX acting as a reverse proxy.
The basic production flow is:
User
↓
Domain / Public IP
↓
NGINX
↓
Node.js
↓
Database / External Services
This setup is a good foundation for learning real-world server deployment before moving to more advanced tools such as Docker, load balancers, CI/CD, and Kubernetes.
Want the Video Walkthrough?
If you prefer following the process visually, I have also explained the deployment in more detail in this
video: https://www.youtube.com/watch?v=4cgvi_uCKiA
Watch the detailed AWS EC2 + NGINX + Node.js deployment video
You can follow this article alongside the video and execute each command directly on your EC2 instance.
Top comments (0)