dotlinux guide

Guide to Secure Nginx Configuration on Linux

Nginx is one of the most popular web servers worldwide, powering over 40% of active websites. Its lightweight design, high performance, and scalability make it a top choice for hosting static content, reverse proxying, and load balancing. However, like any critical infrastructure component, Nginx requires careful security hardening to protect against common threats such as DDoS attacks, data breaches, and misconfiguration vulnerabilities. This guide provides a comprehensive overview of securing Nginx on Linux. We’ll cover fundamental concepts, step-by-step configuration methods, common pitfalls, and industry best practices to help you build a robust, secure web server environment. Whether you’re hosting a personal blog or a enterprise application, these guidelines will help mitigate risks and ensure compliance with modern security standards.

Table of Contents

  1. Fundamentals of Nginx Security
    • 1.1 Why Nginx Security Matters
    • 1.2 Key Components of Nginx Configuration
  2. Pre-Configuration Security Steps
    • 2.1 System Hardening
    • 2.2 Firewall Setup
  3. Core Nginx Security Configurations
    • 3.1 Minimize Exposure: Hide Version & Disable Unused Modules
    • 3.2 Run Nginx as a Non-Root User
    • 3.3 Secure File Permissions
    • 3.4 Harden Server Blocks (Virtual Hosts)
  4. SSL/TLS Configuration
    • 4.1 Enable Modern TLS Protocols
    • 4.2 Strong Cipher Suites
    • 4.3 Let’s Encrypt & Certbot for SSL Certificates
    • 4.4 HTTP Strict Transport Security (HSTS)
    • 4.5 OCSP Stapling
  5. HTTP Security Headers
    • 5.1 Content-Security-Policy (CSP)
    • 5.2 X-Content-Type-Options
    • 5.3 X-Frame-Options
    • 5.4 X-XSS-Protection
    • 5.5 Referrer-Policy
  6. Rate Limiting & DDoS Protection
  7. Access Control
    • 7.1 IP Whitelisting/Blacklisting
    • 7.2 Password Authentication (auth_basic)
  8. Preventing Common Attacks
    • 8.1 Disable Unused HTTP Methods
    • 8.2 Mitigate HTTP Request Smuggling
    • 8.3 Block Malicious User Agents
  9. Logging & Monitoring
  10. Best Practices
  11. Troubleshooting
  12. Conclusion
  13. References

1. Fundamentals of Nginx Security

1.1 Why Nginx Security Matters

Nginx acts as the frontline between your server and the internet. A misconfigured Nginx instance can expose sensitive data, enable unauthorized access, or become a vector for attacks like:

  • DDoS (Distributed Denial of Service): Overwhelming the server with traffic.
  • SQL Injection/XSS: Exploiting vulnerabilities in web apps via Nginx.
  • Man-in-the-Middle (MitM): Intercepting unencrypted traffic.
  • Server Fingerprinting: Attackers identifying Nginx version/OS to target known exploits.

1.2 Key Components of Nginx Configuration

Nginx configuration is defined in text files, typically located in /etc/nginx/. Key files include:

  • /etc/nginx/nginx.conf: Main configuration (global settings).
  • /etc/nginx/sites-available/: Server blocks (per-site configurations).
  • /etc/nginx/sites-enabled/: Symlinks to enabled server blocks.
  • /etc/nginx/conf.d/: Optional includes for modular configs.

2. Pre-Configuration Security Steps

2.1 System Hardening

Before configuring Nginx, secure the underlying Linux system:

  • Update regularly: Ensure Nginx and dependencies are patched.
    # Debian/Ubuntu  
    sudo apt update && sudo apt upgrade nginx -y  
    
    # RHEL/CentOS  
    sudo yum update nginx -y  
  • Use a non-root user: Avoid running Nginx as root (covered later).
  • Install from official repos: Use Nginx’s official repository for the latest security patches (guide).

2.2 Firewall Setup

Restrict network access to only necessary ports (HTTP/80, HTTPS/443) using ufw (Uncomplicated Firewall) or firewalld:

# UFW (Debian/Ubuntu)  
sudo ufw allow 'Nginx Full'  # Allows 80/tcp and 443/tcp  
sudo ufw enable  

# Firewalld (RHEL/CentOS)  
sudo firewall-cmd --add-service=http --permanent  
sudo firewall-cmd --add-service=https --permanent  
sudo firewall-cmd --reload  

3. Core Nginx Security Configurations

