AWS Builder Center

Deploying a NestJS API on AWS EC2: A Step-by-Step Guide

Building a backend API is only part of the development process. To make it accessible to other applications and users, we also need to deploy it to a server, configure network access, and ensure it continues running after the initial deployment.

In this tutorial, we will deploy a NestJS API to an Amazon EC2 instance running Ubuntu. We will use Node.js to run the application, PM2 to manage the process, and Nginx as a reverse proxy.
By the end, you will have a NestJS API accessible through your EC2 instance's public IP address.
What we will use:
  • Amazon EC2: Virtual server for hosting the API.
  • Ubuntu: Operating system for the instance.
  • Node.js and npm: Runtime and package manager.
  • NestJS: Backend framework.
  • PM2: Process manager that can restart the application if it crashes.
  • Nginx: Reverse proxy that receives HTTP requests and forwards them to the API.
This guide assumes you already have an AWS account and a working NestJS application.

1. Launch an EC2 instance

First, open the Amazon EC2 Console  and launch a new instance.
Configure the following options:
  1. Name: nestjs-api-server
  2. AMI: Ubuntu Server LTS, preferably a currently supported release.
  3. Instance type: Choose a small instance suitable for your workload and budget.
  4. Key pair: Create or select an SSH key pair and store the private key securely.
  5. Network settings: Create a security group with the required inbound rules.
For inbound traffic, use the following configuration:
TypePortSource
SSH22My IP
HTTP800.0.0.0/0
HTTPS4430.0.0.0/0
SSH should not be open to the entire internet unless there is a specific, justified need. Restricting access to your IP reduces unnecessary exposure.
Security groups act as virtual firewalls for EC2 instances. See the AWS security group documentation  for more information.
After launching the instance, wait until it passes its status checks.

2. Connect to the instance

Download your private key if you have not already done so. On a Linux machine, restrict its permissions:
1
chmod 400 my-ec2-key.pem
Connect using the instance's public IPv4 address:
1
ssh -i my-ec2-key.pem ubuntu@YOUR_EC2_PUBLIC_IP
Replace my-ec2-key.pem with your key file and YOUR_EC2_PUBLIC_IP with the actual address shown in the EC2 console.
Once connected, update the operating system packages:
1
2
sudo apt update
sudo apt upgrade -y
Keeping the operating system updated is an important part of maintaining a secure server.

3. Install Node.js and npm

NestJS requires a supported Node.jresum node --version npm --version
You should see the installed Node.js and npm versions.
For an existing application, check its package.json and use a compatible Node.js version rather than assuming every project supports the same runtime.

4. Get the NestJS application onto the server

Install Git:
1
sudo apt install -y git
Clone your repository:
1
2
git clone YOUR_REPOSITORY_URL
cd YOUR_PROJECT_DIRECTORY
Replace the placeholders with your repository URL and project directory.
For a private repository, configure authentication securely. Avoid embedding access tokens in repository URLs or committing credentials to source control.
Install dependencies:
1
npm ci
This command uses the lockfile to install the project's declared dependencies. If your project uses pnpm or Yarn, use its corresponding lockfile-based installation command instead.
Next, configure the environment variables required by your application.
For example, a simple API might need:
1
2
NODE_ENV=production
PORT=3000
Database URLs, API keys, and other secrets should also be configured when required by the application.
Do not commit .env files containing credentials to Git. For a production deployment, consider using AWS Secrets Manager or another appropriate secret-management solution.

5. Build and test the application

Compile the NestJS application:
1
npm run build
A successful build should generate the compiled JavaScript files, commonly in the dist directory.
Start the application:
1
NODE_ENV=production node dist/main.js
The exact entry point can differ depending on your project structure. Check the generated files if dist/main.js does not exist.
By default, a new NestJS application commonly listens on port 3000, but the actual port depends on your application's configuration.
Open another terminal and test the API locally on the EC2 instance:
1
curl http://127.0.0.1:3000
If your API has a health endpoint, test that endpoint instead. A 404 Not Found response from the root path does not necessarily mean the server failed to start; the application may simply not define a route at /.
Once you have confirmed that the API responds, stop the foreground process with Ctrl+C.

6. Keep the application running with PM2

Running Node.js directly in a terminal is not ideal for a server because the application stops when the process ends.
PM2 provides process management, logs, and automatic restarts.
Install it globally:
1
sudo npm install -g pm2
Start the compiled application:
1
2
3
cd YOUR_PROJECT_DIRECTORY

