How to Configure Nginx

How to Configure Nginx Nginx (pronounced “engine-x”) is one of the most widely used web servers in the world, powering over 40% of all active websites. Known for its high performance, low memory footprint, and scalability, Nginx excels at handling concurrent connections, reverse proxying, load balancing, and serving static content with exceptional speed. Unlike traditional web servers like Apache,

Nov 6, 2025 - 10:03
Nov 6, 2025 - 10:03
 2

How to Configure Nginx

Nginx (pronounced engine-x) is one of the most widely used web servers in the world, powering over 40% of all active websites. Known for its high performance, low memory footprint, and scalability, Nginx excels at handling concurrent connections, reverse proxying, load balancing, and serving static content with exceptional speed. Unlike traditional web servers like Apache, which use a process-based model, Nginx employs an event-driven, asynchronous architecture that makes it ideal for modern web applications, APIs, and high-traffic environments.

Configuring Nginx correctly is essential to ensure optimal performance, security, and reliability. Whether you're deploying a simple static website, a complex microservices architecture, or a high-availability application stack, understanding how to configure Nginx from the ground up gives you full control over how your server responds to requests, handles traffic, and secures data.

This comprehensive guide walks you through every critical aspect of Nginx configurationfrom installation and basic syntax to advanced optimizations, security hardening, and real-world use cases. By the end of this tutorial, youll have the knowledge and confidence to configure Nginx for any production environment, avoiding common pitfalls and leveraging best practices that top DevOps teams use daily.

Step-by-Step Guide

Step 1: Install Nginx

Before configuring Nginx, you must first install it on your server. The installation process varies slightly depending on your operating system. Below are the most common methods for Linux distributions.

On Ubuntu or Debian:

sudo apt update

sudo apt install nginx

On CentOS, RHEL, or Fedora:

sudo yum install nginx

or for newer versions using dnf:

sudo dnf install nginx

On macOS (using Homebrew):

brew install nginx

After installation, start the Nginx service and enable it to launch at boot:

sudo systemctl start nginx

sudo systemctl enable nginx

Verify that Nginx is running by visiting your servers IP address or domain name in a web browser. You should see the default Nginx welcome page. If you dont, check the service status:

sudo systemctl status nginx

Step 2: Understand Nginx File Structure

Nginx organizes its configuration files in a structured hierarchy. Understanding this structure is critical before making any changes.

  • /etc/nginx/ Main configuration directory
  • /etc/nginx/nginx.conf Primary configuration file
  • /etc/nginx/sites-available/ Contains all available server block configurations (virtual hosts)
  • /etc/nginx/sites-enabled/ Contains symbolic links to active server blocks
  • /var/www/html/ Default document root (where static files are served)
  • /var/log/nginx/ Contains access and error logs

The main configuration file, nginx.conf, is divided into blocks that define global settings, event handling, HTTP behavior, and server-specific configurations. Always make a backup before editing:

sudo cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.bak

Step 3: Configure the Main nginx.conf File

The nginx.conf file contains the core directives that control Nginxs global behavior. Heres a breakdown of the most important sections:

user nginx;

worker_processes auto;

error_log /var/log/nginx/error.log;

pid /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" "$http_x_forwarded_for"';

access_log /var/log/nginx/access.log main;

sendfile on;

tcp_nopush on;

tcp_nodelay on;

keepalive_timeout 65;

types_hash_max_size 2048;

