What Is NGINX and How Does It Work? Architecture & Use Cases

large hero

PrivateAlps Team

June 16, 202620 min. read
Share

What Is NGINX and How Does It Work?

So you take over a Linux box from someone who left the company, and there's NGINX on it. Possibly nobody's touched the config in two years. Possibly it's the only thing keeping a creaky old Rails app alive at a thousand requests per second. Either way - here you are. What is NGINX used for in real-world setups, on bare metal or in the cloud? Most of the things that need to live between a browser and a backend. TLS. Load balancing. Caching. Rate-limiting that one endpoint someone's currently trying to brute-force. All of it usually, on one box, in one binary.

This isn't a stylistic preference, by the way. The web server you put in front of your stack is what decides how many open connections you can hold before your latency graph turns into a stairstep. It's also what decides what each idle keepalive costs you in RAM. And it's what decides - somewhat directly - whether your phone goes off at 3 a.m. with a security alert. The numbers back this up: per W3Techs, Nginx is used by 32.7% of all the websites whose web server is known. That puts it first, ahead of Cloudflare Server (27.8%) and Apache (23.7%) at the time of writing. And on the high-traffic end of the web - WordPress.org, TikTok, Cloudflare's own edge - you'll find most of them are running on the same binary or something derived from it.

Here's what's coming up. Bits inside the binary. The eight roles people put it in. Install steps for Ubuntu and RHEL. A reverse-proxy config that actually works. Seven hardening directives that aren't on by default. Some of this you probably know already. The rest tends to be what bites your team later.

AI Summary

NGINX is a high-performance, open-source web server and reverse proxy. Igor Sysoev started writing it back in 2002. The public release went out on October 4, 2004 - Sysoev picked the date deliberately, it's the anniversary of Sputnik. Architecture is event-driven and asynchronous. One master process, plus a small pool of workers. Each worker handles thousands of connections without spawning a thread per request. That's the design that solved C10K. It's also why this server shows up underneath Kubernetes Ingress, Cloudflare's edge, and a whole list of cloud and on-prem infrastructure you've probably touched today without thinking about it.

  • Built by Igor Sysoev (2002); first public release October 4, 2004
  • Master process + worker processes; one worker per CPU core is the typical default
  • Default config at /etc/nginx/nginx.conf; check syntax with nginx -t
  • Zero-downtime reload via nginx -s reload
  • Roles: HTTP server, reverse proxy, load balancer, HTTP cache, mail proxy, API gateway
  • Native WebSocket support; HTTP/3 over QUIC since version 1.25.0
  • Two flavours: free open-source build (BSD-2-Clause) and the commercial Plus subscription (F5)
  • The Plus tier brings active health checks, JWT/OIDC/SAML auth, a live activity dashboard, and a REST API for dynamic reconfiguration in cloud-native deployments

:::

What Is NGINX?

Shortest way to put it? NGINX is a web server and reverse proxy that holds thousands of concurrent connections inside a single worker process via a non-blocking event loop. No thread-per-connection. No process-per-connection. That's the one architectural choice that puts daylight between it and Apache. Apache, in classic prefork mode, hands every connection its own process. Fine when traffic is low. Less fine once concurrency climbs and the kernel starts burning more cycles juggling processes than serving actual bytes.

So why does any of this exist? The C10K problem - Dan Kegel's 1999 question about how a single server could handle ten thousand simultaneous clients. That was the wall. Sysoev's design was the way through it. So when people ask what is an NGINX server today, they're typically pointing at a Linux box - bare-metal, VPS, or cloud instance - running this binary as the front door for one or several of your apps. Inside each worker, the server organizes traffic in user space. The kernel does the heavy lifting via epoll on Linux, kqueue on BSD and macOS, IOCP on Windows. That split is what lets the whole thing scale linearly with cores while keeping each idle connection cheap. We're talking kilobytes per connection. Not megabytes.

