DEV Community

Ukasha Mahir
Ukasha Mahir

Posted on

Nginx Unleashed: From Static Site Serving to Dynamic Load Balancing

Nginx Unleashed: From Static Site Serving to Dynamic Load Balancing

Nginx (pronounced “engine‑x”) has become the de‑facto web server for everything from personal blogs to massive SaaS platforms. Its event‑driven architecture lets it handle tens of thousands of concurrent connections while using a fraction of the memory that traditional thread‑per‑connection servers need. In this post we’ll walk through a practical setup that starts with serving a static site, then evolves into a full‑blown reverse proxy with SSL termination and round‑robin load balancing. By the end you’ll have a production‑ready nginx.conf you can drop into any Linux box.


1. Quick Installation

Ubuntu / Debian

sudo apt update
sudo apt install -y nginx
Enter fullscreen mode Exit fullscreen mode

CentOS / RHEL

sudo yum install -y epel-release
sudo yum install -y nginx
Enter fullscreen mode Exit fullscreen mode

After installation, start and enable the service:

sudo systemctl start nginx
sudo systemctl enable nginx
Enter fullscreen mode Exit fullscreen mode

You can verify it’s running with curl -I http://localhost. You should see a 200 OK and the default Welcome to nginx! page.


2. Serving a Static Site

Create a simple site in /var/www/myapp:

sudo mkdir -p /var/www/myapp
sudo chown $USER:$USER /var/www/myapp
echo "<h1>Hello from Nginx</h1>" > /var/www/myapp/index.html
Enter fullscreen mode Exit fullscreen mode

Now replace the default server block. Edit /etc/nginx/sites-available/default (or /etc/nginx/conf.d/default.conf on some distros):

server {
    listen 80;
    server_name example.com www.example.com;

    root /var/www/myapp;
    index index.html;

    # Optional: clean URLs
    location / {
        try_files $uri $uri/ =404;
    }

    # Log format for later analysis
    access_log /var/log/nginx/access.log combined;
    error_log  /var/log/nginx/error.log warn;
}
Enter fullscreen mode Exit fullscreen mode

Test the configuration and reload:

sudo nginx -t && sudo systemctl reload nginx
Enter fullscreen mode Exit fullscreen mode

Visiting http://example.com now serves your static index.html. Simple, fast, and secure (the server never spawns a new process per request).


3. Adding a Reverse Proxy

Most modern applications run behind an application server (Node, Django, Go, etc.). Let’s proxy /api to a backend running on localhost:3000.

server {
    listen 80;
    server_name api.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 X-Forwarded-Proto $scheme;

        # WebSocket support
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }
}
Enter fullscreen mode Exit fullscreen mode

The proxy_set_header directives preserve the original request metadata, which is critical for logging and authentication in the upstream app.


4. SSL Termination with Let’s Encrypt

Secure traffic should be the default. We’ll use Certbot to obtain a free certificate and let Nginx handle TLS.

sudo apt install -y certbot python3-certbot-nginx
sudo certbot --nginx -d example.com -d www.example.com
Enter fullscreen mode Exit fullscreen mode

Certbot automatically modifies the server block:

server {
    listen 443 ssl http2;
    server_name example.com www.example.com;

    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
    include /etc/letsencrypt/options-ssl-nginx.conf;
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;

    # Rest of the config (root, location, etc.) stays the same
}
Enter fullscreen mode Exit fullscreen mode

It also creates a redirect from HTTP to HTTPS:

server {
    listen 80;
    server_name example.com www.example.com;
    return 301 https://$host$request_uri;
}
Enter fullscreen mode Exit fullscreen mode

Remember to schedule certificate renewal:

sudo systemctl enable certbot.timer
Enter fullscreen mode Exit fullscreen mode

5. Load Balancing Across Multiple Backends

When traffic spikes, a single backend can become a bottleneck. Nginx’s upstream module makes load balancing painless.

# Define the pool of app servers
upstream app_cluster {
    least_conn;               # Choose the server with the fewest active connections
    server 10.0.0.101:3000;
    server 10.0.0.102:3000;
    server 10.0.0.103:3000 backup;   # Optional: a standby node
}
Enter fullscreen mode Exit fullscreen mode

Now point the proxy to the upstream group:

server {
    listen 443 ssl http2;
    server_name api.example.com;

    location / {
        proxy_pass http://app_cluster;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        # ... other headers as before
    }
}
Enter fullscreen mode Exit fullscreen mode

You can experiment with different algorithms (round_robin, ip_hash, hash $request_uri) based on your workload characteristics.


