Extra Settings

Posted on 19 2026

These snippets are not included automatically. They are prepared configurations for specific situations: restricting access to internal networks, debugging, maintenance mode, PHP handling, and rate limiting for sensitive endpoints. Include them in specific virtual server or location blocks as needed.

All files go in /etc/nginx/snippets/ alongside the snippets from the previous page.

Internal access only

The most commonly needed extra snippet: restricting a service so it is only accessible from the internal network, not the public internet.

Create /etc/nginx/snippets/internal-only.conf:

#
# Restrict access to internal network addresses only
# /etc/nginx/snippets/internal-only.conf
#
# Include in server{} or location{} blocks for admin interfaces,
# monitoring endpoints, or any service that should not be publicly accessible.
#

# Allow Unix domain sockets (local processes)
allow unix:;

# Allow localhost
allow 127.0.0.0/8;
allow ::1;

# Allow all three site subnets
allow 10.1.0.0/16;    # Prevernal site
allow 10.2.0.0/16;    # Vernal site
allow 10.3.0.0/16;    # Estival site

# Allow WireGuard VPN client subnet
allow 10.1.254.0/24;

# Deny everything else
deny all;

Usage:

# Restrict the PostfixAdmin interface to internal access only
location / {
    include snippets/internal-only.conf;
    proxy_pass http://127.0.0.1:8080;
    include snippets/proxy-headers.conf;
}

Debug logging

During troubleshooting, temporarily enable verbose logging for a specific virtual server or location.

Create /etc/nginx/snippets/debug-logging.conf:

#
# Debug logging
# /etc/nginx/snippets/debug-logging.conf
#
# Temporarily include in server{} or location{} for troubleshooting.
# REMOVE after debugging - generates significant log volume.
#

# Detailed error logging for this context
error_log /var/log/nginx/debug.log debug;

# Enable access logging
access_log /var/log/nginx/debug-access.log main;

# Log subrequests (auth_request, SSI, etc.)
log_subrequest on;

# Log 404 errors for missing files
log_not_found on;

# Log rewrite rule processing
rewrite_log on;

Usage:

server {
    server_name problemsite.yourdomain.net;

    # Temporary debug logging - remove after troubleshooting
    include snippets/debug-logging.conf;

    ...
}

Follow the debug log:

sudo tail -f /var/log/nginx/debug.log

Remove the include and reload nginx when troubleshooting is complete.

PHP handler

For virtual servers that serve PHP applications directly (rather than via a reverse proxy).

Create /etc/nginx/snippets/php-handler.conf:

#
# PHP FastCGI handler
# /etc/nginx/snippets/php-handler.conf
#
# Include in server{} blocks for PHP applications.
# Requires the php-fpm upstream defined in conf.d/php-fpm.conf
#

index index.php index.html index.htm;

# Pass PHP scripts to PHP-FPM
location ~ [^/]\.php(/|$) {

    # Split the URL into script path and path info
    fastcgi_split_path_info ^(.+?\.php)(/.*)$;

    # Verify the script file exists before passing to backend
    # Prevents passing non-existent scripts to PHP
    try_files $fastcgi_script_name =404;

    # Pass to PHP-FPM
    fastcgi_pass php-fpm;
    fastcgi_index index.php;

    # Standard FastCGI parameters
    include fastcgi_params;

    # Script filename for PHP
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    fastcgi_param PATH_INFO $fastcgi_path_info;

    # httpoxy mitigation (CVE-2016-5385)
    fastcgi_param HTTP_PROXY '';

    # Pass HTTPS status to PHP
    fastcgi_param HTTPS $https if_not_empty;
}

The try_files $fastcgi_script_name =404 check prevents a common vulnerability where nginx passes requests for non-existent PHP files to PHP-FPM, which then executes whatever PHP it finds by walking up the directory tree. Always include this check.

Maintenance mode

For taking a service offline temporarily while showing a maintenance page.

Create /etc/nginx/snippets/maintenance.conf:

#
# Server maintenance mode
# /etc/nginx/snippets/maintenance.conf
#
# Include in server{} to put a site into maintenance mode.
# Returns 503 with Retry-After header.
#
# Set $maintenance_retry in the server{} block before including:
#   set $maintenance_retry '3600';  # Retry in 1 hour
#

# Default retry time if not set by the server block
set_if_empty $maintenance_retry '900';

# Set Retry-After header
add_header Retry-After $maintenance_retry always;

# Return 503 Service Unavailable
return 503;

Usage:

server {
    server_name nextcloud.yourdomain.net;

    # Maintenance mode: retry in 30 minutes
    set $maintenance_retry '1800';
    include snippets/maintenance.conf;
}