Two flavours. Same source tree. The open-source build is free, BSD-2-Clause licensed, and it covers basically everything most teams actually need: web server, reverse proxy, load balancer, cache. The commercial Plus build is what F5 maintains. You buy it for specific reasons. Active health checks against upstreams. Native JWT/OIDC/SAML for security-sensitive APIs. The live activity dashboard. The REST API that lets you reconfigure upstream pools without editing files - useful in cloud environments where the backend pool changes constantly. None of those apply to your situation? The open-source build is fine. Don't overthink it. The full diff between editions sits in the official NGINX documentation.

DimensionNGINXApache HTTP Server
Connection modelEvent-driven, non-blockingThread- or process-per-connection (MPM)
Concurrency performanceExcellent at 10k+ concurrent connectionsDegrades sharply past a few thousand
Memory usage under loadStays roughly constant as connections growGrows linearly with active connections (prefork)
Static content speedNative sendfile() zero-copy deliverySlower; relies on standard file I/O
Dynamic contentProxies to FastCGI, uWSGI, gRPC, HTTP upstreamsNative mod_php, mod_python in-process
Configuration styleCentralized files, no per-directory overridesCentralized + .htaccess per directory
Typical use caseReverse proxy, edge load balancer, static + APIShared hosting, legacy LAMP stacks

What Is NGINX Used For?

The list goes: web server, reverse proxy, load balancer, HTTP cache, SSL/TLS terminator, WebSocket proxy, mail proxy, API gateway. Eight roles. The thing people new to it don't expect is that most of those roles run at the same time, in the same process, off the same config tree.

They expect a tool that does one thing. What they get instead is a Swiss Army knife where most of the tools work simultaneously without arguing with each other. Your typical edge instance? It terminates TLS, distributes traffic to an upstream pool, serves the static frontend out of /var/www/, and rate-limits the API. One binary. One config tree. One nginx -s reload to ship a change.

RoleHow It WorksTypical Production Scenario
HTTP/HTTPS web serverServes files from disk via sendfile() zero-copy. HTTP/3 over QUIC since NGINX 1.25.0 (released May 23, 2023)Static sites, SPA frontends, JAMstack, asset delivery
Reverse proxyForwards client requests upstream via proxy_pass; rewrites headers, terminates TLSNode.js, Python, Go, or PHP-FPM apps behind a public edge
Load balancerDistributes traffic across an upstream block using round-robin, least_conn, or ip_hashHorizontally scaled API tier, microservices, multi-AZ failover
HTTP cacheStores upstream responses on disk via proxy_cache_pathCaching dynamic CMS output (WordPress, Drupal) at the edge
SSL/TLS terminatorDecrypts TLS at the edge; backend speaks plain HTTP inside the trust boundaryLet's Encrypt + certbot automation; offloading crypto from app servers
WebSocket proxyUpgrades HTTP/1.1 connections via proxy_http_version 1.1 and the Upgrade headerReal-time apps: chat, collaborative editors, trading dashboards
Mail proxyProxies IMAP, POP3, and SMTP with auth handover to a backend HTTP serviceHosted mail platforms, multi-tenant mail gateways
API gatewayCombines proxy_pass, URI routing, and limit_req to enforce per-route policyPublic REST/gRPC APIs, rate-limited partner endpoints

A quick aside on Kubernetes, since it always comes up. The NGINX Ingress Controller is, for better or worse, the de-facto default for HTTP traffic going into a cluster. Watches the K8s API for Ingress and Service objects. Regenerates the config every time something changes. Runs as a pod, not a daemon - which means it restarts on crash and gets scheduled across nodes. If you're routing HTTP traffic in Kubernetes, you're almost certainly running this or something that builds on it.

How Does NGINX Work: Architecture

One master process. A fixed pool of workers. Each worker is single-threaded and runs its own event loop. That event loop is what makes the whole thing scale.

The master process reads the config, binds the listening sockets, and spawns the workers. It handles signals - nginx -s reload sends a SIGHUP, master reads the new config, spawns new workers with the updated config, and waits for the old workers to drain their connections before killing them. Zero-downtime reloads. No connection drop.

