Skip to main content

Implementing Security Best Practices

1. Hiding Nginx Version

Directive Values Description
server_tokens off Hides the Nginx version from error pages and HTTP headers
server_tokens on Shows the Nginx version (default behavior)

Example: Hide Nginx Version

server {
    listen 80;
    server_name example.com;

    # Hide Nginx version
    server_tokens off;

    location / {
        return 200 'Hello World';
    }
}
Note: Setting server_tokens off removes the version information from error pages and HTTP response headers, enhancing security by preventing attackers from identifying the server software and version.

2. Disabling Unwanted Methods

Method Description Configuration Notes
GET Retrieve resources allow_method GET; Default allowed method
POST Submit data to the server allow_method POST; Commonly used for form submissions
PUT Update or replace resources allow_method PUT; May be disabled for security
DELETE Remove resources allow_method DELETE; Often restricted in production
PATCH Partially update resources allow_method PATCH; May require specific handling
HEAD Retrieve headers only allow_method HEAD; Used for checking resource existence
OPTIONS Discover available methods allow_method OPTIONS; Can expose server capabilities

Example: Restricting HTTP Methods

server {
    listen 80;
    server_name example.com;

    location / {
        # Allow only GET and POST methods
        limit_except GET POST {
            deny all;
        }

        # Additional security headers
        add_header X-Content-Type-Options "nosniff";
        add_header X-Frame-Options "DENY";
    }
}
Note: The limit_except directive allows specified methods and denies others. This is useful for restricting access to sensitive endpoints.

3. Preventing Clickjacking

Directive Description Values Notes
add_header Set HTTP headers to prevent clickjacking X-Frame-Options: DENY Prevents the page from being embedded in a frame or iframe
add_header Set HTTP headers to prevent clickjacking X-Frame-Options: SAMEORIGIN Allows embedding only from the same origin
add_header Set HTTP headers to prevent clickjacking X-Frame-Options: ALLOW-FROM uri Allows embedding from a specific URI (deprecated in favor of CSP)
add_header Set HTTP headers to prevent clickjacking Content-Security-Policy: frame-ancestors 'none' 'self' http://example.com Modern and flexible approach to control frame embedding

Example: X-Frame-Options DENY

server {
    listen 80;
    server_name example.com;

    add_header X-Frame-Options DENY;
}

Example: Content-Security-Policy frame-ancestors

server {
    listen 80;
    server_name example.com;

    add_header Content-Security-Policy "frame-ancestors 'none';";
}
Note: The X-Frame-Options header is supported by most modern browsers, but the Content-Security-Policy with frame-ancestors directive is the preferred method as it offers more granular control and better security.
Warning: Setting X-Frame-Options: ALLOW-FROM is deprecated and should not be used in new implementations.

4. Enabling XSS Protection

Directive Description Values Notes
add_header Set security headers X-Content-Type-Options: nosniff Prevents MIME type sniffing
add_header Set security headers X-Frame-Options: DENY Prevents clickjacking attacks
add_header Set security headers X-XSS-Protection: 1; mode=block Enables XSS filtering in browsers

Example: Configuring XSS Protection Headers

server {
    listen 80;
    server_name example.com;

    add_header X-Content-Type-Options "nosniff";
    add_header X-Frame-Options "DENY";
    add_header X-XSS-Protection "1; mode=block";

    location / {
        root /var/www/html;
        index index.html;
    }
}
Note: The X-XSS-Protection header is deprecated in modern browsers but still supported for backward compatibility.

5. Setting Content Type Options

Directive Values Description
add_header X-Content-Type-Options "nosniff" Prevents browsers from MIME-sniffing the content type

Example: Configuring X-Content-Type-Options

server {
    listen 80;
    server_name example.com;

    add_header X-Content-Type-Options "nosniff" always;
}
Note: The nosniff value ensures that browsers will not interpret files as a different MIME type than what is declared in the Content-Type header.

6. Configuring SSL Security

Directive Description Example
ssl_protocols Enables or disables specific SSL/TLS protocols ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers Specifies the list of ciphers to use for SSL connections ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512;
ssl_prefer_server_ciphers Enables or disables preference for server-side cipher preferences ssl_prefer_server_ciphers on;
ssl_session_cache Configures the SSL session cache ssl_session_cache shared:SSL:10m;
ssl_session_timeout Sets the time during which a client can reuse an SSL session ssl_session_timeout 10m;
ssl_stapling Enables OCSP stapling for improved performance and security ssl_stapling on;
ssl_stapling_verify Enables verification of OCSP responses ssl_stapling_verify on;

Example: Basic SSL Configuration

server {
    listen 443 ssl;
    server_name example.com;

    ssl_certificate /path/to/certificate.crt;
    ssl_certificate_key /path/to/private.key;
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512;
    ssl_prefer_server_ciphers on;
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 10m;

    location / {
        root /var/www/html;
        index index.html;
    }
}
Note: Ensure that the SSL certificate and key files are properly secured with appropriate file permissions.
Warning: Using outdated or weak SSL/TLS protocols (e.g., SSLv2, SSLv3) can expose your server to security vulnerabilities.

7. Implementing HSTS

Directive Description Values Notes
add_header HTTP header to add Strict-Transport-Security Enforces HTTPS connections
max-age Duration in seconds 31536000 One year (default)
includeSubDomains Apply to subdomains true Optional, but recommended
preload Preload in browser lists true Optional, for major sites

Example: Basic HSTS Configuration

server {
    listen 443 ssl;
    server_name example.com;

    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
}

Example: HSTS with Preload

