Why use Nginx in front of Node.js?
Running Node.js directly on port 80 or 443 works, but it’s not ideal for production. Nginx as a reverse proxy gives you:
- SSL/TLS termination - Handle HTTPS at the Nginx level
- Static file serving - Nginx serves static files faster than Node.js
- Load balancing - Distribute traffic across multiple Node.js instances
- Security - Hide your Node.js port from the internet
- Caching - Cache responses to reduce load on your application
Prerequisites
Before starting, you need:
- A VPS with Node.js installed
- A Node.js application running (we’ll assume port 3000)
- A domain name pointing to your server (for SSL)
- SSH access with root or sudo privileges
Step 1: Install Nginx
Update your packages and install Nginx:
sudo apt update
sudo apt install -y nginx
Start Nginx and enable it to run on boot:
sudo systemctl start nginx
sudo systemctl enable nginx
Verify it’s running:
sudo systemctl status nginx
Step 2: Configure the reverse proxy
Create a new Nginx configuration file for your site:
sudo nano /etc/nginx/sites-available/myapp
Add this configuration (replace yourdomain.com with your actual domain):
server {
listen 80;
server_name yourdomain.com www.yourdomain.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_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;
proxy_cache_bypass $http_upgrade;
}
}
Key settings explained:
- proxy_pass - Forward requests to your Node.js app on port 3000
- proxy_http_version 1.1 - Required for WebSocket support
- Upgrade and Connection headers - Enable WebSocket connections
- X-Real-IP and X-Forwarded-For - Pass the real client IP to Node.js
- X-Forwarded-Proto - Tell Node.js if the original request was HTTPS
Step 3: Enable the site
Create a symbolic link to enable the site:
sudo ln -s /etc/nginx/sites-available/myapp \
/etc/nginx/sites-enabled/
Remove the default site (optional):
sudo rm /etc/nginx/sites-enabled/default
Test the configuration:
sudo nginx -t
If the test passes, reload Nginx:
sudo systemctl reload nginx
Step 4: Add SSL with Let’s Encrypt
Install Certbot for free SSL certificates:
sudo apt install -y certbot python3-certbot-nginx
Get a certificate for your domain:
sudo certbot --nginx -d yourdomain.com -d www.yourdomain.com
Certbot will:
- Verify you own the domain
- Obtain an SSL certificate
- Automatically configure Nginx for HTTPS
- Set up auto-renewal
Your site now works on HTTPS!
Step 5: Configure your firewall
In your ServerPoint’s Client Portal, update your firewall rules:
- Port 80 (HTTP) - Open for Let’s Encrypt verification and HTTP-to-HTTPS redirect
- Port 443 (HTTPS) - Open for secure traffic
- Port 3000 - Keep closed! Nginx handles external traffic now
- Port 22 (SSH) - Restrict to your IP or keep closed in Global firewall
Serving static files with Nginx
For better performance, let Nginx serve static files directly instead of proxying them to Node.js.
Update your configuration:
sudo nano /etc/nginx/sites-available/myapp
Add a location block for static files before the main location block:
server {
listen 443 ssl;
server_name yourdomain.com www.yourdomain.com;
# SSL configuration added by Certbot
ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;
# Serve static files directly
location /static/ {
alias /home/youruser/myapp/public/;
expires 30d;
add_header Cache-Control "public, immutable";
}
# Proxy everything else to Node.js
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_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;
proxy_cache_bypass $http_upgrade;
}
}
Adjust the alias path to match where your static files are located.
Testing your setup
After reloading Nginx, test your application:
- Visit
https://yourdomain.com- should show your Node.js app - Check the browser’s security icon - should show a valid SSL certificate
- Test WebSocket connections if your app uses them
Troubleshooting
502 Bad Gateway
- Your Node.js app isn’t running
- Check with:
sudo systemctl status myapp(if using systemd) - Or check if the port is listening:
ss -tlnp | grep 3000
504 Gateway Timeout
- Node.js is taking too long to respond
- Add timeout settings to the location block:
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
SSL certificate errors
- Make sure your domain points to your server’s IP
- Run
sudo certbot renew --dry-runto test renewal
Next steps
- Set up PM2 to manage your Node.js process
- Configure automatic deployments from GitHub
Explore our VPS plans for production-ready servers.