NODE_ENV=production pm2 start dist/main.js --name nestjs-api
Check the process status:
1
pm2 status
View application logs:
1
pm2 logs nestjs-api
If the application crashes, PM2 can restart it. However, process management alone does not guarantee that the application is healthy or that its dependencies are available.
To configure startup after a server reboot, run:
1
pm2 startup
PM2 will display a command that you must execute to configure the startup service. Follow the generated instructions, then save the current process list:
1
pm2 save
You can find additional details in the PM2 documentation .

7. Configure Nginx as a reverse proxy

At this point, the API is running on port 3000. Instead of exposing that port publicly, we can use Nginx to receive requests on port 80 and forward them to the application.
Install Nginx:
1
sudo apt install -y nginx
Create a configuration file:
1
sudo nano /etc/nginx/sites-available/nestjs-api
Add the following configuration:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
server {
listen 80;
server_name YOUR_DOMAIN_OR_PUBLIC_IP;

location / {
proxy_pass http://127.0.0.1:3000;

proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
Replace YOUR_DOMAIN_OR_PUBLIC_IP with your domain or the instance's public IP address.
Enable the configuration:
1
2
sudo ln -s /etc/nginx/sites-available/nestjs-api \
/etc/nginx/sites-enabled/nestjs-api
Test the configuration before reloading Nginx:
1
2
sudo nginx -t
sudo systemctl reload nginx
Nginx now forwards incoming HTTP requests to the local NestJS process. This is a common reverse-proxy pattern for web applications.
For further details, see the Nginx reverse proxy guide .

8. Test the public API

Open your browser or use curl from your local machine:
1
curl http://YOUR_EC2_PUBLIC_IP
If you configured a domain name, test that address instead.
If the request fails, check the following:
  • The EC2 instance is running and has passed its status checks.
  • The security group allows inbound HTTP traffic on port 80.
  • Nginx is running and its configuration is valid.
  • PM2 reports that the NestJS application is online.
  • The application listens on port 3000 on the expected interface.
  • The application logs do not contain startup errors.
Useful diagnostic commands include:
1
2
3
4
sudo systemctl status nginx
sudo nginx -t
pm2 status
pm2 logs nestjs-api
If everything is configured correctly, requests should reach the NestJS API through Nginx.

9. Optional: Configure HTTPS

For a publicly accessible API, HTTPS should be used to encrypt traffic between clients and the server.
If you own a domain, configure its DNS records to point to your EC2 instance. Then obtain a TLS certificate using a suitable certificate authority, such as Let's Encrypt.
Certbot provides a convenient way to obtain and renew certificates for Nginx. Follow the instructions for your operating system and web server at Certbot's official website .
Before requesting a certificate, ensure that:
  • Your domain resolves to the correct server.
  • Port 80 is reachable for HTTP-based certificate validation.
  • Port 443 is allowed by the EC2 security group.
  • Nginx is serving the intended domain.
After HTTPS is configured, test the API using:
1
curl https://YOUR_DOMAIN
Do not send credentials or sensitive application data over an unencrypted public HTTP connection.

10. Production considerations

Getting an API online is a useful first step, but a production environment requires more than a successful deployment.
Consider these improvements before using the application for real workloads:
Security
  • Restrict SSH access and avoid exposing the Node.js application port publicly.
  • Keep the operating system and dependencies updated.
  • Store secrets securely and apply least-privilege access.
  • Use HTTPS and avoid logging sensitive information.
Reliability
  • Add a health-check endpoint.
  • Configure process startup after reboots.
  • Monitor logs and system resources.
  • Back up important data and verify recovery procedures.
Operations
  • Automate deployments through a CI/CD pipeline.
  • Monitor application errors and EC2 metrics.
  • Evaluate scaling, load balancing, and database availability as traffic grows.
  • Review AWS costs, including instance storage, data transfer, and any associated services.
An EC2 instance gives you control over the server, but it also means that you are responsible for operating-system maintenance, application deployment, and infrastructure monitoring.

As a next step, you can automate the deployment process with CI/CD, integrate AWS Secrets Manager, and add monitoring through Amazon CloudWatch.
The same principles can help you understand more advanced deployment architectures as your application grows.
Any opinions in this article are those of the individual author and may not reflect the opinions of AWS.
Enjoyed reading this content? Let the author know!

Your likes, comments, shares, and saves help creators reach more builders.

Loading recommendations

Loading article