Overview
When you run a Node.js (or any backend) app on a server, it typically listens on a high port like
3000. You can't expose port 3000 to the public directly because it's not standard HTTP/HTTPS. This
is where Nginx comes in — as a reverse proxy, it sits in front of your app and forwards
incoming requests from port 80 (HTTP) or 443 (HTTPS) to port 3000.
You need a fresh Ubuntu 24 server, a domain pointed to your server's IP, and a running Node.js app on port 3000. This guide assumes you have SSH access with sudo privileges.
Step 1 — Install Nginx
sudo apt update
sudo apt install nginx -y
Once installed, Nginx starts automatically. You can verify it's running with:
sudo systemctl status nginx
Step 2 — Configure the Firewall
sudo ufw allow 'Nginx Full'
sudo ufw enable
sudo ufw status
Nginx Full is a UFW application profile that opens both ports 80 and 443. This is what you want
since we'll be adding SSL later.
Step 3 — Create a Server Block
Nginx stores site configurations in /etc/nginx/sites-available/. Create a new file for your
domain:
sudo nano /etc/nginx/sites-available/yourdomain.com
Paste the following configuration, replacing yourdomain.com with your actual domain:
server {
listen 80;
server_name yourdomain.com www.yourdomain.com;
location / {
proxy_pass http://localhost: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;
}
}
Now enable the site by creating a symbolic link to sites-enabled:
sudo ln -s /etc/nginx/sites-available/yourdomain.com /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
Always run sudo nginx -t before reloading. It checks the config for syntax errors and saves you
from taking the server down with a bad config file.
Step 4 — Add SSL with Certbot
sudo apt install certbot python3-certbot-nginx -y
sudo certbot --nginx -d yourdomain.com -d www.yourdomain.com
Certbot will automatically modify your Nginx config to enable HTTPS and set up automatic certificate renewal. That's it — your app is now accessible over HTTPS.
Verify automatic renewal
Certbot sets up a systemd timer that renews certs before they expire. You can verify it's active with:
sudo systemctl status certbot.timer
Summary
Here's what we did in four steps:
- Installed Nginx and verified it's running
- Opened ports 80 and 443 through the UFW firewall
- Created a server block that proxies traffic to
localhost:3000 - Secured everything with a free Let's Encrypt SSL certificate
Your Node.js app is now reachable at https://yourdomain.com without exposing its port directly.