본문으로 건너뛰기
Previous
Next
Nginx Complete Guide | Reverse Proxy· Load Balancing

Nginx Complete Guide | Reverse Proxy· Load Balancing

Nginx Complete Guide | Reverse Proxy· Load Balancing

이 글의 핵심

A complete Nginx guide: internals (event loop, master/worker model, config inheritance), load-balancing algorithms, production patterns (keepalive pools, rate limits, graceful reload), plus static files, reverse proxy, SSL/TLS, caching, gzip, and a full-stack example.

What this post covers

This is a complete guide to building a high-performance web server with Nginx. After a short internals section (event loop, master/worker model, configuration inheritance, upstream algorithms, production patterns), it walks through installation, reverse proxying, load balancing, SSL/TLS, caching, and tuning?�with practical examples.

From the field: After replacing Apache with Nginx, we increased concurrent capacity by about 5× and cut memory usage by roughly 60%.

Introduction: ?�Our web server feels slow??

Real-world scenarios

Scenario 1: Traffic spikes make the site slow

Apache often struggles past roughly 1,000 concurrent users in common configurations. Nginx routinely handles 10,000+ connections.

Scenario 2: Static file serving is slow

The application server is serving static assets. Let Nginx serve them directly?�it is much faster.

Scenario 3: SSL setup feels complicated

Let’s Encrypt can feel fiddly. Certbot plus the Nginx plugin makes certificate issuance and renewal straightforward.


1. What is Nginx?

Key characteristics

Nginx is a high-performance web server and reverse proxy.

Common use cases:

  • Web server: static file serving
  • Reverse proxy: fronting backends
  • Load balancer: distributing traffic
  • SSL termination: handling HTTPS
  • Caching: caching upstream responses

Performance (order-of-magnitude, not a benchmark):

  • Concurrent connections: 10,000+
  • Memory: on the order of ~2.5 MB per worker (typical baseline)

2. Internals: event loop, workers, inheritance, load balancing & production patterns

If you only ever copy snippets, you will hit tuning ceilings and painful incidents. This section ties together the process model, event-driven I/O, configuration contexts, upstream algorithms, and production operating patterns.

Event-driven architecture

Traditional thread/process-per-connection servers allocate resources per request. As concurrency grows, context switching and memory overhead dominate. Each Nginx worker runs an event loop and can handle many connections with few processes.

  • Event modules: On Linux, Nginx uses epoll; on BSD/macOS, kqueue. events { use epoll; } selects that path explicitly (when supported).
  • One worker, many connections: A worker only does work when sockets are ready. Non-blocking sockets plus kernel readiness notifications avoid blocking the whole process.
  • sendfile: Reduces copies when moving data from disk to socket?�important for static files.
  • worker_connections: Per-worker cap on simultaneous connections. Rough capacity is related to worker_processes × worker_connections, but you must also align file descriptor limits (ulimit -n) and real traffic patterns.

This is why Nginx scales toward C10K-class concurrency. CPU-heavy TLS handshakes and large bodies still concentrate load on workers?�so tune worker count, hardware, and TLS session resumption together.

Worker process model

Nginx splits responsibilities between a master and worker processes.

  • Master: Reads configuration, forks workers, and manages lifecycle. Privileged steps (e.g., binding to port 80) typically happen before workers handle traffic.
  • Workers: Run the actual request path?�HTTP, reverse proxying, cache I/O, etc. worker_processes auto is a common choice to track CPU cores.
  • Graceful reload: nginx -s reload / SIGHUP replaces workers with a new configuration without dropping in-flight work in the common case?�still validate timeouts and upstream behavior after changes.
  • Shutdown signals: SIGTERM/SIGQUIT request graceful shutdown; SIGKILL is immediate. Check what your systemd unit or deploy script sends.

Workers do not share application memory. Shared caches usually mean OS page cache or an external store (Redis, etc.).

Configuration inheritance and merging

