Mahamudul Hasan Rubel
HomeAboutProjectsSkillsExperienceBlogPhotosContact
Mahamudul Hasan Rubel

Senior Software Engineer crafting high-performance web applications and SaaS platforms.

Navigation

  • Home
  • About
  • Projects
  • Skills
  • Experience
  • Blog
  • Photos
  • Contact

Get in Touch

Available for senior/lead roles and consulting.

bd.mhrubel@gmail.comHire Me

© 2026 Mahamudul Hasan Rubel. All rights reserved.

Built with using Next.js 16 & Tailwind v4

Back to Blog
DevOpsJune 20, 20264 min read

Nginx as a reverse proxy: The config explained line by line

Nginx as a reverse proxy is the backbone of reliable web traffic routing. Learn how to configure your setup line-by-line for production-grade performance.

NginxReverse ProxyDevOpsInfrastructureLinuxWeb ServersDockerCI/CD
A classic MS-DOS terminal screen displayed on a laptop keyboard with vivid illumination.

I spent my first year in production engineering treating Nginx configs like black boxes. I’d copy-paste snippets from Stack Overflow, pray they didn't crash the server, and move on. It worked—until it didn't. When a production spike hit and my upstream services started timing out, I realized I didn't actually know how to tune the proxy layer.

Nginx as a reverse proxy is more than just a proxy_pass directive. It’s about how you hand off connection state, handle buffering, and manage timeouts. If you’re running a Zero-downtime deploy with GitHub Actions: A practical guide, your proxy is the gatekeeper that keeps users from seeing 502 Bad Gateway errors while your containers swap.

The Anatomy of a Proxy Block

Let’s look at a standard configuration for a Node.js or Go service running on port 3000. We’ll place this inside a server block.

NGINX
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_cache_bypass $http_upgrade;
}

Here is what is actually happening under the hood:

  • proxy_pass: This is your target. Nginx resolves the address and forwards the request. If you're using Docker, you can use the service name here instead of an IP (e.g., http://my-api:3000).
  • proxy_http_version 1.1: By default, Nginx uses HTTP/1.0 for upstream connections, which doesn't support keep-alive. Setting this to 1.1 allows Nginx to reuse connections to your backend, which saves roughly 2-5ms per request by skipping the TCP handshake overhead.
  • proxy_set_header Host $host: This is critical. Without it, your backend app might think it's being accessed by its own internal IP rather than the domain name the user requested. If your app relies on virtual hosts, this line is non-negotiable.

Handling Headers and Real IPs

One of the biggest mistakes I see is failing to pass the user's real IP to the application. If you don't configure this, every request to your backend will look like it's coming from 127.0.0.1.

You need these lines to maintain visibility into your logs:

NGINX
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;

When you use Nginx as a reverse proxy, it acts as a man-in-the-middle. By passing these headers, you’re telling your application, "Hey, the request actually started here." If you’re ever curious about how this compares to Kubernetes-native routing, I’ve written about Kubernetes Ingress: NGINX vs Gateway API for traffic routing to help you decide when to stick with Nginx and when to upgrade your infrastructure.

The Trade-offs of Buffering

By default, Nginx will buffer the entire response from your backend before sending it to the client. This is great for slow clients—it frees up your backend worker immediately.

However, if you are streaming large files or using Server-Sent Events (SSE), buffering is the enemy. It will cause your connection to hang until the buffer is full. If you’re building an application where real-time data is key, you’ll need to disable it:

NGINX
proxy_buffering off;
proxy_request_buffering off;

I once spent about two days debugging a "frozen" dashboard update, only to realize Nginx was patiently waiting to fill a 1MB buffer before pushing the data to the browser. Disabling the buffer fixed it instantly.

Common Timeouts

Production traffic is messy. If your backend takes 60 seconds to process a report, but Nginx has a default timeout of 60 seconds, you’re going to have a bad time. You should define your timeouts explicitly:

NGINX
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;

Don't just set these to infinity. If you have an unresponsive service, you want the proxy to fail fast so you can recover, rather than hanging your entire worker pool.

Frequently Asked Questions

Q: Should I use Nginx or just expose my container ports directly? A: Always use a proxy. Nginx handles SSL termination, request buffering, and static file serving much more efficiently than most application frameworks.

Q: Why do I see 502 errors after a deployment? A: Usually, this means Nginx is trying to connect to a socket that doesn't exist yet or has closed. Check your upstream configuration and ensure your backend is actually listening on the port you specified.

Q: Does using Nginx as a reverse proxy slow things down? A: The overhead is negligible—usually less than 1ms. The security and flexibility benefits far outweigh the cost.

Final Thoughts

Configuring Nginx is a skill that evolves with your infrastructure. I still occasionally misconfigure a header or forget a timeout, and it usually happens during a high-traffic window. The best advice I can give is to keep your configs modular. Don't build one giant nginx.conf; use include directives to keep your logic clean.

What’s the one Nginx directive you’ve struggled with the most? We’ve all been there, staring at a config file at 3 AM. It’s part of the process.

Back to Blog

Similar Posts

Close-up of colorful programming code on a computer screen, showcasing digital technology.
DevOpsJune 20, 20264 min read

Zero-downtime deploy with GitHub Actions: A Practical Guide

Achieve a zero-downtime deploy with GitHub Actions using blue-green strategies. Learn how to keep your services running seamlessly during every release.

Read more
Close-up of blue ethernet cables hanging in a data center, highlighting technology connections.
DevOps
June 20, 2026
4 min read

Linux server hardening: Automate audits with Lynis and fail2ban

Linux server hardening doesn't have to be manual. Learn to use Lynis for automated security audits and fail2ban to block brute-force attacks effectively.

Read more
Shipping containers and cranes at Hamburg port showcasing global trade.
DevOpsJune 20, 20265 min read

Docker for app developers: A mental model that sticks

Master Docker for app developers by shifting your mental model. Learn how containers actually work, why they aren't VMs, and how to build efficient images.

Read more