Nginx Reverse Proxy for Node.js (Config Snippet + Test with curl)

Running a Node.js app behind Nginx is a battle-tested pattern: Nginx handles TLS, static files, gzip, and connection upgrades (for WebSockets), while your Node app focuses on business logic. This guide gives you a clean, production-ready Nginx config and shows how to test it with curl.


What you’ll set up

  • A Node.js app listening on 127.0.0.1:3000
  • Nginx reverse proxy on port 80/443
  • WebSocket support
  • Gzip compression & basic hardening
  • Simple tests with curl

Works on Ubuntu/Debian and CentOS/RHEL. Adjust paths if your distro uses different Nginx locations.


1) Minimal Node.js app (for testing)

Create a tiny server to verify the proxy:

mkdir -p /var/www/node-app && cd /var/www/node-app
cat > server.js <<'EOF'
const http = require('http');

const server = http.createServer((req, res) => {
  // Simple health route
  if (req.url === '/health') {
    res.writeHead(200, { 'Content-Type': 'application/json' });
    return res.end(JSON.stringify({ ok: true, via: 'node', time: new Date().toISOString() }));
  }

  // Echo headers (useful for proxy tests)
  res.writeHead(200, { 'Content-Type': 'application/json' });
  res.end(JSON.stringify({
    url: req.url,
    headers: req.headers,
    message: 'Hello from Node behind Nginx!'
  }));
});

server.listen(3000, '127.0.0.1', () => {
  console.log('Node app listening on http://127.0.0.1:3000');
});
EOF

node server.js

You should see: Node app listening on http://127.0.0.1:3000


2) (Optional) Keep Node running with systemd

sudo tee /etc/systemd/system/node-app.service >/dev/null <<'EOF'
[Unit]
Description=Node.js Example App
After=network.target

[Service]
WorkingDirectory=/var/www/node-app
ExecStart=/usr/bin/node server.js
Restart=always
RestartSec=3
Environment=NODE_ENV=production
User=www-data
Group=www-data

[Install]
WantedBy=multi-user.target
EOF

sudo systemctl daemon-reload
sudo systemctl enable --now node-app
sudo systemctl status node-app --no-pager

On CentOS/RHEL, the Node path is usually /usr/bin/node too; user/group may be nginx instead of www-data.


3) Nginx reverse proxy config (HTTP)

Create a site config (Debian/Ubuntu style):

sudo mkdir -p /etc/nginx/sites-available /etc/nginx/sites-enabled
sudo tee /etc/nginx/sites-available/node-proxy.conf >/dev/null <<'EOF'
# Replace example.com with your domain
server {
    listen 80;
    server_name example.com www.example.com;

    # Gzip for JSON/JS/CSS
    gzip on;
    gzip_types text/plain application/json application/javascript text/css;
    gzip_min_length 1024;

    # Proxy timeouts (tune as needed)
    proxy_connect_timeout 5s;
    proxy_send_timeout 60s;
    proxy_read_timeout 60s;
    send_timeout 60s;

    # Forward real client IPs
    set $upstream http://127.0.0.1:3000;

    location / {
        proxy_pass $upstream;

        # Preserve Host and IP info
        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;

        # WebSocket support
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $connection_upgrade;

        # Don't buffer SSE/WebSockets too aggressively
        proxy_buffering off;
    }

    # Health path can be cached off for clarity
    location = /health {
        proxy_pass $upstream;
        proxy_set_header Host $host;
        proxy_buffering off;
    }

    # Basic hardening
    add_header X-Frame-Options SAMEORIGIN always;
    add_header X-Content-Type-Options nosniff always;

    # Map for Connection upgrade (place in http{} block if in main nginx.conf)
}
EOF

Create a small map to handle Connection header for WS upgrades. Put this once in your global http {} block (e.g., /etc/nginx/nginx.conf), outside the server block:

map $http_upgrade $connection_upgrade {
    default upgrade;
    ''      close;
}

Enable and test:

sudo ln -s /etc/nginx/sites-available/node-proxy.conf /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx

