View Raw
# 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;
}