What is Nginx?
Nginx (pronounced "engine-x") is a web server that also functions as a reverse proxy, load balancer, and HTTP cache. Created by Igor Sysoev in 2004 to handle the C10K problem (10,000 concurrent connections), it now powers over 30% of the web.
server {
listen 80;
server_name example.com;
location / {
proxy_pass http://localhost:3000;
proxy_set_header Host $host;
}
}
Unlike Apache's process-per-connection model, Nginx uses an event-driven, asynchronous architecture that handles thousands of connections with minimal memory.
Core Concepts
Server Blocks (Virtual Hosts)
Server blocks let you host multiple sites on one machine:
# Site 1
server {
listen 80;
server_name app.example.com;
root /var/www/app;
}
# Site 2
server {
listen 80;
server_name api.example.com;
location / {
proxy_pass http://localhost:8080;
}
}
Location Blocks
Location blocks match URL paths and define how to handle requests:
server {
# Exact match
location = /health {
return 200 'ok';
}
# Prefix match
location /api/ {
proxy_pass http://backend;
}
# Regex match
location ~* \.(jpg|png|gif)$ {
expires 30d;
add_header Cache-Control "public";
}
# Default fallback
location / {
try_files $uri $uri/ /index.html;
}
}
| Modifier | Priority | Behavior |
|---|---|---|
= | 1st | Exact match only |
^~ | 2nd | Prefix match, stops regex search |
~ | 3rd | Case-sensitive regex |
~* | 3rd | Case-insensitive regex |
| (none) | 4th | Prefix match |
Reverse Proxy
The most common Nginx use case — sitting in front of application servers:
upstream backend {
server 127.0.0.1:3000;
server 127.0.0.1:3001;
server 127.0.0.1:3002;
}
server {
listen 80;
location / {
proxy_pass http://backend;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
}
}
SSL/TLS Configuration
server {
listen 443 ssl http2;
server_name example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
# Modern TLS settings
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers off;
}
# Redirect HTTP to HTTPS
server {
listen 80;
server_name example.com;
return 301 https://$server_name$request_uri;
}
Common Patterns
SPA (Single Page App) Routing
location / {
try_files $uri $uri/ /index.html;
}
Gzip Compression
gzip on;
gzip_types text/plain text/css application/json application/javascript;
gzip_min_length 1000;
Rate Limiting
limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;
location /api/ {
limit_req zone=api burst=20 nodelay;
proxy_pass http://backend;
}
Where You'll See This
- Web hosting — Serving static files and proxying to app servers
- Load balancing — Distributing traffic across multiple backends
- SSL termination — Handling HTTPS at the edge
- CDN/Caching — Caching responses to reduce backend load
- API gateways — Routing and rate-limiting API traffic
- Docker/Kubernetes — Ingress controllers and sidecar proxies
Nginx vs Apache
| Feature | Nginx | Apache |
|---|---|---|
| Architecture | Event-driven | Process/thread per connection |
| Static files | Very fast | Fast |
| Config style | Centralized files | .htaccess + centralized |
| Modules | Compiled in | Dynamic loading |
| Best for | Reverse proxy, high concurrency | Shared hosting, .htaccess |
Common Gotchas
Every Nginx directive must end with a semicolon. A missing semicolon gives cryptic errors like "unexpected end of file" that point to the wrong line.
Always run nginx -t before reloading. It validates your config without disrupting live traffic. Then nginx -s reload to apply changes gracefully.
- Location block priority — Regex locations can override longer prefix matches. Use
^~to prevent this. - proxy_pass trailing slash —
proxy_pass http://backend/(with slash) strips the matched location prefix. Without slash, it passes the full URI. - try_files and proxy_pass — You cannot use both in the same location block. Use a named location instead.
- Config formatting — Messy configs with inconsistent indentation make it hard to spot nesting errors. Use a formatter to keep things clean.
Try It
Format Nginx Config"In nginx config, the semicolons are mandatory but the tears are optional."