Each worker runs a non-blocking event loop using epoll (Linux), kqueue (BSD/macOS), or IOCP (Windows). The event loop multiplexes thousands of file descriptors in one thread. When a connection arrives: accept, read headers, match server block and location, decide (serve static, proxy upstream, return cached). No thread context switch per connection. No process spawn per connection. The cost of an idle keepalive connection is measured in bytes of memory for the event slot and fd, not in thread stack (typically 8MB per thread on Linux).

The tuning knobs that actually matter:

worker_processes auto;          # One per CPU core
worker_connections 1024;        # Per-worker fd limit
keepalive_timeout 65;           # Seconds to hold idle connections
sendfile on;                    # Zero-copy file delivery
tcp_nopush on;                  # Batch packets; works with sendfile
gzip on;                        # Response compression

worker_processes auto is almost always right. Sets one worker per logical CPU core. The exception: I/O-bound deployments where you're proxying slow upstreams and want more workers to have more event loops available, at the cost of more memory.

How to Install NGINX

Ubuntu / Debian:

sudo apt update
sudo apt install nginx
sudo systemctl enable --now nginx
nginx -t    # Validate config syntax

RHEL / Fedora / Rocky Linux:

sudo dnf install nginx
sudo systemctl enable --now nginx
nginx -t

For a newer version than the distro packages, add the upstream NGINX repo and install from there. Distro packages tend to lag behind mainline by one or two minor versions.

Reverse proxy config for a Node.js app on port 3000:

server {
    listen 80;
    server_name 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 Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }
}

The Upgrade and Connection headers are what WebSocket support requires. Leave them out and WebSocket upgrade requests fail silently - the connection looks like it succeeded and then immediately drops.

NGINX Security Hardening

A fresh install isn't hardened. The defaults exist for compatibility, not for facing the open internet - and certainly not for cloud environments where your server is exposed to scanners within minutes of going up. Server version disclosure: on. Some builds still happily accept TLSv1.0 and TLSv1.1. Rate limiting? Not unless you configure it yourself. Every directive in this section is opt-in, and skipping them turns your NGINX deployment from a security layer into a fast attack surface.

ThreatAttack VectorNGINX-Level Mitigation
Server version disclosureServer: nginx/1.25.3 header leaks the exact version, making targeted CVE lookup trivialserver_tokens off; in http block
ClickjackingSite rendered inside a hostile <iframe> to harvest credentialsadd_header X-Frame-Options "SAMEORIGIN" always;
HTTP flood / brute forceLogin or API endpoint hit thousands of times per second from one IPlimit_req_zone $binary_remote_addr zone=api:10m rate=10r/s; + limit_conn_zone
MIME-type sniffingBrowser executes uploaded .txt as JavaScript based on content guessingadd_header X-Content-Type-Options "nosniff" always;
Weak TLS protocolsTLSv1.0 / TLSv1.1 downgrade attacks (BEAST, POODLE)ssl_protocols TLSv1.2 TLSv1.3;
Dotfile exposure.git/, .env, .htaccess served as plain files, leaking secretslocation ~ /\. { deny all; }
Oversized headersMemory exhaustion via abusive header sizesclient_header_buffer_size 1k; large_client_header_buffers 2 1k;

Take nothing else out of this section if you don't want to. But take these five lines and paste them into every production nginx.conf you maintain:

  • server_tokens off; - strips the version string from response headers and error pages
  • ssl_protocols TLSv1.2 TLSv1.3; - kills every protocol version with known weaknesses
  • limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s; - per-IP request budget
  • location ~ /\. { deny all; } - blocks every dotfile path (.git, .env, .aws, you name it)
  • user nginx; - runs workers as a non-root, non-login system account

For TLS specifically: don't write the cipher list yourself. Just don't. Use the Mozilla SSL Configuration Generator - it outputs an NGINX-ready protocol and cipher set for each policy tier (modern, intermediate, old) and gets updated whenever a new attack lands in the wild. There's roughly zero reason to write that block by hand in 2026.