To allow internal access to bypass maintenance (for testing the site is ready before lifting maintenance):

server {
    server_name nextcloud.yourdomain.net;

    # Allow internal access to bypass maintenance
    location / {
        # Allow internal access
        allow 10.0.0.0/8;
        allow 127.0.0.0/8;

        # Return 503 for external access
        if ($remote_addr !~* "^10\.") {
            set $maintenance_retry '1800';
            return 503;
        }

        proxy_pass http://127.0.0.1:8080;
        include snippets/proxy-headers.conf;
    }
}

Aggressive rate limiting for sensitive endpoints

The global rate limiting zones defined in conf.d/rate-limiting.conf are intentionally permissive. Sensitive endpoints like login pages and password reset forms need much tighter limits.

Create /etc/nginx/snippets/login-rate-limit.conf:

#
# Aggressive rate limiting for authentication endpoints
# /etc/nginx/snippets/login-rate-limit.conf
#
# Include in location blocks for login pages, API auth endpoints,
# password reset forms, and similar sensitive endpoints.
#

# 1 request per minute per IP for login attempts
limit_req zone=ip_req burst=3 nodelay;

# Maximum 2 simultaneous connections per IP to this endpoint
limit_conn ip_conn 2;

Usage in a Nextcloud virtual server:

location /login {
    include snippets/login-rate-limit.conf;
    proxy_pass http://127.0.0.1:8080/login;
    include snippets/proxy-headers.conf;
}

Note: the ip_req zone allows 10r/s globally. Using it for login rate limiting still allows 10 requests per second, which is far too permissive. For proper login rate limiting, define a separate, more restrictive zone in conf.d/rate-limiting.conf:

# Add to conf.d/rate-limiting.conf
# Very strict: 1 request per 10 seconds per IP for auth endpoints
limit_req_zone $binary_remote_addr zone=auth_req:10m rate=6r/m;

Then reference this stricter zone in login-rate-limit.conf:

limit_req zone=auth_req burst=3 nodelay;
limit_conn ip_conn 2;

Real IP from trusted proxies

If the nginx container is behind another reverse proxy (for example, a cloud load balancer or a Cloudflare proxy), configure nginx to extract the real client IP from the X-Forwarded-For header.

Create /etc/nginx/snippets/real-ip-cloudflare.conf if using Cloudflare:

#
# Real IP restoration for Cloudflare-proxied connections
# /etc/nginx/snippets/real-ip-cloudflare.conf
#
# Include in server{} blocks for sites behind Cloudflare.
# Update the IP ranges from: https://www.cloudflare.com/ips/
#

# Cloudflare IPv4 ranges (updated 2026)
set_real_ip_from 103.21.244.0/22;
set_real_ip_from 103.22.200.0/22;
set_real_ip_from 103.31.4.0/22;
set_real_ip_from 104.16.0.0/13;
set_real_ip_from 104.24.0.0/14;
set_real_ip_from 108.162.192.0/18;
set_real_ip_from 131.0.72.0/22;
set_real_ip_from 141.101.64.0/18;
set_real_ip_from 162.158.0.0/15;
set_real_ip_from 172.64.0.0/13;
set_real_ip_from 173.245.48.0/20;
set_real_ip_from 188.114.96.0/20;
set_real_ip_from 190.93.240.0/20;
set_real_ip_from 197.234.240.0/22;
set_real_ip_from 198.41.128.0/17;

# Cloudflare IPv6 ranges
set_real_ip_from 2400:cb00::/32;
set_real_ip_from 2405:8100::/32;
set_real_ip_from 2405:b500::/32;
set_real_ip_from 2606:4700::/32;
set_real_ip_from 2803:f800::/32;
set_real_ip_from 2a06:98c0::/29;
set_real_ip_from 2c0f:f248::/32;

# Use the CF-Connecting-IP header for the real client IP
real_ip_header CF-Connecting-IP;

The Cloudflare IP ranges change periodically. Check https://www.cloudflare.com/ips/ for the current list. This series connects directly to the internet without Cloudflare, so this snippet is provided for reference rather than active use.

Snippet quick reference

SnippetLocationPurpose
internal-only.confserver{} or location{}Restrict to internal network
debug-logging.confserver{} or location{}Verbose logging for troubleshooting
php-handler.confserver{}Handle PHP via FastCGI
maintenance.confserver{}Return 503 with Retry-After
login-rate-limit.conflocation{}Tight rate limits for auth endpoints
real-ip-cloudflare.confserver{}Restore real IP behind Cloudflare

The maintenance snippet uses return 503 which immediately terminates request processing. Any directives after return in the same context are ignored. Place return 503 last within its context, or use the include at the start of the server block to ensure it takes effect before any other processing.