3.1 Minimize Exposure: Hide Version & Disable Unused Modules

By default, Nginx reveals its version in headers and error pages. Hide this and disable unnecessary modules to reduce attack surface:

Edit /etc/nginx/nginx.conf and add/modify:

http {  
    # Hide Nginx version in headers/error pages  
    server_tokens off;  

    # Disable unused modules (e.g., autoindex if not needed)  
    # autoindex off;  # Prevents directory listing  
}  

3.2 Run Nginx as a Non-Root User

Nginx binds to ports <1024 (e.g., 80/443) as root but drops privileges afterward. Configure it to run as a low-privilege user (e.g., www-data):

In /etc/nginx/nginx.conf:

user www-data;  # Default on Debian/Ubuntu; use "nginx" on RHEL/CentOS  
worker_processes auto;  # Use 1 per CPU core for performance  

3.3 Secure File Permissions

Ensure Nginx config files and web root have strict permissions:

  • Config files: Owned by root, readable by Nginx user, no write access.
    sudo chown -R root:root /etc/nginx/  
    sudo chmod -R 644 /etc/nginx/  # Readable by all, writable by root  
  • Web root: Restrict write access (e.g., /var/www/example.com):
    sudo chown -R www-data:www-data /var/www/example.com  
    sudo chmod -R 755 /var/www/example.com  # Directories: rwxr-xr-x  
    sudo find /var/www/example.com -type f -exec chmod 644 {} \;  # Files: rw-r--r--  

3.4 Harden Server Blocks

Server blocks (virtual hosts) define per-site settings. Restrict server_name to prevent host header attacks:

server {  
    listen 80;  
    server_name example.com www.example.com;  # Specific domains only (avoid wildcards)  

    # Redirect HTTP to HTTPS (see Section 4)  
    return 301 https://$host$request_uri;  
}  

4. SSL/TLS Configuration

SSL/TLS encrypts traffic between clients and Nginx. Weak SSL/TLS settings expose data to MitM attacks.

4.1 Enable Modern TLS Protocols

Disable outdated protocols (SSLv3, TLS 1.0/1.1) and enforce TLS 1.2+.

In your HTTPS server block:

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

    # Protocols: TLS 1.2+ only  
    ssl_protocols TLSv1.2 TLSv1.3;  
}  

4.2 Strong Cipher Suites

Use cryptographically strong ciphers and prioritize ECDHE (forward secrecy). Mozilla’s SSL Configuration Generator is a great resource.

Example for “Intermediate” compatibility (supports most modern browsers):

ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;  
ssl_prefer_server_ciphers on;  # Let server choose best cipher  

4.3 Let’s Encrypt & Certbot

Use Let’s Encrypt for free, trusted SSL certificates. Certbot automates issuance/renewal:

# Install Certbot (Debian/Ubuntu)  
sudo apt install certbot python3-certbot-nginx -y  

# Obtain/renew certificate (auto-updates Nginx config)  
sudo certbot --nginx -d example.com -d www.example.com  

4.4 HTTP Strict Transport Security (HSTS)

Forces browsers to use HTTPS, even if users request HTTP. Add the Strict-Transport-Security header:

add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;  
# max-age=31536000: 1 year (persists after first visit)  
# includeSubDomains: Applies to subdomains (e.g., blog.example.com)  
# preload: Submit to HSTS preload list (https://hstspreload.org/)  

4.5 OCSP Stapling

Speeds up SSL handshakes by having Nginx fetch certificate revocation status (OCSP) instead of clients.

ssl_stapling on;  
ssl_stapling_verify on;  
ssl_trusted_certificate /etc/letsencrypt/live/example.com/chain.pem;  # Let's Encrypt chain  
resolver 8.8.8.8 8.8.4.4 valid=300s;  # DNS resolvers for OCSP  
resolver_timeout 5s;  

5. HTTP Security Headers

HTTP headers mitigate common attacks like XSS, clickjacking, and MIME sniffing. Add these in your server block:

5.1 Content-Security-Policy (CSP)

Controls which resources (scripts, styles, images) a page can load (prevents XSS). Start with a strict policy and relax as needed:

add_header Content-Security-Policy "default-src 'self'; script-src 'self' https://trusted-cdn.com; style-src 'self' https://trusted-cdn.com; img-src 'self' data:; object-src 'none';" always;  

5.2 X-Content-Type-Options

