Linux VPS

Put a Node.js app behind Nginx, Apache or LiteSpeed (reverse proxy)

Serve a Node.js app on port 80/443 by proxying a domain to it with Nginx, Apache or OpenLiteSpeed, including headers, WebSocket support and testing.

IntermediateLinux VPS2 min read

A Node.js app listens on a local port such as 3000. Visitors expect your domain on ports 80 and 443. A reverse proxy sits in front, accepts the public traffic, handles SSL and passes requests to your app. This guide gives a working config for each of the three common web servers.

Before you start

  • Your app running and reachable locally: curl http://127.0.0.1:3000 returns a page. Keep it running with PM2.
  • Your domain's A record pointing to the VPS IP.
  • One web server installed: Nginx, Apache or OpenLiteSpeed.

Tip: Make the app listen on 127.0.0.1 only, not 0.0.0.0, so nobody can bypass the proxy by visiting http://your-ip:3000.

Nginx

  1. Create /etc/nginx/sites-available/example.com (on AlmaLinux use /etc/nginx/conf.d/example.com.conf):
    server {
        listen 80;
        server_name example.com www.example.com;
    
        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;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "upgrade";
        }
    }
  2. Enable it and reload:
    sudo ln -s /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled/
    sudo nginx -t
    sudo systemctl reload nginx

More Nginx options are in Nginx reverse proxy setup.

Apache

  1. Enable the proxy modules (Debian/Ubuntu):
    sudo a2enmod proxy proxy_http proxy_wstunnel headers rewrite
  2. Create /etc/apache2/sites-available/example.com.conf:
    <VirtualHost *:80>
        ServerName example.com
        ServerAlias www.example.com
        ProxyPreserveHost On
        RequestHeader set X-Forwarded-Proto "http"
        RewriteEngine On
        RewriteCond %{HTTP:Upgrade} websocket [NC]
        RewriteRule ^/(.*) ws://127.0.0.1:3000/$1 [P,L]
        ProxyPass / http://127.0.0.1:3000/
        ProxyPassReverse / http://127.0.0.1:3000/
    </VirtualHost>
  3. Enable the site and reload:
    sudo a2ensite example.com
    sudo apachectl configtest
    sudo systemctl reload apache2

On AlmaLinux and Rocky the modules are loaded by default; put the file in /etc/httpd/conf.d/ and reload httpd. See also Apache reverse proxy.

OpenLiteSpeed

  1. Open the WebAdmin console on port 7080 and go to Virtual Hosts → your host → External App. Add a Web Server app named node3000 with address 127.0.0.1:3000.
  2. Go to Context, add a Proxy context with URI / and Web Server node3000.
  3. Click Graceful Restart.

LiteSpeed passes WebSocket upgrades through proxy contexts automatically.

Check that it works

curl -I http://example.com

You should get your app's response headers, not a default web server page. Then add HTTPS as shown in Add SSL to a Node.js app.

Troubleshooting

  • 502 Bad Gateway — the app is not running or listens on another port. Check pm2 list and ss -ltnp | grep 3000. See Fix Nginx 502 Bad Gateway.
  • Redirect loops after SSL — the app does not see X-Forwarded-Proto. In Express set app.set('trust proxy', 1).
  • All visitors show 127.0.0.1 — read the X-Forwarded-For header and enable trust proxy.

Next steps

Was this guide helpful?

Still stuck?

Ask MdmHost AI for a quick answer, or open a ticket and our team will take a look. We are here 24/7.