Put Nginx in front of your Node app — forward requests with proxy_pass, pass the headers your app needs to see the real client, support WebSockets, and cache responses at the proxy.
Your Node/Python/Java app listens on a port like 3000, but you do not expose that to the internet directly. Instead Nginx listens on 80/443 and forwards requests to your app — this is a "reverse proxy." It lets Nginx handle TLS, serve static files, load-balance, and shield your app, while your app focuses on logic. proxy_pass names where to forward.
server {
listen 80;
server_name example.com;
location / {
# Forward every request to the app running on this machine.
proxy_pass http://127.0.0.1:3000;
}
}Once Nginx sits in front, your app sees Nginx as the client — every request looks like it came from 127.0.0.1 over plain HTTP. You fix that by forwarding the original details: Host (the domain the user typed), X-Real-IP and X-Forwarded-For (the real client IP, needed for logging and rate limiting), and X-Forwarded-Proto (so your app knows the user was on HTTPS). Without these, things like "secure cookies" and real-IP logging break.
location / {
proxy_pass http://127.0.0.1:3000;
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;
# Allow WebSocket connections to be upgraded and stay open:
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}Nginx can cache your app's responses so repeat requests are answered from the proxy without ever hitting your app — useful for expensive but slow-changing pages or API results. Define a cache location once in the http block, then turn it on per location. Nginx honors your app's Cache-Control headers, and proxy_cache_valid sets a fallback duration.
# In http { }: reserve a 10 MB key index, 1 GB of cached bodies.
proxy_cache_path /var/cache/nginx keys_zone=app_cache:10m max_size=1g;
# In the proxied location:
location /api/ {
proxy_pass http://127.0.0.1:3000;
proxy_cache app_cache;
proxy_cache_valid 200 60s; # cache OK responses for 60s
add_header X-Cache-Status $upstream_cache_status; # HIT / MISS
}