CentOS/RHEL path: often a single /etc/nginx/nginx.conf with server {} blocks in /etc/nginx/conf.d/*.conf. If so, save as /etc/nginx/conf.d/node-proxy.conf and skip the symlink step.


4) Add HTTPS (Let’s Encrypt)

If your DNS points to the server, you can set up TLS quickly:

# Install Certbot
# Ubuntu/Debian:
sudo apt-get update && sudo apt-get install -y certbot python3-certbot-nginx

# CentOS/RHEL (Stream 8/9; may be 'dnf' and package names differ slightly):
# sudo dnf install -y certbot python3-certbot-nginx

# Obtain and auto-configure SSL for the server block with server_name example.com
sudo certbot --nginx -d example.com -d www.example.com

# Auto renewal (usually installed by default)
sudo systemctl status certbot.timer --no-pager

Certbot will add listen 443 ssl http2; and ssl_certificate lines for you.


5) Test with 

curl

A. Test that Nginx reaches Node

# Replace example.com with your domain or server IP (if HTTP only for now)
curl -i http://example.com/health

Expected:

  • HTTP/1.1 200 OK (or HTTP/2 200 if HTTPS)
  • JSON body like: {“ok”:true,”via”:”node”,”time”:”…”}
  • Response header server: nginx (from Nginx) and body says it came from Node

B. Check headers forwarded by Nginx

curl -i http://example.com/ -H "X-Demo: test123"

Look for:

  • Host: example.com
  • x-demo: test123
  • x-forwarded-proto: http (or https if TLS enabled)
  • x-real-ip set to your client IP

C. Test HTTPS (after Certbot)

curl -I https://example.com/health

You should see:

  • HTTP/2 200
  • TLS certificate fields if you add -v

D. (Optional) WebSocket sanity test

If your Node app upgrades connections at /ws, you can verify the handshake:

curl -i -N \
  -H "Connection: Upgrade" \
  -H "Upgrade: websocket" \
  -H "Host: example.com" \
  -H "Origin: https://example.com" \
  http://example.com/ws

You should get 101 Switching Protocols if your backend handles WS.


6) Common pitfalls & fixes

  • 502 Bad Gateway
    • Node app not running or wrong upstream port/host.
    • SELinux (CentOS) may block Nginx from proxying: setsebool -P httpd_can_network_connect 1
  • WebSockets not upgrading
    • Missing proxy_http_version 1.1, Upgrade, and Connection headers.
    • The map $http_upgrade $connection_upgrade must be in http{}.
  • Wrong client IP
    • Ensure proxy_set_header X-Real-IP $remote_addr; and X-Forwarded-For.
  • TLS issues
    • DNS not pointing to server before running Certbot.
    • Port 80/443 blocked by firewall.

7) Full example (drop-in) for 

/etc/nginx/conf.d/node-proxy.conf

# Place this map ONCE in /etc/nginx/nginx.conf inside http { }:
# map $http_upgrade $connection_upgrade { default upgrade; '' close; }

server {
    listen 80;
    server_name example.com www.example.com;

    gzip on;
    gzip_types text/plain application/json application/javascript text/css;
    gzip_min_length 1024;

    set $upstream http://127.0.0.1:3000;

    location / {
        proxy_pass $upstream;
        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_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $connection_upgrade;

        proxy_buffering off;
        proxy_connect_timeout 5s;
        proxy_send_timeout 60s;
        proxy_read_timeout 60s;
    }

    location = /health {
        proxy_pass $upstream;
        proxy_set_header Host $host;
        proxy_buffering off;
    }

    add_header X-Frame-Options SAMEORIGIN always;
    add_header X-Content-Type-Options nosniff always;
}

Reload Nginx after changes:

sudo nginx -t && sudo systemctl reload nginx

Final checklist

  • Node app runs on 127.0.0.1:3000 (or your chosen port)
  • Nginx config enabled and tested (nginx -t)
  • Health endpoint returns 200 via Nginx
  • TLS installed with Certbot (optional but recommended)
  • curl tests show correct headers and status codes

Tags: Nginx, Node.js, Reverse Proxy, WebSockets, Linux, CentOS, Ubuntu, DevOps

Meta Description: Learn how to put Node.js behind Nginx with a production-ready reverse proxy config, WebSocket support, and quick tests using curl.


Posted

in

by

Comments

15 responses to “Nginx Reverse Proxy for Node.js (Config Snippet + Test with curl)”

  1. bet88comvn Avatar

    Bet88comvn, alright lads, this site’s got a smooth interface and a good selection of games. I’ve had decent luck there, and the bonuses are alright. Give it a burl: bet88comvn

  2. ph888one Avatar

    Roulette’s allure is fascinating – the probabilities really do shape every spin! Seeing platforms like ph888one app casino offer diverse games & easy deposits (like GCash!) makes access simpler for Filipino players. It’s about informed fun, right?

  3. 95ph Avatar

    Interesting read! Bankroll management is key, and choosing a platform with solid security-like seeing with 95ph vip-gives peace of mind. Strategic play & responsible gaming are a winning combo!

  4. phl789 Avatar

    Solid article! Thinking about bankroll management is key, especially with quick deposit options like GCash-makes it easy to stay in the game. Checking out phl789 vip for localized payment methods could be a smart move for PH players. Good insights!

  5. 11betcon Avatar

    Has anyone used 11betcon before? What are your thoughts? Is it legit and easy to use? Curious minds want to know! 11betcon

  6. ty so 7m ma cao Avatar

    7mcnmacao.net is the bomb for 7m Macau scores. Never miss a goal again!ty so 7m ma cao

  7. game b29.win Avatar

    Been playing ‘game b29.win’ for a bit now, and it’s pretty solid. Digging the variety. Check it out if you’re bored!game b29.win

  8. betvndwin Avatar

    Betvndwin! Now that’s a name that promises wins! Lol… But seriously, who’s played here? Any luck? Lemme know! Check them out: betvndwin

  9. luk88club Avatar

    Alright, been hanging out at luk88club. Things here get pretty hot! If you need some fun, check this out! luk88club

  10. me88onlinecasino Avatar

    Oi, anyone tried me88onlinecasino yet? Thinking of having a crack at it. Let me know if it’s the real deal, yeah?

  11. jilibb Avatar

    Excellent guide on the Nginx + Node.js proxy setup! This architecture is exactly what we implemented for our gaming platform’s backend services. The WebSocket handling and gzip compression tips are spot-on for real-time applications. Similar to how we optimized load balancing for jilibb casino to handle thousands of concurrent connections, your TLS termination strategy significantly reduces Node.js overhead.

  12. jilimk Avatar

    Solid points about balancing risk & reward! Thinking about platforms like jilimk com, their KYC protocols highlight how crucial verified randomness is for strategic play – it’s all about informed decisions!

  13. jilikovip Avatar

    Jilikovip is on my radar now. The VIP program looks pretty sweet, and the user interface is easy to get around. Could be a good one for long-term play. Have a look: jilikovip.

  14. 1010betapp Avatar

    1010Betapp is my favourite gambling app for those long commutes! Easy to access, not bad for promotions either. Check it out at 1010betapp!

  15. 252winbet Avatar

    Alright, so I stumbled upon 252winbet and I’m kinda digging it. The interface is clean and they have a good selection of games. What do you guys think? Have a look: 252winbet.

Leave a Reply

Your email address will not be published. Required fields are marked *