Nginx configuration is a tree of contexts: main ??events, http ??server ??location (plus upstream, mail, etc., when used).

  • Inheritance: A directive in http (e.g., gzip on) applies to nested server blocks unless overridden lower in the tree.
  • include: Splits files but merges into one logical tree?�think ?�composition,??not isolation.
  • location matching: Exact = ??longest prefix ??if ^~ wins, skip regex ??first matching regex ~ / ~*. Heavy if usage is hard to reason about; prefer map and explicit location splits when possible.
  • default_server: Chooses the default server block when Host does not match?�important for multi-tenant setups.

Use nginx -t and small, reviewable includes?�otherwise ?�what did the parent block leave on???becomes guesswork.

Load-balancing algorithms (deep dive)

The upstream algorithm should match backend load shape and session stickiness needs.

MethodSummaryWhen it shines
Default (round robin)Rotate in orderSimilar backends, similar per-request cost
least_connPick fewest active connectionsVariable upstream latency, long-lived connections
ip_hashSticky by client IPLocal session state (watch NAT and mobile IP churn)
hash ??consistentConsistent hashing ringCache sharding; smoother moves when nodes change
random twoPick two at random, then apply a rule (e.g., least_conn)Open-source option since 1.15+

Combine with weight, down, backup, and passive health via max_fails / fail_timeout. Active health checks are often Nginx Plus, another LB, or a service mesh.

upstream api {
    least_conn;
    server 10.0.0.1:8080 max_fails=3 fail_timeout=30s;
    server 10.0.0.2:8080 max_fails=3 fail_timeout=30s;
    server 10.0.0.3:8080 backup;
}

upstream cache_nodes {
    hash $request_uri consistent;
    server 10.0.0.10:11211;
    server 10.0.0.11:11211;
}

Production Nginx patterns

  • TLS termination + upstream keepalive: HTTPS to clients, HTTP inside the DC is common; pair with upstream connection pools (proxy_http_version 1.1, clear Connection, keepalive inside upstream) to avoid reconnect storms to backends.
  • proxy_next_upstream: Decide which errors/timeouts retry on another peer. Be careful with non-idempotent requests?�pair settings with non_idempotent rules where appropriate.
  • Rate limiting: limit_req_zone / limit_req for abuse; limit_conn for concurrent connections per key.
  • Observability: stub_status (if built-in), exporters, structured access logs (log_format JSON) for latency and cache hit ratio.
  • Shipping config: Always nginx -t before reload. Store configs in Git and align with IaC to avoid snowflake servers.

The hands-on sections below (load balancing, SSL, caching) are where these ideas become concrete nginx.conf snippets.


3. Installation

Ubuntu

sudo apt update
sudo apt install nginx
# Start
sudo systemctl start nginx
# Enable on boot
sudo systemctl enable nginx
# Check status
sudo systemctl status nginx

Docker

docker run -d -p 80:80 nginx:latest

4. Basic configuration

nginx.conf