include /etc/nginx/conf.d/*.conf;

include /etc/nginx/sites-enabled/*;

}

Key Directives Explained:

  • user nginx; Defines the system user under which Nginx worker processes run. For security, avoid running as root.
  • worker_processes auto; Automatically sets the number of worker processes to match the number of CPU cores.
  • worker_connections 1024; Maximum number of simultaneous connections per worker process. Adjust based on expected traffic.
  • sendfile on; Enables efficient file transfers using the sendfile() system call.
  • keepalive_timeout 65; How long Nginx keeps idle connections open. Lower values reduce memory usage on high-traffic sites.
  • include /etc/nginx/sites-enabled/*; Loads all active server blocks from the sites-enabled directory.

After editing nginx.conf, always test the configuration before reloading:

sudo nginx -t

If the test passes, reload Nginx to apply changes:

sudo systemctl reload nginx

Step 4: Create Server Blocks (Virtual Hosts)

Server blocks are Nginxs equivalent of Apaches virtual hosts. They allow you to host multiple websites on a single server using different domain names or IP addresses.

Create a new configuration file in /etc/nginx/sites-available/:

sudo nano /etc/nginx/sites-available/example.com

Add the following basic server block:

server {

listen 80;

server_name example.com www.example.com;

root /var/www/example.com/html;

index index.html index.htm index.nginx-debian.html;

location / {

try_files $uri $uri/ =404;

}

access_log /var/log/nginx/example.com.access.log;

error_log /var/log/nginx/example.com.error.log;

}

Key Directives:

  • listen 80; Specifies the port Nginx listens on. Use listen 443 ssl; for HTTPS.
  • server_name; Defines the domain(s) this block responds to. Wildcards (e.g., *.example.com) are supported.
  • root; The directory where site files are stored.
  • index; List of default files to serve when a directory is requested.
  • location /; Handles requests to the root path. try_files checks for files in order and returns 404 if none exist.

Enable the server block by creating a symbolic link to sites-enabled/:

sudo ln -s /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled/

Test and reload:

sudo nginx -t

sudo systemctl reload nginx

Create the document root and a test file:

sudo mkdir -p /var/www/example.com/html

echo "<h1>Welcome to example.com</h1>" | sudo tee /var/www/example.com/html/index.html

Step 5: Configure SSL/TLS with Lets Encrypt

Secure your site with HTTPS using free certificates from Lets Encrypt via Certbot.

Install Certbot:

sudo apt install certbot python3-certbot-nginx

Run the Nginx plugin:

sudo certbot --nginx -d example.com -d www.example.com

Certbot will automatically:

  • Request a certificate from Lets Encrypt
  • Modify your Nginx configuration to enable HTTPS
  • Set up automatic certificate renewal

After completion, your server block will be updated to include SSL directives:

server {

listen 443 ssl;

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/example.com/html;

index index.html;

location / {

try_files $uri $uri/ =404;

}

}

Also ensure a redirect from HTTP to HTTPS is in place:

server {

listen 80;

server_name example.com www.example.com;

return 301 https://$server_name$request_uri;

}

Test and reload again:

sudo nginx -t && sudo systemctl reload nginx

Step 6: Optimize Performance with Caching and Compression

Performance tuning is one of the most impactful configuration tasks. Use caching and compression to reduce bandwidth and improve load times.

Enable Gzip Compression

Add these directives inside the http block in nginx.conf:

gzip on;

gzip_vary on;

gzip_min_length 1024;

gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;

gzip_comp_level 6;

  • gzip on; Enables compression.
  • gzip_min_length 1024; Only compress responses larger than 1KB.
  • gzip_types; Specifies MIME types to compress. Include common text, JSON, JS, and CSS.
  • gzip_comp_level 6; Compression level (19). Level 6 offers a good balance between speed and compression ratio.

Enable Browser Caching

Add a location block to set cache headers for static assets:

location ~* \.(jpg|jpeg|png|gif|ico|css|js|woff|woff2|ttf|svg)$ {

expires 1y;

add_header Cache-Control "public, immutable";

access_log off;

}

  • expires 1y; Tells browsers to cache assets for one year.
  • Cache-Control "public, immutable"; Indicates the asset can be cached by any cache and wont change.
  • access_log off; Reduces disk I/O by disabling logs for static files.

Step 7: Configure Reverse Proxy for Backend Applications

Nginx is commonly used as a reverse proxy to forward requests to backend services like Node.js, Python (Django/Flask), or Java applications.

Example: Proxying to a Node.js app running on port 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 Upgrade $http_upgrade;

proxy_set_header Connection 'upgrade';

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_cache_bypass $http_upgrade;

}

}

Key Proxy Directives:

  • proxy_pass; Defines the backend server URL.
  • proxy_http_version 1.1; Required for WebSocket support.
  • proxy_set_header; Passes client headers to the backend (essential for authentication and logging).

For HTTPS proxying, ensure the backend app trusts the forwarded protocol:

proxy_set_header X-Forwarded-Proto $scheme;

Step 8: Set Up Load Balancing

Nginx can distribute traffic across multiple backend servers using upstream blocks.

Define an upstream group in the http block:

upstream backend {

server 192.168.1.10:8000;

server 192.168.1.11:8000;

server 192.168.1.12:8000;

least_conn;

}

Then reference it in your server block:

server {

listen 80;

server_name loadbalancer.example.com;

location / {

proxy_pass http://backend;

proxy_set_header Host $host;

proxy_set_header X-Real-IP $remote_addr;

}

}

Load Balancing Methods:

  • round-robin (default) Distributes requests evenly.
  • least_conn Sends requests to the server with fewest active connections.
  • ip_hash Routes requests from the same IP to the same server (useful for session persistence).

Step 9: Configure Rate Limiting and Security

Protect your server from brute force attacks and DDoS attempts using rate limiting.

Add this to the http block to define a limit zone:

limit_req_zone $binary_remote_addr zone=login:10m rate=5r/m;

  • $binary_remote_addr; Uses the clients IP address as the key.
  • zone=login:10m; Creates a shared memory zone named login with 10MB capacity.
  • rate=5r/m; Allows 5 requests per minute per IP.

Apply it to a specific location:

location /login {

limit_req zone=login burst=10 nodelay;

proxy_pass http://auth_backend;

}

  • burst=10; Allows 10 extra requests to be queued if rate limit is exceeded.
  • nodelay; Processes queued requests immediately instead of spacing them out.

Additionally, block common malicious requests:

location ~* \.(htaccess|htpasswd|env|log)$ {

deny all;

}

Step 10: Enable Logging and Monitoring

Proper logging is critical for debugging and security audits. Customize log formats and rotate logs regularly.

Define a custom log format in nginx.conf:

log_format detailed '$remote_addr - $remote_user [$time_local] '

'"$request" $status $body_bytes_sent '

'"$http_referer" "$http_user_agent" '

'rt=$request_time uct="$upstream_connect_time" uht="$upstream_header_time" urt="$upstream_response_time"';

Apply it to your server block:

access_log /var/log/nginx/access.log detailed;

Install and configure logrotate to prevent log files from consuming disk space:

sudo nano /etc/logrotate.d/nginx

Add:

/var/log/nginx/*.log {

daily

missingok

rotate 14

compress

delaycompress

notifempty

create 0640 www-data adm

sharedscripts

postrotate

[ -f /var/run/nginx.pid ] && kill -USR1 cat /var/run/nginx.pid

endscript

}

Best Practices

Configuring Nginx isnt just about making it workits about making it secure, scalable, and maintainable. Below are industry-proven best practices to follow in every production environment.

1. Never Run Nginx as Root

Always specify a non-privileged user in the nginx.conf file:

user www-data;

Ensure the user has read access to your static files and write access to logs. Avoid running worker processes with elevated privileges.

2. Use Separate Configuration Files

Instead of dumping all configurations into nginx.conf, use modular files in /etc/nginx/conf.d/ or sites-available/. This improves readability, version control, and deployment automation.

3. Enable HSTS for HTTPS Sites

HTTP Strict Transport Security (HSTS) forces browsers to use HTTPS only. Add this header to your SSL server block:

add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;

Use always to ensure the header is sent even on error responses.

4. Disable Server Tokens

By default, Nginx reveals its version in response headers, which can aid attackers. Hide it:

server_tokens off;

5. Limit HTTP Methods

Most websites only need GET, POST, and HEAD. Block dangerous methods like PUT, DELETE, and TRACE:

if ($request_method !~ ^(GET|HEAD|POST)$ ) {

return 405;

}

6. Use Secure SSL/TLS Settings

Use modern cipher suites and disable outdated protocols. Heres a recommended SSL configuration:

ssl_protocols TLSv1.2 TLSv1.3;

ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384;

ssl_prefer_server_ciphers off;

ssl_session_cache shared:SSL:10m;

ssl_session_timeout 10m;

Use Mozillas SSL Configuration Generator for up-to-date recommendations.

7. Implement Content Security Policy (CSP)

Prevent XSS attacks by defining which sources scripts, styles, and images can be loaded from:

add_header Content-Security-Policy "default-src 'self'; script-src 'self' https://cdn.example.com; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:;";

8. Regularly Update and Patch

Keep Nginx updated to the latest stable version. Security vulnerabilities are patched frequently. Use package managers or compile from source with security patches applied.

9. Monitor Performance and Errors

Use tools like nginx-status (built-in) or external monitoring services to track request rates, response times, and error codes.

Enable the status module (if compiled with --with-http_stub_status_module):

location /nginx_status {

stub_status on;

access_log off;

allow 127.0.0.1;

deny all;

}

Access http://your-server/nginx_status to view live metrics.

10. Backup and Version Control

Always back up your configuration files before changes. Use Git to track modifications:

cd /etc/nginx

git init

git add .

git commit -m "Initial Nginx config"

This allows you to roll back changes quickly and collaborate with teams.

Tools and Resources

Effective Nginx configuration relies on the right tools and authoritative resources. Below are essential utilities and references to enhance your workflow.

Configuration Validators

  • nginx -t Tests configuration syntax and file validity. Always run before reloading.
  • nginx -T Displays the full effective configuration, including included files. Useful for debugging.

Performance Testing Tools

  • ab (Apache Bench) Simple benchmarking tool: ab -n 1000 -c 100 http://example.com/
  • wrk High-performance HTTP benchmarking tool with Lua scripting support.
  • Locust Python-based load testing tool for simulating real user behavior.

SSL/TLS Testing

  • SSL Labs (ssllabs.com) Free, detailed SSL certificate analysis with grade ratings.
  • TestSSL.sh Command-line tool to scan for SSL/TLS vulnerabilities.

Log Analysis

  • GoAccess Real-time web log analyzer with interactive dashboard.
  • AWStats Generates advanced statistics from log files.
  • ELK Stack (Elasticsearch, Logstash, Kibana) Enterprise-grade log aggregation and visualization.

Automation and DevOps Tools

  • Ansible Automate Nginx deployment across multiple servers with playbooks.
  • Docker Run Nginx in containers for consistent environments.
  • Terraform Provision Nginx servers on cloud platforms like AWS or GCP.

Official Documentation and Community

Real Examples

Understanding configuration in isolation is useful, but seeing real-world applications solidifies knowledge. Below are three common production scenarios with complete Nginx configurations.

Example 1: Static Website with HTTPS and Caching

Host a marketing website with optimized static assets and full SSL.

server {

listen 80;

server_name mywebsite.com www.mywebsite.com;

return 301 https://$server_name$request_uri;

}

server {

listen 443 ssl http2;

server_name mywebsite.com www.mywebsite.com;

root /var/www/mywebsite;

index index.html;

ssl_certificate /etc/letsencrypt/live/mywebsite.com/fullchain.pem;

ssl_certificate_key /etc/letsencrypt/live/mywebsite.com/privkey.pem;

ssl_protocols TLSv1.2 TLSv1.3;

ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512;

ssl_prefer_server_ciphers off;

ssl_session_cache shared:SSL:10m;

ssl_session_timeout 10m;

add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;

add_header X-Frame-Options "SAMEORIGIN" always;

add_header X-Content-Type-Options "nosniff" always;

gzip on;

gzip_vary on;

gzip_min_length 1024;

gzip_types text/plain text/css application/json application/javascript text/xml application/xml;

location / {

try_files $uri $uri/ =404;

}

location ~* \.(jpg|jpeg|png|gif|ico|css|js|woff|woff2|ttf|svg)$ {

expires 1y;

add_header Cache-Control "public, immutable";

access_log off;

}

access_log /var/log/nginx/mywebsite.access.log combined;

error_log /var/log/nginx/mywebsite.error.log;

}

Example 2: API Gateway with Rate Limiting and Load Balancing

Proxy requests to three Node.js microservices with rate limiting and failover.

upstream api_backend {

server 10.0.0.10:3000 max_fails=3 fail_timeout=30s;

server 10.0.0.11:3000 max_fails=3 fail_timeout=30s;

server 10.0.0.12:3000 max_fails=3 fail_timeout=30s;

least_conn;

}

limit_req_zone $binary_remote_addr zone=api:10m rate=100r/m;

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;

ssl_protocols TLSv1.2 TLSv1.3;

ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512;

location / {

limit_req zone=api burst=20 nodelay;

proxy_pass http://api_backend;

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;

proxy_read_timeout 300s;

proxy_connect_timeout 300s;

}

access_log /var/log/nginx/api.access.log;

error_log /var/log/nginx/api.error.log;

}

Example 3: WordPress Site with FastCGI Cache

Optimize WordPress performance using FastCGI caching to reduce database load.

fastcgi_cache_path /var/cache/nginx levels=1:2 keys_zone=WORDPRESS:100m inactive=60m use_temp_path=off;

server {

listen 443 ssl;

server_name wordpress-site.com;

root /var/www/wordpress;

index index.php;

ssl_certificate /etc/letsencrypt/live/wordpress-site.com/fullchain.pem;

ssl_certificate_key /etc/letsencrypt/live/wordpress-site.com/privkey.pem;

location / {

try_files $uri $uri/ /index.php?$args;

}

location ~ \.php$ {

include snippets/fastcgi-php.conf;

fastcgi_pass unix:/var/run/php/php8.1-fpm.sock;

fastcgi_cache WORDPRESS;

fastcgi_cache_valid 200 60m;

fastcgi_cache_valid 404 10m;

fastcgi_cache_use_stale updating error timeout invalid_header http_500;

fastcgi_cache_lock on;

add_header X-Cache $upstream_cache_status;

}

location ~* \.(css|js|png|jpg|jpeg|gif|ico|svg)$ {

expires 1y;

add_header Cache-Control "public, immutable";

access_log off;

}

access_log /var/log/nginx/wordpress.access.log;

error_log /var/log/nginx/wordpress.error.log;

}

FAQs

What is the difference between nginx.conf and sites-available?

nginx.conf is the main configuration file that defines global settings like worker processes, HTTP behavior, and logging. sites-available contains individual server block configurations for each website or domain. Only the files symlinked into sites-enabled are loaded by Nginx. This separation allows easy enabling/disabling of sites without editing the core configuration.

How do I check if my Nginx configuration is correct?

Use the command sudo nginx -t. It tests syntax and file validity. If successful, it returns test is successful. Always run this before reloading Nginx to avoid downtime.

Why is my website showing a 502 Bad Gateway error?

A 502 error typically means Nginx cannot communicate with the backend server. Check if your backend service (e.g., PHP-FPM, Node.js) is running. Verify the proxy_pass or fastcgi_pass address is correct. Also check firewall rules and socket permissions.

Can I run multiple websites on one Nginx server?

Yes. Use server blocks with different server_name directives. Each block can point to a different document root and handle a unique domain. Ensure DNS records point each domain to your servers IP address.

How do I enable HTTP/2 in Nginx?

Modify your listen directive to include http2:

listen 443 ssl http2;

Ensure your Nginx version is 1.9.5 or higher and that SSL is enabled. HTTP/2 requires HTTPS.

How do I block bots or bad referrers?

Use the map directive to block based on User-Agent or Referer:

map $http_user_agent $bad_bot {

default 0;

~*(bot|crawler|spider|scraper) 1;

}

if ($bad_bot) {

return 403;

}

What is the best way to back up Nginx configurations?

Use version control (e.g., Git) to track changes. Additionally, create daily backups of the /etc/nginx directory using a cron job:

0 2 * * * tar -czf /backup/nginx-$(date +\%Y\%m\%d).tar.gz /etc/nginx

How do I restart Nginx without dropping active connections?

Use sudo systemctl reload nginx instead of restart. Reload re-reads the configuration and spawns new worker processes while keeping existing connections alive until they complete.

Does Nginx support automatic certificate renewal?

Yes, if you use Certbot. It automatically sets up a cron job to renew certificates 30 days before expiration. Test renewal with: sudo certbot renew --dry-run.

Can Nginx handle WebSocket connections?

Yes. Use the following directives in your proxy block:

proxy_http_version 1.1;

proxy_set_header Upgrade $http_upgrade;

proxy_set_header Connection "upgrade";

Conclusion

Configuring Nginx is a foundational skill for any web developer, DevOps engineer, or system administrator. Its speed, flexibility, and reliability make it the backbone of modern web infrastructurefrom small blogs to Fortune 500 platforms. This guide has taken you from the basics of installation and server blocks to advanced configurations like reverse proxying, load balancing, SSL/TLS hardening, and performance optimization.

Remember: configuration is not a one-time task. It requires ongoing monitoring, iterative tuning, and proactive security. Always test changes with nginx -t, use version control, and leverage tools like Certbot, SSL Labs, and GoAccess to maintain a robust, high-performing server.

By following the best practices outlined here and applying the real-world examples provided, youre now equipped to deploy Nginx confidently in any environment. Whether youre serving static assets, proxying APIs, or scaling microservices, Nginxs powerful configuration engine gives you the control you need to build fast, secure, and scalable web applications.

Continue learning by exploring Nginx modules, contributing to open-source configurations, and experimenting with containerized deployments. The more you understand its inner workings, the more youll unlock its full potential.