Summary

Shortest version of all of this: NGINX solves C10K with a master/worker architecture that scales linearly with cores and keeps each idle connection cheap. Whatever role it plays - web server, reverse proxy, load balancer, API gateway, cloud Ingress controller - comes down to your deployment topology, not a different binary. Security hardening is opt-in. Mess up the defaults, you've got a fast attack surface. Get them right, you've got the same edge layer Cloudflare and Netflix run.

The server behaves very differently on bare metal than it does on shared hosting or in cloud environments. On a managed platform you typically can't touch worker_processes. The kernel knobs (net.core.somaxconn, worker_rlimit_nofile) are off-limits. Recompiling for a custom module isn't a conversation. PrivateAlps runs bare-metal in Switzerland - full root access for your team, custom NGINX builds (HTTP/3, stream, whatever you actually need), strong physical security, and Swiss revDSG jurisdiction for teams where data residency has to be more than a checkbox on a compliance form somewhere.

FAQ

What is NGINX?

NGINX is an open-source, event-driven HTTP server and reverse proxy. Igor Sysoev started writing it in 2002. In one line: a non-blocking event-loop binary that holds thousands of concurrent connections in a single worker process, where Apache's classic prefork would have spawned a thread or process per connection instead. It's several things at once: HTTP server, reverse proxy, load balancer, HTTP cache, API gateway - depends which directives you've got turned on. Licensing: BSD-2-Clause for the open-source build, commercial F5 subscription for NGINX Plus.

What is NGINX used for?

Web server, reverse proxy, load balancer, SSL/TLS terminator, Kubernetes Ingress controller - those are the big five. Most production instances run several of those at once: terminating TLS at the edge, fanning requests out to an upstream pool, caching responses, all in the same config tree.

What is the difference between NGINX and Apache?

NGINX wins on high concurrency and static-file delivery. That's the event loop, not marketing. Apache wins where you specifically need .htaccess per-directory rules or in-process mod_php. The pattern you'll see most often in real deployments? Hybrid. NGINX as the public-facing reverse proxy. Apache + PHP-FPM behind it. NGINX does what it's good at - connections, TLS, caching. Apache does what it's good at - running PHP. Neither one has to do something it's bad at.

What is NGINX reverse proxy?

It's an NGINX instance that takes client traffic and forwards it to backend application servers, hiding the upstream from the client. Two big production wins. Backend isolation - internal IPs and ports stay private. Centralized SSL/TLS termination - cert renewal happens in one place, not one per service.

How do I install and start NGINX?

Ubuntu: sudo apt install nginx, then sudo systemctl enable --now nginx, validate with nginx -t. Same flow on Debian. RHEL/Fedora: just swap apt for dnf. The official install guide on nginx.org covers the upstream repo if you need a newer version than the distro ships with.

What is NGINX web server?

NGINX in the web-server role specifically: an instance handling client requests directly - reading files from disk, pushing them back out via sendfile() zero-copy. Distinct from the reverse-proxy role, where NGINX forwards each request to an upstream application process instead of touching the filesystem at all. Both can run inside the same instance. Different location blocks in the same server block can serve static assets straight from disk and proxy /api/ to a Node.js process upstream.

What is NGINX and how does it work?

Event-driven web server and reverse proxy. One master process reads the config. A small pool of worker processes handles every connection through a non-blocking event loop, using epoll on Linux or kqueue on BSD. A single request goes through TCP accept, header parsing, server and location matching, static delivery or upstream proxying, response buffering, and client write - all without ever spawning a thread per request.

Solusi hosting yang berfokus pada privasi dengan lokasi offshore, opsi pembayaran anonim, dan perlindungan data absolut.

Tetap Terhubung

Newsletter

Pembaruan privasi bulanan. Berhenti berlangganan kapan saja.

Telegram

Telegram QR Code