# /etc/nginx/nginx.conf
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
    worker_connections 1024;
}
http {
    include /etc/nginx/mime.types;
    default_type application/octet-stream;
    log_format main '$remote_addr - $remote_user [$time_local] "$request" '
                    '$status $body_bytes_sent "$http_referer" '
                    '"$http_user_agent"';
    access_log /var/log/nginx/access.log main;
    sendfile on;
    tcp_nopush on;
    keepalive_timeout 65;
    gzip on;
    include /etc/nginx/conf.d/*.conf;
}

5. Static file serving

# /etc/nginx/conf.d/default.conf
server {
    listen 80;
    server_name example.com;
    root /var/www/html;
    index index.html;
    location / {
        try_files $uri $uri/ =404;
    }
    location ~* \.(jpg|jpeg|png|gif|ico|css|js)$ {
        expires 1y;
        add_header Cache-Control "public, immutable";
    }
}

6. Reverse proxy

Basic setup

server {
    listen 80;
    server_name api.example.com;
    location / {
        proxy_pass http://localhost:8000;
        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 X-Forwarded-Proto $scheme;
    }
}

WebSocket

location /ws {
    proxy_pass http://localhost:3000;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
}

7. Load balancing

For algorithm trade-offs and max_fails / backup, see section 2. The snippets below are quick copy-paste references.

Round Robin (default)

upstream backend {
    server backend1.example.com;
    server backend2.example.com;
    server backend3.example.com;
}
server {
    listen 80;
    location / {
        proxy_pass http://backend;
    }
}

Least connections

upstream backend {
    least_conn;
    server backend1.example.com;
    server backend2.example.com;
}

IP hash (sticky sessions)

upstream backend {
    ip_hash;
    server backend1.example.com;
    server backend2.example.com;
}

Weighted servers

upstream backend {
    server backend1.example.com weight=3;
    server backend2.example.com weight=2;
    server backend3.example.com weight=1;
}

Consistent hash (hash + consistent)

Useful when you want stable mapping across nodes (e.g., cache sharding) with less churn when the set changes.

upstream shard {
    hash $request_uri consistent;
    server 10.0.0.1:8080;
    server 10.0.0.2:8080;
}

random two (open source 1.15+)

Pick two backends at random, then send to the better candidate (here, fewer active connections).

upstream backend {
    random two least_conn;
    server backend1.example.com;
    server backend2.example.com;
    server backend3.example.com;
}

8. SSL/TLS

Let’s Encrypt

# Install Certbot
sudo apt install certbot python3-certbot-nginx
# Obtain certificates
sudo certbot --nginx -d example.com -d www.example.com
# Test renewal
sudo certbot renew --dry-run

SSL server block

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;
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers HIGH:!aNULL:!MD5;
    ssl_prefer_server_ciphers on;
    location / {
        proxy_pass http://localhost:8000;
    }
}
# HTTP ??HTTPS redirect
server {
    listen 80;
    server_name example.com;
    return 301 https://$server_name$request_uri;
}

9. Caching

Proxy cache

proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=my_cache:10m max_size=1g inactive=60m;
server {
    location / {
        proxy_cache my_cache;
        proxy_cache_valid 200 60m;
        proxy_cache_valid 404 1m;
        proxy_cache_bypass $http_cache_control;
        add_header X-Cache-Status $upstream_cache_status;
        proxy_pass http://backend;
    }
}

10. Performance tuning

Gzip compression

gzip on;
gzip_vary on;
gzip_min_length 1024;
gzip_types text/plain text/css text/xml text/javascript 
           application/json application/javascript application/xml+rss;

Connection tuning

# Worker processes
worker_processes auto;
# Connections
events {
    worker_connections 2048;
    use epoll;
}
# Keepalive
keepalive_timeout 65;
keepalive_requests 100;

Upstream keepalive (backend connection pool)

Opening a new TCP connection per request to backends adds latency and can exhaust local ports. For HTTP/1.1 upstream pools, set keepalive on the upstream and clear Connection on the proxy hop.

upstream api {
    server 127.0.0.1:8080;
    keepalive 64;
}
server {
    location / {
        proxy_http_version 1.1;
        proxy_set_header Connection "";
        proxy_pass http://api;
    }
}

Buffer sizes

client_body_buffer_size 10K;
client_header_buffer_size 1k;
client_max_body_size 8m;
large_client_header_buffers 2 1k;

11. Full-stack example

The following is a sample Nginx configuration for a typical app.

# /etc/nginx/conf.d/app.conf
upstream frontend {
    server localhost:3000;
}
upstream backend {
    server localhost:8000;
    server localhost:8001;
    server localhost:8002;
}
# HTTP ??HTTPS
server {
    listen 80;
    server_name myapp.com www.myapp.com;
    return 301 https://$server_name$request_uri;
}
# HTTPS
server {
    listen 443 ssl http2;
    server_name myapp.com www.myapp.com;
    ssl_certificate /etc/letsencrypt/live/myapp.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/myapp.com/privkey.pem;
    # Frontend (React)
    location / {
        proxy_pass http://frontend;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
    # Backend API
    location /api {
        proxy_pass http://backend;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        
        # CORS
        add_header Access-Control-Allow-Origin *;
        add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS";
    }
    # Static assets
    location /static {
        alias /var/www/static;
        expires 1y;
        add_header Cache-Control "public, immutable";
    }
}

Connecting this to interviews and your resume

Being able to explain reverse proxying, SSL, and caching from real operations experience helps in infrastructure and backend interviews. For CS and systems-style questions, see the [coding test & interview strategy guide](/en/blog/coding-test-strategy-guide/; for how to phrase this on a resume, see the [developer job hunting guide](/en/blog/developer-job-hunting-practical-tips/.


Summary and checklist

Key takeaways

  • Nginx: high-performance web server
  • Reverse proxy: sits in front of backends
  • Load balancing: spreads traffic across instances
  • SSL/TLS: HTTPS for users and upstreams
  • Caching: cache responses to reduce load
  • Scale: designed for very high concurrent connection counts

Production checklist

  • Install Nginx
  • Configure reverse proxy
  • Set up load balancing
  • Obtain SSL certificates
  • Configure caching
  • Tune performance
  • Add monitoring

  • [Kubernetes practical guide](/en/blog/kubernetes-practical-guide/
  • [Docker Compose complete guide](/en/blog/docker-compose-complete-guide/
  • [Terraform practical guide](/en/blog/terraform-practical-guide/

Keywords covered in this post

Nginx, Web Server, Reverse Proxy, Load Balancing, SSL, Performance, DevOps

Frequently asked questions (FAQ)

Q. Nginx vs Apache?�which is better?

A. Nginx is generally faster and more memory-efficient. For most new projects, Nginx is the recommended default.

Q. Can it serve dynamic content?

A. Nginx is optimized for static files. Proxy dynamic work to a backend application server.

Q. Is it free?

A. Yes?�the open-source Nginx is free. Nginx Plus is the paid enterprise offering.

Q. Is it safe for production?

A. Yes. Many organizations?�including large consumer and enterprise sites?�run Nginx in production.


?�주 묻는 질문 (FAQ)

Q. ???�용???�무?�서 ?�제 ?�나??

A. Nginx guide: event loop & workers, config inheritance, load-balancing algorithms, production patterns?�plus reverse proxy???�무?�서????본문???�제?� ?�택 가?�드�?참고???�용?�면 ?�니??

Q. ?�행?�로 ?�으�?좋�? 글?�?

A. �?글 ?�단???�전 글 ?�는 관??글 링크�??�라가�??�서?��?배울 ???�습?�다. C++ ?�리�?목차?�서 ?�체 ?�름???�인?????�습?�다.

Q. ??깊이 공�??�려�?

A. cppreference?� ?�당 ?�이브러�?공식 문서�?참고?�세?? 글 말�???참고 ?�료 링크???�용?�면 좋습?�다.


같이 보면 좋�? 글 (?��? 링크)

??주제?� ?�결?�는 ?�른 글?�니??

  • [Kubernetes Practical Guide | Pods· Deployments](/en/blog/kubernetes-practical-guide/
  • [Docker Compose Complete Guide | Multi-Container Apps](/en/blog/docker-compose-complete-guide/
  • [Coding Test Complete Preparation Complete Guide](/en/blog/coding-test-strategy-guide/
  • [Developer Job Hunting Guide | Resume· Portfolio](/en/blog/developer-job-hunting-practical-tips/

??글?�서 ?�루???�워??(관??검?�어)

Nginx, Web Server, Reverse Proxy, Load Balancing, SSL, Performance, DevOps ?�으�?검?�하?�면 ??글???��????�니??