Nginx Explained in Plain English

birdculture1 pts0 comments

Nginx as a Reverse Proxy | Engineering Notes before<br>the browser paints. Runs synchronously, no defer/async.<br>--><br>Skip to content<br>Go back<br>Nginx as a Reverse Proxy<br>15 Jun, 2026

Your app runs on port 3000.

node server.js<br># listening on 0.0.0.0:3000<br>You open http://localhost:3000 and it works.

Then it has to go live. A real domain. HTTPS on port 443. The same app, now reachable from the internet.

The first instinct is to make the app listen on 443 directly. That works for about a day, until the app also needs to serve static files, handle TLS certificates, survive restarts without dropping traffic, limit how fast a single client can hit it, and eventually run as more than one process behind one address.

A single application process is not a good front door.

Table of contents

Open Table of contents

The Problem Nginx Is Solving

The Big Idea

How Nginx Is Built

How A Request Flows

Server Blocks

Location Blocks

proxy_pass And The Trailing Slash

Passing The Real Client Information

WebSockets Need An Upgrade

Buffering And Timeouts

HTTP/2 vs HTTP/1.1

Compressing Responses

Tuning Workers To The Server

Rate Limiting

Hiding Server Information

Restricting Who Can Embed Your Site

Multiple Backends With Upstream

Failure Modes

A Practical Config

Operating Nginx

Final Thoughts

The Problem Nginx Is Solving

An application process is good at running application logic. It is not built to be the thing the public internet talks to directly.

When the app is the only layer, it has to handle:

TLS termination and certificate renewal

serving static files efficiently

slow clients holding connections open

request size limits and timeouts

rate limiting and abuse control

routing different paths to different services

staying reachable while the app itself restarts

Every one of these is work that has nothing to do with the actual business logic.

Nginx takes that work and sits in front. The app moves behind it and goes back to doing one job.

The Big Idea

Nginx becomes the single front door.

The public talks to Nginx. Nginx talks to the app over a private connection.

client -> nginx (443, TLS) -> app (3000, plain http)<br>The app no longer faces the internet. It listens on a local port that only Nginx reaches. Nginx handles the parts that face the outside world: the certificate, the public port, the timeouts, the limits.

This is what “reverse proxy” means here. A normal proxy sits in front of clients and talks to many servers on their behalf. A reverse proxy sits in front of servers and takes requests from many clients on their behalf.

How Nginx Is Built

Nginx runs as one master process and a set of worker processes.

master process<br>├── worker process<br>├── worker process<br>└── worker process<br>The master process reads the config, binds the ports, and manages the workers. It does not handle a single request itself. When you reload the config, the master is what starts new workers and retires old ones.

The workers do the actual work. Each worker is a single process running an event loop.

The older model, used by servers like Apache in its default setup, gave each connection its own thread or process. A thousand idle clients meant a thousand threads sitting around, each using memory and forcing the kernel to switch between them.

A single Nginx worker takes a different approach. It keeps thousands of connections open at once and only touches a connection when something actually happens on it, using the kernel’s event notification (epoll on Linux). When a connection is waiting on the network, the worker is not blocked on it. It moves on and services another.

This is why a slow client holding a connection open is cheap for Nginx and expensive for a thread-per-connection app. It is also the reason Nginx is placed in front of the app: it absorbs slow and idle connections so the app only deals with complete, ready requests.

How A Request Flows

A request to https://example.com/api/users goes through a few steps.

The client opens a TLS connection to Nginx on port 443.

Nginx terminates TLS and now has a plain HTTP request.

Nginx matches the request against its server and location rules.

Nginx opens a connection to the app on 127.0.0.1:3000.

The app responds to Nginx.

Nginx sends the response back to the client over the encrypted connection.

The app sees a plain HTTP request coming from Nginx on the local machine. It never sees the TLS handshake and never sees the client directly.

Server Blocks

A server block tells Nginx how to handle traffic for a given name and port.

server {<br>listen 443 ssl;<br>server_name example.com;

ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;<br>ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

location / {<br>proxy_pass http://127.0.0.1:3000;<br>listen 443 ssl means this block handles HTTPS.

server_name decides which block answers when a request arrives. One Nginx instance can hold many server blocks for many domains on the same port, and the Host header...

nginx process server request connection port

Related Articles