server {
    listen 443 ssl;
    server_name example.com;

    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
}
Note: HSTS headers are only effective over HTTPS. Ensure all traffic is redirected to HTTPS.
Warning: Misconfiguring HSTS can lead to permanent browser redirects. Test thoroughly before deploying.

8. Restricting File Access

Directive Description Default Notes
location Defines how to handle requests to a specific URI or path None Used to restrict access to sensitive files or directories
allow Allows access from specific IP addresses or networks None Can be used in conjunction with deny
deny Denies access from specific IP addresses or networks None Can be used in conjunction with allow
limit_req Controls the rate of requests to a location None Can be used to prevent brute-force attacks or DDoS

Example: Restricting Access to .env Files

location ~ /\.env {
    deny all;
}

Example: Restricting Access to Configuration Files

location ~ /config/.*\.(conf|yaml|yml)$ {
    deny all;
}

Example: Rate Limiting Requests

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

location /api/ {
    limit_req zone=api burst=5 nodelay;
}
Note: The location directive can be used with regex patterns to match specific file extensions or paths. The deny all directive blocks access to any matching files or directories.
Warning: Misconfiguring access restrictions can lead to unintended exposure of sensitive files or directories. Always test configurations in a staging environment before deploying to production.

9. Securing Admin Paths

Path Security Measure Description
/admin auth_basic Enables basic HTTP authentication for admin access
/admin allow/deny Restricts access to specific IP addresses or ranges
/admin location with limit_req Limits the number of requests to admin endpoints

Example: Basic Auth for Admin

location /admin {
    auth_basic "Admin Area";
    auth_basic_user_file /etc/nginx/htpasswd;
}

Example: IP Restriction for Admin

location /admin {
    allow 192.168.1.0/24;
    deny all;
}

Example: Rate Limiting for Admin

limit_req_zone $binary_remote_addr zone=admin:10m rate=1r/s;

location /admin {
    limit_req zone=admin burst=5 nodelay;
}

10. Preventing Buffer Overflow

Directive Description Default Notes
client_max_body_size Sets the maximum allowed size of the client request body. 1m Prevents large uploads from consuming memory or causing overflow.
client_body_buffer_size Defines the buffer size for reading client request body. 128k Controls how much data is read into memory at once.
large_client_header_buffers Defines the number and size of buffers for reading large client request headers. 4 8k Increases buffer size to prevent overflow in large headers.

Example: Configuring Buffer Limits

server {
    listen 80;
    client_max_body_size 10m;
    client_body_buffer_size 256k;
    large_client_header_buffers 4 16k;

    location /upload {
        client_max_body_size 50m;
    }
}
Note: Setting client_max_body_size to a reasonable limit prevents attackers from uploading excessively large files, which can lead to buffer overflows or denial of service.
Warning: If large_client_header_buffers is too small, Nginx may fail to parse large headers and return a 400 Bad Request error.

11. Using Secure Headers

Header Description Example Notes
Content-Security-Policy Prevents cross-site scripting (XSS) and other code injection attacks Content-Security-Policy: default-src 'self'; script-src 'self' https://apis.google.com; Use report-uri to report violations
X-Frame-Options Prevents clickjacking by controlling whether the page can be embedded in an iframe X-Frame-Options: DENY Values: DENY, SAMEORIGIN, ALLOW-FROM uri
X-Content-Type-Options Prevents browsers from interpreting files as a different MIME type than declared X-Content-Type-Options: nosniff Helps prevent MIME type sniffing attacks
X-XSS-Protection Enables XSS filtering in browsers (deprecated but still supported) X-XSS-Protection: 1; mode=block Deprecated in favor of CSP
Strict-Transport-Security Enforces secure (HTTPS) connections to the server Strict-Transport-Security: max-age=31536000; includeSubDomains Use preload for preloading in browsers
Referrer-Policy Controls how much referrer information is sent with requests Referrer-Policy: no-referrer-when-downgrade Values: no-referrer, origin, strict-origin

Example: Setting Secure Headers in Nginx

server {
    listen 443 ssl;
    server_name example.com;

    add_header Content-Security-Policy "default-src 'self'; script-src 'self' https://apis.google.com;";
    add_header X-Frame-Options DENY;
    add_header X-Content-Type-Options nosniff;
    add_header X-XSS-Protection "1; mode=block";
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains";
    add_header Referrer-Policy "no-referrer-when-downgrade";

    location / {
        root /var/www/html;
        index index.html;
    }
}
Note: CSP is the most powerful security header and should be configured carefully to avoid breaking legitimate functionality.

12. Implementing DDoS Protection

Example: Basic DDoS Protection Configuration

# Limit requests per IP
limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;

# Apply to specific location
location /api/ {
    limit_req zone=api burst=20 nodelay;
}
Directive Description Values
limit_req_zone Defines a shared memory zone for rate limiting $binary_remote_addr zone=name:size rate=r/s
limit_req Applies rate limiting to a location zone=name [burst=N] [nodelay]
burst Maximum number of requests allowed to exceed the rate limit Integer
nodelay Whether to delay requests or reject immediately true | false
Note: The limit_req_zone directive uses binary IP addresses for more efficient storage.

Example: Rate Limiting with Different Zones

# Rate limit for login attempts
limit_req_zone $binary_remote_addr zone=login:10m rate=5r/m;

# Rate limit for API calls
limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;

location /login {
    limit_req zone=login burst=5 nodelay;
}

location /api {
    limit_req zone=api burst=20 nodelay;
}

DDoS Protection Strategies

  • Use limit_req_zone to define rate limits per IP
  • Implement burst handling to allow temporary spikes
  • Apply rate limits selectively to sensitive paths (e.g., login, API)
  • Combine with geo or map to apply different rules based on IP or region

Was this article helpful?