Files
nginx-config/nginx.conf
2025-08-17 02:24:39 -07:00

306 lines
14 KiB
Nginx Configuration File

# ============================================================================
# Full nginx.conf for Nextcloud running in Docker BEHIND an external
# SSL-terminating reverse proxy (at 192.168.0.215).
#
# - This Nginx instance listens on HTTP/80.
# - It serves Nextcloud directly using PHP-FPM from the 'nextcloud:9000' container.
# - It trusts headers forwarded by the external proxy.
# - NO SSL configuration is needed here.
# ============================================================================
user www-data;
# Use 'auto' or set to the number of CPU cores available to the container
worker_processes auto;
# Standard error log and PID file paths within the container
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
# Adjust worker_connections based on expected load
worker_connections 1024;
}
http {
# Include standard MIME types
include /etc/nginx/mime.types;
default_type application/octet-stream;
# Custom MIME types - Enhanced for MJS support
types {
image/x-raw raw;
image/x-sony-arw arw;
application/javascript mjs; # Ensure MJS has proper MIME type
}
# Double-check the MIME type mapping by adding it globally
map $uri $javascript_module {
~\.mjs$ "application/javascript";
default "";
}
# ==================================================
# Proxy Handling & Real IP Configuration
# ==================================================
# Define the IP of the trusted external reverse proxy
set_real_ip_from 192.168.0.215;
# Specify the header containing the client's real IP
real_ip_header X-Forwarded-For;
# Use 'on' if the proxy might add multiple IPs (e.g., X-Forwarded-For: client, proxy1)
# real_ip_recursive on;
# ==================================================
# Logging Configuration
# ==================================================
# Log format including the forwarded-for header.
# If realip module works, $remote_addr will show the real client IP.
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;
# ==================================================
# Performance & Security Defaults
# ==================================================
server_tokens off; # Hide nginx version
sendfile on; # Use efficient file transfer
tcp_nopush on; # Optimize packet sending
tcp_nodelay on; # Reduce latency for keep-alive
keepalive_timeout 65; # Keep connections open longer
# Helper map for cache control (retained from original)
map $arg_v $asset_immutable {
"" "";
default ", immutable";
}
# ==================================================
# Upstream PHP-FPM Definition
# ==================================================
# Define the Nextcloud application container running PHP-FPM
upstream php-handler {
# Use the Docker service name and port
server nextcloud:9000;
}
# ==================================================
# Main Server Block (Listens on HTTP/80)
# ==================================================
server {
# Listen on port 80 within the container network
listen 80;
# listen [::]:80; # Uncomment if using IPv6 internally
# Optional: Set server name (domain used publicly)
# server_name cloud.example.com; # <<< Your public Nextcloud domain
# --- Basic Settings ---
# Set maximum allowed size for uploaded files
client_max_body_size 512M; # Adjust as needed
# Set timeout for reading client request body
client_body_timeout 300s;
# FastCGI buffer settings for PHP communication
fastcgi_buffers 64 4K;
client_body_buffer_size 512k; # Buffer for client request body
# --- Gzip Compression ---
gzip on;
gzip_vary on;
gzip_comp_level 4; # Balance between CPU and compression ratio
gzip_min_length 256; # Don't compress very small files
gzip_proxied expired no-cache no-store private no_last_modified no_etag auth; # Compress even for proxied requests
# Define types of files to compress
gzip_types
application/atom+xml application/javascript application/json application/ld+json
application/manifest+json application/rss+xml application/vnd.geo+json
application/vnd.ms-fontobject application/wasm application/x-font-ttf
application/x-web-app-manifest+json application/xhtml+xml application/xml
font/opentype image/bmp image/svg+xml image/x-icon text/cache-manifest
text/css text/plain text/vcard text/vnd.rim.location.xloc text/vtt
text/x-component text/x-cross-domain-policy;
# --- Security Headers ---
# These add defense-in-depth. HSTS should be set on the external proxy (192.168.0.215).
# add_header Strict-Transport-Security "max-age=..." always; # DO NOT set HSTS here
add_header Referrer-Policy "no-referrer" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Permitted-Cross-Domain-Policies "none" always;
add_header X-Robots-Tag "noindex, nofollow" always;
add_header X-XSS-Protection "1; mode=block" always;
# Content Security Policy (retained from original - review if suitable)
add_header Content-Security-Policy "frame-ancestors 'self'; connect-src 'self' blob: stun.nextcloud.com:443 wss://gabenszip.com https://gabenszip.com http://gabenszip.com ws://gabenszip.com gabenszip.com:* 'unsafe-eval' 'unsafe-inline'" always;
# Hide PHP's "X-Powered-By" header
fastcgi_hide_header X-Powered-By;
# --- Document Root ---
# IMPORTANT: Adjust this path if your Nextcloud files are mounted elsewhere in this container
root /var/www/html;
# Define default index files
index index.php index.html /index.php$request_uri;
# --- Location Blocks ---
# Deny access to sensitive files/directories
location ~ ^/(?:build|tests|config|lib|3rdparty|templates|data)(?:$|/) { return 404; }
location ~ ^/(?:\.|autotest|occ|issue|indie|db_|console) { return 404; }
# Handle /.well-known requests for service discovery (CalDAV, CardDAV, etc.)
location ^~ /.well-known {
location = /.well-known/carddav { return 301 /remote.php/dav/; }
location = /.well-known/caldav { return 301 /remote.php/dav/; }
# ACME challenges usually handled by external proxy, otherwise allow here if needed
location ~ ^/\.well-known/(acme-challenge|pki-validation)/ { allow all; }
# Let Nextcloud handle other .well-known requests via PHP
return 301 /index.php$request_uri;
}
# Special handling for Microsoft DAV clients hitting the root
location = / {
if ($http_user_agent ~ ^DavClnt) {
return 302 /remote.php/webdav/$is_args$args;
}
# If not DAV, fallback to PHP front controller
try_files $uri $uri/ /index.php$request_uri;
}
# Robots.txt - allow access
location = /robots.txt {
allow all;
log_not_found off;
access_log off;
}
# Enhanced handling for JavaScript module files (.mjs)
location ~* \.mjs$ {
# Multiple methods to ensure correct Content-Type header
types { application/javascript mjs; }
# Force the correct MIME type
default_type application/javascript;
# Explicitly set Content-Type header
add_header Content-Type application/javascript always;
# Override any default Content-Type
if ($javascript_module) {
add_header Content-Type $javascript_module always;
}
# Try serving file directly, else pass to PHP
try_files $uri /index.php$request_uri;
# Caching headers
add_header Cache-Control "public, max-age=15778463$asset_immutable";
# Add security headers
add_header Referrer-Policy "no-referrer" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Permitted-Cross-Domain-Policies "none" always;
add_header X-Robots-Tag "noindex, nofollow" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Content-Security-Policy "frame-ancestors 'self'; connect-src 'self' blob: stun.nextcloud.com:443 wss://gabenszip.com https://gabenszip.com http://gabenszip.com ws://gabenszip.com gabenszip.com:* 'unsafe-eval' 'unsafe-inline'" always;
# Disable access logging for static files
access_log off;
}
# Main PHP processing block
location ~ \.php(?:$|/) {
# Security rewrite: Prevent direct access to PHP files except known endpoints
rewrite ^/(?!index|remote|public|cron|core\/ajax\/update|status|ocs\/v[12]|updater\/.+|ocs-provider\/.+|.+\/richdocumentscode(_arm64)?\/proxy) /index.php$request_uri;
# Split path info for PHP (e.g., /index.php/foo/bar)
fastcgi_split_path_info ^(.+?\.php)(/.*)$;
set $path_info $fastcgi_path_info;
# Try the script itself, otherwise return 404
try_files $fastcgi_script_name =404;
# Include standard FastCGI parameters
include fastcgi_params;
# --- Crucial FastCGI Parameters ---
# Set script filename and path info
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $path_info;
# HTTPS handling
fastcgi_param HTTPS off; # Let Nextcloud config handle the protocol
# Force protocol settings to use HTTP (not HTTPS)
fastcgi_param HTTP_X_FORWARDED_PROTO http;
fastcgi_param REQUEST_SCHEME http;
# Pass the client's real IP address to PHP
fastcgi_param REMOTE_ADDR $remote_addr;
# Pass other useful headers from the proxy (ensure proxy sets them!)
fastcgi_param HTTP_X_FORWARDED_FOR $http_x_forwarded_for;
# Pass host header
fastcgi_param HTTP_HOST $http_host;
# Parameters for Nextcloud pretty URLs and header management
fastcgi_param modHeadersAvailable true;
fastcgi_param front_controller_active true;
# Send request to the PHP-FPM upstream handler defined earlier
fastcgi_pass php-handler;
# --- Performance & Error Handling ---
fastcgi_intercept_errors on; # Let Nginx handle PHP errors (e.g., show custom 50x page)
fastcgi_request_buffering off; # Disable buffering for long-running scripts/uploads
fastcgi_max_temp_file_size 0; # Prevent writing large uploads to temp files
}
# Serve static files (CSS, JS, images, including custom types)
location ~* \.(?:css|js|svg|gif|ico|jpe?g|png|webp|wasm|tflite|map|ogg|flac|arw|raw)$ {
# Try to serve file directly, else pass to PHP (e.g., for theming)
try_files $uri /index.php$request_uri;
# Caching headers
add_header Cache-Control "public, max-age=15778463$asset_immutable";
# Add security headers (can potentially be inherited)
add_header Referrer-Policy "no-referrer" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Permitted-Cross-Domain-Policies "none" always;
add_header X-Robots-Tag "noindex, nofollow" always;
add_header X-XSS-Protection "1; mode=block" always;
# Disable access logging for static files
access_log off;
# Specific MIME type for WebAssembly if needed explicitly
location ~ \.wasm$ {
default_type application/wasm;
}
}
# Serve font files with longer expiry
location ~ \.(?:woff2?|ttf|eot)$ {
# Try to serve file directly, else pass to PHP
try_files $uri /index.php$request_uri;
# Caching headers (fonts rarely change)
add_header Cache-Control "public, max-age=15778463$asset_immutable";
expires 7d; # Alternative cache control
# Add security headers (can potentially be inherited)
add_header Referrer-Policy "no-referrer" always;
add_header X-Content-Type-Options "nosniff" always;
# Disable access logging for static files
access_log off;
}
# Redirect for /remote endpoint used by some clients
location /remote {
return 301 /remote.php$request_uri;
}
# Fallback location - pass everything else to the PHP front controller
location / {
try_files $uri $uri/ /index.php$request_uri;
}
} # End server block (port 80)
} # End http block