Nginx (pronounced “engine-x”) is an open-source web server, reverse proxy and load balancer built on an event-driven, asynchronous architecture that lets a small, fixed number of processes handle many thousands of concurrent connections. Among web servers, it is the usual choice for serving static files, terminating TLS and passing dynamic requests to application back ends such as PHP-FPM, Node.js or Python application servers.
Nginx was first released publicly in 2004 to address the C10k problem, the difficulty of serving ten thousand simultaneous clients on one machine. It is distributed under a two-clause BSD license, and a commercial edition, NGINX Plus, adds features such as active health checks and a live monitoring API.
How the Nginx event-driven architecture works
Nginx runs as one master process and several worker processes. The master process runs with elevated privileges, reads the configuration, binds to ports such as 80 and 443 and manages the workers; the workers handle all client traffic under an unprivileged account.
Each worker runs a non-blocking event loop on top of the operating system’s notification mechanism, such as epoll on Linux or kqueue on BSD and macOS. Instead of dedicating a thread to each connection and waiting while it is idle, a worker reacts only when a socket is ready to read or write. As a result, memory use grows slowly with connection count, because an idle keep-alive connection costs only a few kilobytes of state rather than a whole thread or process.
The practical ceiling on concurrent connections is roughly worker_processes multiplied by worker_connections, limited further by the file descriptor limit. When Nginx works as a reverse proxy, each client normally consumes two connections, one to the client and one to the upstream server, so the effective client capacity is about half.
The table below lists the core directives that shape this model and their usual values.
| Directive | Typical value | What it controls |
|---|---|---|
| worker_processes | auto (one per CPU core) | Number of worker processes |
| worker_connections | 512 compiled default, often 1024 or more | Connections each worker may hold open |
| worker_rlimit_nofile | At least twice worker_connections | File descriptor limit per worker |
| keepalive_timeout | 75 s default, often 15-65 s | How long idle client connections stay open |
| client_max_body_size | 1 MB default | Largest accepted request body, such as uploads |
| sendfile | on for static content | Kernel-level file transfer without copying to user space |
Configuration structure and request matching
Nginx is configured through plain-text files with nested contexts, usually rooted at /etc/nginx/nginx.conf. The http context holds global web settings, each server block defines a virtual host selected by listen and server_name, and each location block defines how a group of URIs is handled.
Location selection follows a fixed precedence order rather than the order in the file, which is one of the most common sources of configuration errors. The table summarizes the rules Nginx applies when it chooses a location for a request URI.
| Modifier | Match type | Precedence |
|---|---|---|
| = | Exact match | Highest; search stops immediately |
| ^~ | Prefix match that skips regex checks | Wins if it is the longest prefix |
| ~ and ~* | Regular expression, case-sensitive or not | First matching regex in file order |
| None | Ordinary prefix match | Longest prefix, used if no regex matches |
Changes take effect through a graceful reload: nginx -t validates the syntax, and nginx -s reload makes the master start new workers with the new configuration while old workers finish their open requests. Unlike Apache, Nginx has no per-directory .htaccess files, which removes a filesystem lookup on every request but means all rules live in the central configuration.
Nginx compared with other web servers
Nginx differs from its neighbors mainly in concurrency model, configuration style and dynamic content handling. The comparison below covers the servers most often evaluated alongside it.
| Server | Concurrency model | Dynamic content | Distinctive trait |
|---|---|---|---|
| Nginx | Event-driven workers | Proxied to PHP-FPM or app servers | Low memory, strong reverse proxy |
| Apache | Prefork, worker or event MPM | Embedded modules or PHP-FPM | .htaccess and broad module set |
| Caddy | Go runtime with goroutines | Reverse proxy or FastCGI | Automatic HTTPS by default |
| OpenLiteSpeed | Event-driven | LSAPI for PHP | .htaccess rewrite compatibility |
Nginx does not execute PHP itself. It forwards PHP requests over the FastCGI protocol with fastcgi_pass to a PHP-FPM pool, usually through a Unix socket, and serves images, CSS and JavaScript directly from disk. This separation of static and dynamic work is the reason a common stack places Nginx in front of every application tier.
Typical roles in a server stack
The same Nginx binary can fill several distinct roles, and many deployments combine them in one configuration. Choosing the role determines which modules and directives matter most.
| Role | Key directives | Typical benefit |
|---|---|---|
| Static file server | root, try_files, expires | Fast delivery with low CPU use |
| Reverse proxy | proxy_pass, proxy_set_header | Shields and offloads application servers |
| Load balancer | upstream, least_conn, ip_hash | Spreads traffic across back ends |
| TLS termination | ssl_certificate, ssl_protocols | Central certificate and cipher management |
| Cache layer | proxy_cache, fastcgi_cache | Serves repeated responses without the back end |
Open-source Nginx balances load with round robin by default and also supports least connections, IP hash, generic hash and random selection. Its health checking is passive: a back end is marked unavailable after max_fails failed attempts, one by default, within fail_timeout, 10 seconds by default. Active probing of back ends requires NGINX Plus or a third-party module.
Limitations and common mistakes
Nginx is efficient, but its defaults and matching rules cause predictable misconfigurations. Most problems in production trace back to a short list of errors.
- Missing proxy headers: without
Host,X-Forwarded-ForandX-Forwarded-Proto, applications log the proxy address and generate wrong redirect URLs. - Unsafe PHP handling: passing any URI ending in .php to PHP-FPM without checking that the file exists can let uploaded files be executed as scripts.
- Low upload limits: the 1 MB client_max_body_size default produces HTTP 413 errors on media uploads.
- Misread location order: placing a regex location expecting file order to win over a longer prefix match.
- Blocking modules: third-party code that performs blocking I/O inside a worker stalls every connection that worker serves.
Dynamic modules have been supported since version 1.9.11, yet many modules must still be compiled against the exact Nginx version in use. That makes upgrades slower than with servers that load plugins at run time.
In plain words
Nginx is the receptionist at the front door of a website. It greets every visitor, hands out ready-made items such as pictures and style files immediately, and passes only the requests that need real work to the specialists behind it.
Its strength is that one receptionist can juggle thousands of visitors at once, because it never stands idle waiting for one person to finish. That is why so many busy sites put Nginx first in line.
A real-world example
A small agency runs an online store on a virtual server with 4 CPU cores and 8 GB of RAM. Before a seasonal sale, pages slow down because the old setup serves every image through the PHP application.
The administrator places Nginx in front with worker_processes auto, 4,096 worker connections, a try_files rule that serves product images directly from disk and fastcgi_cache for anonymous visitors with a 60-second validity. PHP-FPM now receives only cart, checkout and logged-in requests, and client_max_body_size is raised to 20 MB for product photo uploads.
During the sale, the store handles about five times more visitors with lower CPU use on the PHP tier, and response times for cached catalog pages stay below 50 milliseconds.