Before deploying the application, it is important to properly set up and secure your Ubuntu VPS (AWS-EC2).
Follow steps 1–14 from the repository (deploy-flask-postgresql-ubuntu-aws-ec2) to configure your server environment.
- These steps include updating system packages
- creating a non-root user
- configuring the firewall
- securing SSH access
- installing essential dependencies.
Completing this preparation ensures that your VPS is both stable and hardened against common security risks.
Run to ensure all packages are up to date.
sudo apt update && sudo apt upgrade -y
Install Node.js and its package manager (npm) on your server. Using a tool like NVM (Node Version Manager) is recommended for managing Node.js versions.
# Download and install nvm:
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.3/install.sh | bash
# in lieu of restarting the shell
\. "$HOME/.nvm/nvm.sh"
# Download and install Node.js:
nvm install 22
# Verify the Node.js version:
node -v # Should print "v22.18.0".
nvm current # Should print "v22.18.0".
# Verify npm version:
npm -v # Should print "10.9.3".
Install PM2 globally to manage your Node.js application process, ensuring it runs continuously and restarts automatically.
npm install -g pm2
Install MongoDB on your Ubuntu server. Ensure it's configured to bind to localhost for security unless you explicitly need remote access and have properly secured it.
-
Import MongoDB GPG Key
curl -fsSL https://pgp.mongodb.com/server-7.0.asc | \ sudo gpg -o /usr/share/keyrings/mongodb-server-7.0.gpg \ --dearmor
-
Add MongoDB Repository
echo "deb [ signed-by=/usr/share/keyrings/mongodb-server-7.0.gpg ] \ https://repo.mongodb.org/apt/ubuntu $(lsb_release -cs)/mongodb-org/7.0 multiverse" | \ sudo tee /etc/apt/sources.list.d/mongodb-org-7.0.list
-
Install MongoDB
sudo apt update sudo apt install -y mongodb-org
-
Start & Enable MongoDB
sudo systemctl start mongod sudo systemctl enable mongod
-
Check status:
systemctl status mongod
-
Bind MongoDB to localhost (for security)
By default, MongoDB binds to
127.0.0.1
. To confirm:sudo nano /etc/mongod.conf
Find:
net: bindIp: 127.0.0.1
⚠️ Only change this if you want remote access (and then use a firewall/VPN + authentication).Save and restart:
sudo systemctl restart mongod
-
Verify Installation
Open MongoDB shell:
mongosh
Test:
db.runCommand({ connectionStatus: 1 })
On your local machine, build your Next.js application for production using npm run build
. This generates the optimized static assets and server-side code.
On your VPS, clone your application's Git repository to a suitable directory (e.g., /var/www/your-app-name
).
mkdir -p /var/www/
cd /var/www/
sudo git clone https://<Personal Access Token (PAT)>@github.com/Project-Buck/R3_Diagnostics_Website.git myapp
cd myapp
You should give your system user (e.g., "grader" or your actual username) ownership of the project directory
sudo chown -R grader:grader /var/www/myapp
Navigate to your application's directory on the VPS and install the Node.js dependencies using npm install.
-
Navigate to your project directory
cd /var/www/myapp
-
Install dependencies (if not installed yet)
npm install
-
Run the production build
npm run build
This command creates an optimized
.next/
folder containing:- Static assets → for client-side usage.
- Server-side code → for server rendering (if you’re not using static export).
- Optimized JavaScript & CSS.
-
Start the production server (locally test)
npm run start
⚡ At this stage, your app is ready for deployment
Set up environment variables for your application, including your MongoDB connection string and any other necessary configurations. This can be done using a .env
file or by setting them in your PM2 configuration.
-
Inside your project root, create a
.env
file:nano .env
-
Add your environment variables:
MONGODB_URI=mongodb://localhost:27017/myapp PORT=3000 NODE_ENV=production SECRET_KEY=mySuperSecretKey
-
In Next.js, only environment variables prefixed with
NEXT_PUBLIC_
are exposed to the browser; all other variables remain server-side:NEXT_PUBLIC_API_URL=https://mydomain.com/api NEXT_PUBLIC_SITE_URL=http://mydomain.com
-
Restart your app so the
.env
is loaded:cd /var/www/myapp rm -rf .next npm run build npm run start
Install Nginx on your VPS using sudo apt install nginx
.
-
Here’s how you can install Nginx on your Ubuntu VPS:
# Update package lists sudo apt update # Install Nginx sudo apt install nginx -y # Enable Nginx to start on boot sudo systemctl enable nginx # Start Nginx service sudo systemctl start nginx # Check Nginx status sudo systemctl status nginx
✅ After installation, open your browser and go to your server’s IP address (e.g.,
http://your_server_ip
). You should see the default “Welcome to Nginx” page.
Create a new Nginx configuration file for your application (e.g., in /etc/nginx/sites-available/your-app-name
) and configure it to act as a reverse proxy, forwarding requests to your Next.js/Node.js application running on a specific port (e.g., 3000 or 8080).
-
Create a new configuration file
sudo nano /etc/nginx/sites-available/myapp
-
Add the following configuration
Replace
your_domain.com
with your actual domain name or server IP, and3000
with the port your app is running on:server { listen 80; server_name your_domain.com; location / { proxy_pass http://127.0.0.1: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; } }
-
Clear old build & rebuild
cd /var/www/myapp rm -rf .next npm run build npm run start
Create a symbolic link from your configuration file in sites-available
to sites-enabled
.
-
Link the file from sites-available to sites-enabled:
# Go to Nginx config directory cd /etc/nginx/sites-available/ # Create a symbolic link sudo ln -s /etc/nginx/sites-available/myapp /etc/nginx/sites-enabled/
Test your Nginx configuration with sudo nginx -t and reload Nginx with sudo systemctl reload nginx.
-
Test the configuration (to ensure there are no syntax errors):
sudo nginx -t
-
If the test is successful, reload Nginx:
sudo systemctl reload nginx
✅ Now, Nginx will forward all requests coming to your_domain.com
to your Next.js app running on port 3000
.
-
From your application's directory, start your Next.js/Node.js application using PM2 (e.g.,
pm2 start npm --name "your-app-name" -- run start
).-
Navigate to your app’s directory
cd /var/www/myapp
-
Start the app with PM2
Run this command (replace
your-app-name
with your app name and in my case ismyapp
):pm2 start npm --name "myapp" -- run start
Explanation:
pm2 start npm
→ tells PM2 to run an npm command.--name "myapp"
→ gives your process a readable name in PM2.-- run start
→ executes your"start"
script from package.json (usuallynext start
).
-
-
Save PM2 Process List: Use
pm2 save
to save the current process list, ensuring PM2 restarts your application automatically after a server reboot.-
Check if the app is running
pm2 list
-
View logs if needed
pm2 logs myapp
-
Keep app running after reboot
pm2 save
-
-
Enable PM2 Startup: Configure PM2 to start on system boot using the following command:
pm2 startup systemd
-
To setup the Startup Script, copy/paste the following command:
You will get this command after running the above command according to your OS
sudo env PATH=$PATH:/home/grader/.nvm/versions/node/v22.18.0/bin /home/grader/.nvm/versions/node/v22.18.0/lib/node_modules/pm2/bin/pm2 startup systemd -u grader --hp /home/grader
-
-
Install Certbot to easily obtain and manage SSL certificates. It is the official tool for acquiring Let’s Encrypt certificates and automatically configuring Nginx.
sudo apt update sudo apt install certbot python3-certbot-nginx -y
-
Use Certbot to obtain an SSL certificate for your domain and configure Nginx to use it.
sudo certbot --nginx -d your_domain.com -d www.your_domain.com
- Follow prompts:
- Enter email (for renewal notices)
- Agree to terms
- Certbot will automatically configure Nginx for HTTPS
- Follow prompts:
-
Configure Certbot to automatically renew your SSL certificates. Let’s Encrypt certificates are valid for 90 days. Certbot can auto-renew:
sudo systemctl status certbot.timer
-
Or test renewal manually:
sudo certbot renew --dry-run
-
Edit your Nginx server block:
sudo nano /etc/nginx/sites-available/myapp
-
Replace old with this configuration:
# Redirect all HTTP requests to HTTPS server { listen 80; server_name your_domain.com www.your_domain.com; location / { return 301 https://$host$request_uri; } } # HTTPS server block server { listen 443 ssl; server_name your_domain.com www.your_domain.com; ssl_certificate /etc/letsencrypt/live/your_domain.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/your_domain.com/privkey.pem; include /etc/letsencrypt/options-ssl-nginx.conf; ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; location / { proxy_pass http://127.0.0.1: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; } }
✅ Make sure to replace your_domain.com with your actual domain name.
# Disable the default site
sudo rm /etc/nginx/sites-enabled/default
sudo unlink /etc/nginx/sites-enabled/default
# Ensure your site config is enabled
sudo ln -s /etc/nginx/sites-available/myapp /etc/nginx/sites-enabled/
# Test Nginx configuration
sudo nginx -t
sudo systemctl reload nginx
# Clear Next.js build and cache
cd /var/www/myapp/
rm -rf .next
rm -rf node_modules
npm install
# Rebuild Next.js
npm run build
# Stop PM2 completely
pm2 stop myapp
pm2 delete myapp
# Start fresh with PM2
pm2 start npm --name "myapp" -- run start
pm2 save
# Reload Nginx:
sudo nginx -t
sudo systemctl reload nginx
By following these steps, you can successfully deploy your Next.js and Node.js application with MongoDB on an Ubuntu VPS, ensuring it's accessible, secure, and running reliably.
deploy-nextjs-nodejs-mongodb-ubuntu-aws-ec2
is Copyright ©️ 2025 Kashif Iqbal. It is free, and may be redistributed under the terms specified in the LICENSE file.