6. Performance Tweaks

a. Gzip Compression

gzip on;
gzip_types text/css application/javascript text/xml application/json;
gzip_min_length 256;
gzip_proxied any;
Enter fullscreen mode Exit fullscreen mode

b. Caching Static Assets

location ~* \.(js|css|png|jpg|jpeg|gif|svg|ico)$ {
    expires 30d;
    add_header Cache-Control "public, immutable";
}
Enter fullscreen mode Exit fullscreen mode

c. Connection Limits

# Prevent a single IP from hogging connections
limit_conn_zone $binary_remote_addr zone=addr:10m;

server {
    limit_conn addr 10;   # max 10 concurrent connections per IP
    # ... rest of the block
}
Enter fullscreen mode Exit fullscreen mode

d. Worker Processes & Connections

Edit /etc/nginx/nginx.conf:

worker_processes auto;          # Auto‑detect CPU cores
events {
    worker_connections 4096;   # Max connections per worker
    multi_accept on;
    use epoll;                 # Linux‑specific, best performance
}
Enter fullscreen mode Exit fullscreen mode

These settings give Nginx a solid baseline for high‑throughput environments.


7. Debugging & Monitoring

  • Access & error logs: Tail them in real time.
  sudo tail -f /var/log/nginx/access.log /var/log/nginx/error.log
Enter fullscreen mode Exit fullscreen mode
  • Status module: Enable a lightweight endpoint for metrics.
  server {
      listen 127.0.0.1:8080;
      location /nginx_status {
          stub_status;
          allow 127.0.0.1;
          deny all;
      }
  }
Enter fullscreen mode Exit fullscreen mode

Then query curl http://127.0.0.1:8080/nginx_status to see active connections, request rates, etc.

  • Third‑party tools: Grafana + Prometheus, or the NGINX Amplify service for deeper insights.

8. Putting It All Together

Below is a consolidated nginx.conf that incorporates static serving, SSL, reverse proxy, load balancing, and performance tweaks.

user  www-data;
worker_processes auto;
pid   /run/nginx.pid;

events {
    worker_connections 4096;
    use epoll;
    multi_accept on;
}

http {
    include       mime.types;
    default_type  application/octet-stream;

    # Gzip
    gzip on;
    gzip_types text/css application/javascript text/xml application/json;
    gzip_min_length 256;
    gzip_proxied any;

    # Cache static assets
    location ~* \.(js|css|png|jpg|jpeg|gif|svg|ico)$ {
        expires 30d;
        add_header Cache-Control "public, immutable";
    }

    # Upstream pool
    upstream app_cluster {
        least_conn;
        server 10.0.0.101:3000;
        server 10.0.0.102:3000;
        server 10.0.0.103:3000 backup;
    }

    # Status endpoint
    server {
        listen 127.0.0.1:8080;
        location /nginx_status {
            stub_status;
            allow 127.0.0.1;
            deny all;
        }
    }

    # Main site – static + SSL
    server {
        listen 80;
        server_name example.com www.example.com;
        return 301 https://$host$request_uri;
    }

    server {
        listen 443 ssl http2;
        server_name example.com www.example.com;

        ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
        include /etc/letsencrypt/options-ssl-nginx.conf;
        ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;

        root /var/www/myapp;
        index index.html;

        location / {
            try_files $uri $uri/ =404;
        }
    }

    # API reverse proxy + load balancing
    server {
        listen 80;
        server_name api.example.com;
        return 301 https://$host$request_uri;
    }

    server {
        listen 443 ssl http2;
        server_name api.example.com;

        ssl_certificate /etc/letsencrypt/live/api.example.com/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/api.example.com/privkey.pem;
        include /etc/letsencrypt/options-ssl-nginx.conf;
        ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;

        location / {
            proxy_pass http://app_cluster;
            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;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "upgrade";
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Run sudo nginx -t && sudo systemctl reload nginx after saving. Your stack is now capable of handling static content, encrypted traffic, and scaling across multiple backend instances—all with minimal resource consumption.


9. Conclusion

Nginx’s modular design means you can start small—just a static file server—and grow into a full‑featured edge proxy without rewriting configuration. By mastering the core directives (listen, server_name, location, proxy_pass, upstream) and a handful of performance knobs, you gain a resilient, low‑latency front line for any web application.

Happy tuning, and may your connections stay ever‑alive!


Recommended Tools

These tools complement the Nginx setup and help you keep your infrastructure performant and observable.

Top comments (0)