# 5q12-indexer secure nginx config with X-Accel-Redirect support and clean URL routing server { listen 5012; server_name 5q12-indexer; # Document root root {WEB_PATH}; index index.php; # CRITICAL: Internal location for X-Accel-Redirect file serving # This allows nginx to serve files directly after PHP authorization location /internal-files/ { internal; # Only accessible via X-Accel-Redirect alias {WEB_PATH}/files/; # Map to your actual files directory # Optimize for large file downloads sendfile on; sendfile_max_chunk 1m; tcp_nopush on; tcp_nodelay on; # Support range requests for resume capability add_header Accept-Ranges bytes; # No caching for downloads expires off; add_header Cache-Control "no-cache, no-store, must-revalidate"; add_header Pragma "no-cache"; } # Allow CSS and font files from .indexer_files/local_api/style directory location ~ ^/\.indexer_files/local_api/style/.*\.(css|woff2)$ { # Set proper MIME types location ~* \.css$ { add_header Content-Type "text/css" always; } location ~* \.woff2$ { add_header Content-Type "font/woff2" always; } # Cache static assets expires 1d; add_header Cache-Control "public, immutable" always; add_header X-Content-Type-Options "nosniff" always; try_files $uri =404; } # Allow PNG files from .indexer_files/icons directory location ~ ^/\.indexer_files/icons/.*\.png$ { # Set proper MIME type for images add_header Content-Type "image/png" always; # Cache icons expires 7d; add_header Cache-Control "public, immutable" always; add_header X-Content-Type-Options "nosniff" always; try_files $uri =404; } # Allow favicon files from .indexer_files/favicon directory location ~ ^/\.indexer_files/favicon/.*\.(ico|png)$ { # Set proper MIME types location ~* \.ico$ { add_header Content-Type "image/x-icon" always; } location ~* \.png$ { add_header Content-Type "image/png" always; } # Cache favicons expires 7d; add_header Cache-Control "public, immutable" always; add_header X-Content-Type-Options "nosniff" always; try_files $uri =404; } # Explicitly deny access to other .indexer_files subdirectories location ~ ^/\.indexer_files/(?!local_api/style/|icons/|favicon/) { deny all; return 404; } # Main indexer application - handle all requests through index.php with clean URLs location / { # Add security headers for non-download requests add_header X-Frame-Options "SAMEORIGIN" always; add_header X-Content-Type-Options "nosniff" always; add_header X-XSS-Protection "1; mode=block" always; # Route everything through index.php for clean URL handling try_files $uri $uri/ /index.php$is_args$args; } # PHP handler with optimizations for downloads location ~ \.php$ { # Only allow index.php to be executed if ($uri != "/index.php") { return 404; } try_files $uri =404; fastcgi_split_path_info ^(.+\.php)(/.+)$; fastcgi_pass unix:/var/run/php/php-fpm.sock; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; # Extended timeouts for large operations fastcgi_read_timeout 7200; # 2 hours fastcgi_send_timeout 7200; # 2 hours # Disable buffering for downloads to allow X-Accel-Redirect fastcgi_buffering off; fastcgi_request_buffering off; # Don't add security headers for downloads (they're added in location / block) set $is_download 0; if ($arg_download) { set $is_download 1; } } # Deny access to configuration and sensitive files location ~ /\.(ht|git|env|log|sqlite|json)$ { deny all; return 404; } # Deny access to backup and temporary files location ~ \.(bak|backup|old|tmp|temp|swp|swo|~)$ { deny all; return 404; } # Deny access to common sensitive filenames location ~ ^/(config|configuration|settings|private|admin|api|\.well-known) { deny all; return 404; } # Block common attack patterns location ~ /(wp-|wordpress|admin|phpmyadmin|mysql|database) { deny all; return 404; } # Increased limits for large file operations client_max_body_size 200G; client_body_buffer_size 128k; client_header_buffer_size 4k; large_client_header_buffers 8 8k; # Rate limiting (optional - uncomment if needed) # limit_req_zone $binary_remote_addr zone=indexer:10m rate=10r/s; # limit_req zone=indexer burst=20 nodelay; }