Prevents browsers from “sniffing” MIME types (e.g., treating text/plain as HTML):

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

5.3 X-Frame-Options

Blocks clickjacking by preventing the page from being embedded in an iframe:

add_header X-Frame-Options "SAMEORIGIN" always;  # Allow iframes only from same domain  

5.4 X-XSS-Protection

Enables browser XSS filters:

add_header X-XSS-Protection "1; mode=block" always;  

5.5 Referrer-Policy

Controls what referrer info is sent when users click links:

add_header Referrer-Policy "strict-origin-when-cross-origin" always;  

6. Rate Limiting & DDoS Protection

Limit repeated requests to prevent brute-force or DDoS attacks using Nginx’s limit_req module.

Define a rate limit zone in nginx.conf (global):

http {  
    # Zone "login_limit": 10MB storage, 5 requests/minute per IP  
    limit_req_zone $binary_remote_addr zone=login_limit:10m rate=5r/m;  
}  

Apply to a sensitive endpoint (e.g., /login):

location /login {  
    limit_req zone=login_limit burst=2 nodelay;  # Allow 2 extra requests (burst)  
    # ...  
}  

7. Access Control

7.1 IP Whitelisting/Blacklisting

Restrict access to admin areas (e.g., /wp-admin for WordPress) using allow/deny:

location /admin {  
    allow 192.168.1.100;  # Trusted IP  
    allow 10.0.0.0/24;    # Trusted subnet  
    deny all;             # Block others  
}  

7.2 Password Authentication (auth_basic)

Secure sensitive paths with password protection using auth_basic:

  1. Create a password file with htpasswd:

    sudo apt install apache2-utils  # Debian/Ubuntu  
    sudo htpasswd -c /etc/nginx/.htpasswd admin  
  2. Add to Nginx config:

    location /secret {  
        auth_basic "Restricted Access";  
        auth_basic_user_file /etc/nginx/.htpasswd;  
    }  

8. Preventing Common Attacks

8.1 Disable Unused HTTP Methods

Block methods like PUT/DELETE unless required by your app:

if ($request_method !~ ^(GET|HEAD|POST)$) {  
    return 405;  # Method Not Allowed  
}  

8.2 Mitigate HTTP Request Smuggling

Limit request body size and buffer sizes to prevent request smuggling:

client_body_buffer_size 16k;  
client_max_body_size 1M;  # Adjust based on app needs (e.g., 100M for file uploads)  
large_client_header_buffers 4 16k;  # Limit header size  

8.3 Block Malicious User Agents

Filter out bots/scrapers with suspicious user agents:

if ($http_user_agent ~* (malicious-bot|scraper|wget)) {  
    return 403;  # Forbidden  
}  

9. Logging & Monitoring

Enable detailed logging to detect attacks and troubleshoot issues.

In nginx.conf:

http {  
    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;  # Access log  
    error_log /var/log/nginx/error.log warn;   # Error log (warn level or higher)  
}  

Log Rotation: Use logrotate to prevent logs from filling the disk. Config file: /etc/logrotate.d/nginx.

10. Best Practices

  • Regular Updates: Keep Nginx and OS patched.
  • Least Privilege: Run Nginx as a non-root user; restrict file permissions.
  • Backup Configs: Version-control /etc/nginx/ with Git.
  • Test Changes: Validate configs with nginx -t before reloading:
    sudo nginx -t  # Checks syntax  
    sudo systemctl reload nginx  # Applies changes gracefully  
  • Scan for Vulnerabilities: Use tools like:
  • Disable Directory Listing: Ensure autoindex off; (default) to prevent listing files.

11. Troubleshooting

  • Check config syntax: sudo nginx -t.
  • View errors: tail -f /var/log/nginx/error.log.
  • Verify headers: Use curl to test headers:
    curl -I https://example.com  # Shows response headers  
  • Certbot issues: Renew certificates manually with sudo certbot renew --dry-run.

12. Conclusion

Securing Nginx is an ongoing process. By following this guide, you’ll mitigate common threats like data leaks, DDoS, and injection attacks. Key takeaways:

  • Use HTTPS with modern TLS protocols and strong ciphers.
  • Enforce HTTP security headers to protect against XSS/clickjacking.
  • Restrict access with rate limiting, IP whitelisting, and password auth.
  • Monitor logs and update Nginx regularly.

Remember: Security is never “done”—periodically audit your configs and stay updated on new threats.

13. References

  • [Nginx