Extra Settings
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
| Snippet | Location | Purpose |
|---|---|---|
internal-only.conf | server{} or location{} | Restrict to internal network |
debug-logging.conf | server{} or location{} | Verbose logging for troubleshooting |
php-handler.conf | server{} | Handle PHP via FastCGI |
maintenance.conf | server{} | Return 503 with Retry-After |
login-rate-limit.conf | location{} | Tight rate limits for auth endpoints |
real-ip-cloudflare.conf | server{} | Restore real IP behind Cloudflare |
The maintenance snippet uses
return 503which immediately terminates request processing. Any directives afterreturnin the same context are ignored. Placereturn 503last within its context, or use the include at the start of the server block to ensure it takes effect before any other processing.