# Local Ginxsom Development Server Configuration # Comprehensive Blossom Protocol Implementation # Main context - specify error log here to override system default error_log logs/nginx/error.log info; pid logs/nginx/nginx.pid; events { worker_connections 1024; } # HTTP context http { # Basic settings sendfile on; tcp_nopush on; tcp_nodelay on; keepalive_timeout 65; types_hash_max_size 2048; # Temporary file paths (relative to nginx prefix) client_body_temp_path tmp/nginx_temp; # MIME types (local) include mime.types; default_type application/octet-stream; # Logging (relative to prefix directory) access_log logs/nginx/access.log; # FastCGI upstream configuration upstream fastcgi_backend { server unix:/tmp/ginxsom-fcgi.sock; } # Map endpoints to their allowed methods for CORS map $uri $cors_methods { default "GET, HEAD, OPTIONS"; /upload "PUT, HEAD, OPTIONS"; /mirror "PUT, OPTIONS"; /report "PUT, OPTIONS"; /auth "GET, OPTIONS"; ~^/list/ "GET, OPTIONS"; ~^/api/ "GET, PUT, OPTIONS"; ~^/[a-f0-9]\{64\} "GET, HEAD, DELETE, OPTIONS"; } # Local development server - HTTP server { listen 9001; server_name localhost; # Root directory for blossom files (local blobs directory) root blobs; # Maximum upload size (adjust as needed) client_max_body_size 100M; # Security headers add_header X-Content-Type-Options nosniff always; add_header X-Frame-Options DENY always; add_header X-XSS-Protection "1; mode=block" always; # Universal CORS headers for all responses add_header Access-Control-Allow-Origin * always; add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, HEAD, OPTIONS, PATCH" always; add_header Access-Control-Allow-Headers "Authorization, Content-Type, Content-Length, Accept, Origin, User-Agent, DNT, Cache-Control, X-Mx-ReqToken, Keep-Alive, X-Requested-With, If-Modified-Since, *" always; add_header Access-Control-Max-Age 86400 always; # Universal OPTIONS preflight handler if ($request_method = OPTIONS) { return 204; } # 1. SPECIFIC ENDPOINTS (most specific first) # PUT /upload (BUD-02) - File uploads location = /upload { if ($request_method !~ ^(PUT|HEAD)$) { return 405; } fastcgi_pass fastcgi_backend; fastcgi_param QUERY_STRING $query_string; fastcgi_param REQUEST_METHOD $request_method; fastcgi_param CONTENT_TYPE $content_type; fastcgi_param CONTENT_LENGTH $content_length; fastcgi_param SCRIPT_NAME $fastcgi_script_name; fastcgi_param REQUEST_URI $request_uri; fastcgi_param DOCUMENT_URI $document_uri; fastcgi_param DOCUMENT_ROOT $document_root; fastcgi_param SERVER_PROTOCOL $server_protocol; fastcgi_param REQUEST_SCHEME $scheme; fastcgi_param HTTPS $https if_not_empty; fastcgi_param GATEWAY_INTERFACE CGI/1.1; fastcgi_param SERVER_SOFTWARE nginx/$nginx_version; fastcgi_param REMOTE_ADDR $remote_addr; fastcgi_param REMOTE_PORT $remote_port; fastcgi_param SERVER_ADDR $server_addr; fastcgi_param SERVER_PORT $server_port; fastcgi_param SERVER_NAME $server_name; fastcgi_param REDIRECT_STATUS 200; fastcgi_param SCRIPT_FILENAME $document_root/ginxsom.fcgi; fastcgi_param HTTP_AUTHORIZATION $http_authorization; } # GET /list/ (BUD-02) - List user's blobs location ~ "^/list/([a-f0-9]{64})$" { if ($request_method !~ ^(GET)$) { return 405; } fastcgi_pass fastcgi_backend; fastcgi_param QUERY_STRING $query_string; fastcgi_param REQUEST_METHOD $request_method; fastcgi_param CONTENT_TYPE $content_type; fastcgi_param CONTENT_LENGTH $content_length; fastcgi_param SCRIPT_NAME $fastcgi_script_name; fastcgi_param REQUEST_URI $request_uri; fastcgi_param DOCUMENT_URI $document_uri; fastcgi_param DOCUMENT_ROOT $document_root; fastcgi_param SERVER_PROTOCOL $server_protocol; fastcgi_param REQUEST_SCHEME $scheme; fastcgi_param HTTPS $https if_not_empty; fastcgi_param GATEWAY_INTERFACE CGI/1.1; fastcgi_param SERVER_SOFTWARE nginx/$nginx_version; fastcgi_param REMOTE_ADDR $remote_addr; fastcgi_param REMOTE_PORT $remote_port; fastcgi_param SERVER_ADDR $server_addr; fastcgi_param SERVER_PORT $server_port; fastcgi_param SERVER_NAME $server_name; fastcgi_param REDIRECT_STATUS 200; fastcgi_param SCRIPT_FILENAME $document_root/ginxsom.fcgi; fastcgi_param HTTP_AUTHORIZATION $http_authorization; } # PUT /mirror (BUD-04) - Mirror content location = /mirror { if ($request_method !~ ^(PUT)$) { return 405; } fastcgi_pass fastcgi_backend; fastcgi_param QUERY_STRING $query_string; fastcgi_param REQUEST_METHOD $request_method; fastcgi_param CONTENT_TYPE $content_type; fastcgi_param CONTENT_LENGTH $content_length; fastcgi_param SCRIPT_NAME $fastcgi_script_name; fastcgi_param REQUEST_URI $request_uri; fastcgi_param DOCUMENT_URI $document_uri; fastcgi_param DOCUMENT_ROOT $document_root; fastcgi_param SERVER_PROTOCOL $server_protocol; fastcgi_param REQUEST_SCHEME $scheme; fastcgi_param HTTPS $https if_not_empty; fastcgi_param GATEWAY_INTERFACE CGI/1.1; fastcgi_param SERVER_SOFTWARE nginx/$nginx_version; fastcgi_param REMOTE_ADDR $remote_addr; fastcgi_param REMOTE_PORT $remote_port; fastcgi_param SERVER_ADDR $server_addr; fastcgi_param SERVER_PORT $server_port; fastcgi_param SERVER_NAME $server_name; fastcgi_param REDIRECT_STATUS 200; fastcgi_param SCRIPT_FILENAME $document_root/ginxsom.fcgi; fastcgi_param HTTP_AUTHORIZATION $http_authorization; } # PUT /report (BUD-09) - Report content location = /report { if ($request_method !~ ^(PUT)$) { return 405; } fastcgi_pass fastcgi_backend; fastcgi_param QUERY_STRING $query_string; fastcgi_param REQUEST_METHOD $request_method; fastcgi_param CONTENT_TYPE $content_type; fastcgi_param CONTENT_LENGTH $content_length; fastcgi_param SCRIPT_NAME $fastcgi_script_name; fastcgi_param REQUEST_URI $request_uri; fastcgi_param DOCUMENT_URI $document_uri; fastcgi_param DOCUMENT_ROOT $document_root; fastcgi_param SERVER_PROTOCOL $server_protocol; fastcgi_param REQUEST_SCHEME $scheme; fastcgi_param HTTPS $https if_not_empty; fastcgi_param GATEWAY_INTERFACE CGI/1.1; fastcgi_param SERVER_SOFTWARE nginx/$nginx_version; fastcgi_param REMOTE_ADDR $remote_addr; fastcgi_param REMOTE_PORT $remote_port; fastcgi_param SERVER_ADDR $server_addr; fastcgi_param SERVER_PORT $server_port; fastcgi_param SERVER_NAME $server_name; fastcgi_param REDIRECT_STATUS 200; fastcgi_param SCRIPT_FILENAME $document_root/ginxsom.fcgi; fastcgi_param HTTP_AUTHORIZATION $http_authorization; } # GET /auth (NIP-42) - Challenge generation location = /auth { if ($request_method !~ ^(GET)$) { return 405; } fastcgi_pass fastcgi_backend; fastcgi_param QUERY_STRING $query_string; fastcgi_param REQUEST_METHOD $request_method; fastcgi_param CONTENT_TYPE $content_type; fastcgi_param CONTENT_LENGTH $content_length; fastcgi_param SCRIPT_NAME $fastcgi_script_name; fastcgi_param REQUEST_URI $request_uri; fastcgi_param DOCUMENT_URI $document_uri; fastcgi_param DOCUMENT_ROOT $document_root; fastcgi_param SERVER_PROTOCOL $server_protocol; fastcgi_param REQUEST_SCHEME $scheme; fastcgi_param HTTPS $https if_not_empty; fastcgi_param GATEWAY_INTERFACE CGI/1.1; fastcgi_param SERVER_SOFTWARE nginx/$nginx_version; fastcgi_param REMOTE_ADDR $remote_addr; fastcgi_param REMOTE_PORT $remote_port; fastcgi_param SERVER_ADDR $server_addr; fastcgi_param SERVER_PORT $server_port; fastcgi_param SERVER_NAME $server_name; fastcgi_param REDIRECT_STATUS 200; fastcgi_param SCRIPT_FILENAME $document_root/ginxsom.fcgi; fastcgi_param HTTP_AUTHORIZATION $http_authorization; } # Admin API endpoints (/api/*) location /api/ { if ($request_method !~ ^(GET|PUT|POST)$) { return 405; } fastcgi_pass fastcgi_backend; fastcgi_param QUERY_STRING $query_string; fastcgi_param REQUEST_METHOD $request_method; fastcgi_param CONTENT_TYPE $content_type; fastcgi_param CONTENT_LENGTH $content_length; fastcgi_param SCRIPT_NAME $fastcgi_script_name; fastcgi_param REQUEST_URI $request_uri; fastcgi_param DOCUMENT_URI $document_uri; fastcgi_param DOCUMENT_ROOT $document_root; fastcgi_param SERVER_PROTOCOL $server_protocol; fastcgi_param REQUEST_SCHEME $scheme; fastcgi_param HTTPS $https if_not_empty; fastcgi_param GATEWAY_INTERFACE CGI/1.1; fastcgi_param SERVER_SOFTWARE nginx/$nginx_version; fastcgi_param REMOTE_ADDR $remote_addr; fastcgi_param REMOTE_PORT $remote_port; fastcgi_param SERVER_ADDR $server_addr; fastcgi_param SERVER_PORT $server_port; fastcgi_param SERVER_NAME $server_name; fastcgi_param REDIRECT_STATUS 200; fastcgi_param SCRIPT_FILENAME $document_root/ginxsom.fcgi; fastcgi_param HTTP_AUTHORIZATION $http_authorization; } # 2. BLOB OPERATIONS (SHA256 patterns) # GET/HEAD/DELETE / (BUD-01) - Blob operations with optional file extensions location ~ "^/([a-f0-9]{64})(\.[a-zA-Z0-9]+)?$" { # Handle DELETE method via rewrite to avoid fastcgi_param in if block if ($request_method = DELETE) { rewrite ^/(.*)$ /fcgi-delete/$1 last; } # Route HEAD requests to FastCGI for metadata if ($request_method = HEAD) { rewrite ^/(.*)$ /fcgi-head/$1 last; } # Only allow GET for file serving at this point if ($request_method != GET) { return 405; } # GET requests - serve files directly with extension fallback try_files /$1.txt /$1.jpg /$1.jpeg /$1.png /$1.webp /$1.gif /$1.pdf /$1.mp4 /$1.mp3 /$1.md =404; # Cache headers for blob content add_header Cache-Control "public, max-age=31536000, immutable"; add_header Access-Control-Allow-Origin * always; add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, HEAD, OPTIONS, PATCH" always; add_header Access-Control-Allow-Headers "Authorization, Content-Type, Content-Length, Accept, Origin, User-Agent, DNT, Cache-Control, X-Mx-ReqToken, Keep-Alive, X-Requested-With, If-Modified-Since, *" always; add_header Access-Control-Max-Age 86400 always; } # Internal handler for DELETE operations location ~ "^/fcgi-delete/([a-f0-9]{64}).*$" { internal; fastcgi_pass fastcgi_backend; fastcgi_param QUERY_STRING $query_string; fastcgi_param REQUEST_METHOD DELETE; fastcgi_param CONTENT_TYPE $content_type; fastcgi_param CONTENT_LENGTH $content_length; fastcgi_param SCRIPT_NAME $fastcgi_script_name; fastcgi_param REQUEST_URI /$1; fastcgi_param DOCUMENT_URI /$1; fastcgi_param DOCUMENT_ROOT $document_root; fastcgi_param SERVER_PROTOCOL $server_protocol; fastcgi_param REQUEST_SCHEME $scheme; fastcgi_param HTTPS $https if_not_empty; fastcgi_param GATEWAY_INTERFACE CGI/1.1; fastcgi_param SERVER_SOFTWARE nginx/$nginx_version; fastcgi_param REMOTE_ADDR $remote_addr; fastcgi_param REMOTE_PORT $remote_port; fastcgi_param SERVER_ADDR $server_addr; fastcgi_param SERVER_PORT $server_port; fastcgi_param SERVER_NAME $server_name; fastcgi_param REDIRECT_STATUS 200; fastcgi_param SCRIPT_FILENAME $document_root/ginxsom.fcgi; fastcgi_param HTTP_AUTHORIZATION $http_authorization; } # FastCGI handler for HEAD requests location ~ "^/fcgi-head/([a-f0-9]{64}).*$" { internal; fastcgi_pass fastcgi_backend; fastcgi_param QUERY_STRING $query_string; fastcgi_param REQUEST_METHOD HEAD; fastcgi_param CONTENT_TYPE $content_type; fastcgi_param CONTENT_LENGTH $content_length; fastcgi_param SCRIPT_NAME $fastcgi_script_name; fastcgi_param REQUEST_URI /$1; fastcgi_param DOCUMENT_URI /$1; fastcgi_param DOCUMENT_ROOT $document_root; fastcgi_param SERVER_PROTOCOL $server_protocol; fastcgi_param REQUEST_SCHEME $scheme; fastcgi_param HTTPS $https if_not_empty; fastcgi_param GATEWAY_INTERFACE CGI/1.1; fastcgi_param SERVER_SOFTWARE nginx/$nginx_version; fastcgi_param REMOTE_ADDR $remote_addr; fastcgi_param REMOTE_PORT $remote_port; fastcgi_param SERVER_ADDR $server_addr; fastcgi_param SERVER_PORT $server_port; fastcgi_param SERVER_NAME $server_name; fastcgi_param REDIRECT_STATUS 200; fastcgi_param SCRIPT_FILENAME $document_root/ginxsom.fcgi; fastcgi_param HTTP_AUTHORIZATION $http_authorization; } # 3. UTILITY ENDPOINTS # Health check endpoint location /health { access_log off; return 200 "OK\n"; add_header Content-Type text/plain; add_header Access-Control-Allow-Origin * always; add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, HEAD, OPTIONS, PATCH" always; add_header Access-Control-Allow-Headers "Authorization, Content-Type, Content-Length, Accept, Origin, User-Agent, DNT, Cache-Control, X-Mx-ReqToken, Keep-Alive, X-Requested-With, If-Modified-Since, *" always; add_header Access-Control-Max-Age 86400 always; } # List files endpoint for debugging location /debug/list { autoindex on; autoindex_format json; } # Root endpoint - Server info from FastCGI location = / { if ($request_method !~ ^(GET)$) { return 405; } fastcgi_pass fastcgi_backend; fastcgi_param QUERY_STRING $query_string; fastcgi_param REQUEST_METHOD $request_method; fastcgi_param CONTENT_TYPE $content_type; fastcgi_param CONTENT_LENGTH $content_length; fastcgi_param SCRIPT_NAME $fastcgi_script_name; fastcgi_param REQUEST_URI $request_uri; fastcgi_param DOCUMENT_URI $document_uri; fastcgi_param DOCUMENT_ROOT $document_root; fastcgi_param SERVER_PROTOCOL $server_protocol; fastcgi_param REQUEST_SCHEME $scheme; fastcgi_param HTTPS $https if_not_empty; fastcgi_param GATEWAY_INTERFACE CGI/1.1; fastcgi_param SERVER_SOFTWARE nginx/$nginx_version; fastcgi_param REMOTE_ADDR $remote_addr; fastcgi_param REMOTE_PORT $remote_port; fastcgi_param SERVER_ADDR $server_addr; fastcgi_param SERVER_PORT $server_port; fastcgi_param SERVER_NAME $server_name; fastcgi_param REDIRECT_STATUS 200; fastcgi_param SCRIPT_FILENAME $document_root/ginxsom.fcgi; fastcgi_param HTTP_AUTHORIZATION $http_authorization; } } # Local development server - HTTPS server { listen 9443 ssl; server_name localhost; # SSL Configuration using existing certificates ssl_certificate /home/teknari/.ssl_for_local_servers/cert.pem; ssl_certificate_key /home/teknari/.ssl_for_local_servers/key.pem; # SSL Security settings ssl_protocols TLSv1.2 TLSv1.3; ssl_prefer_server_ciphers on; ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384; # Root directory for blossom files (local blobs directory) root blobs; # Maximum upload size (adjust as needed) client_max_body_size 100M; # Security headers add_header X-Content-Type-Options nosniff always; add_header X-Frame-Options DENY always; add_header X-XSS-Protection "1; mode=block" always; # Universal CORS headers for all responses add_header Access-Control-Allow-Origin * always; add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, HEAD, OPTIONS, PATCH" always; add_header Access-Control-Allow-Headers "Authorization, Content-Type, Content-Length, Accept, Origin, User-Agent, DNT, Cache-Control, X-Mx-ReqToken, Keep-Alive, X-Requested-With, If-Modified-Since, *" always; add_header Access-Control-Max-Age 86400 always; # Universal OPTIONS preflight handler if ($request_method = OPTIONS) { return 204; } # 1. SPECIFIC ENDPOINTS (most specific first) # PUT /upload (BUD-02) - File uploads location = /upload { if ($request_method !~ ^(PUT|HEAD)$) { return 405; } # CORS headers add_header Access-Control-Allow-Origin * always; add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, HEAD, OPTIONS, PATCH" always; add_header Access-Control-Allow-Headers "Authorization, Content-Type, Content-Length, Accept, Origin, User-Agent, DNT, Cache-Control, X-Mx-ReqToken, Keep-Alive, X-Requested-With, If-Modified-Since, *" always; add_header Access-Control-Max-Age 86400 always; fastcgi_pass fastcgi_backend; fastcgi_param QUERY_STRING $query_string; fastcgi_param REQUEST_METHOD $request_method; fastcgi_param CONTENT_TYPE $content_type; fastcgi_param CONTENT_LENGTH $content_length; fastcgi_param SCRIPT_NAME $fastcgi_script_name; fastcgi_param REQUEST_URI $request_uri; fastcgi_param DOCUMENT_URI $document_uri; fastcgi_param DOCUMENT_ROOT $document_root; fastcgi_param SERVER_PROTOCOL $server_protocol; fastcgi_param REQUEST_SCHEME $scheme; fastcgi_param HTTPS $https if_not_empty; fastcgi_param GATEWAY_INTERFACE CGI/1.1; fastcgi_param SERVER_SOFTWARE nginx/$nginx_version; fastcgi_param REMOTE_ADDR $remote_addr; fastcgi_param REMOTE_PORT $remote_port; fastcgi_param SERVER_ADDR $server_addr; fastcgi_param SERVER_PORT $server_port; fastcgi_param SERVER_NAME $server_name; fastcgi_param REDIRECT_STATUS 200; fastcgi_param SCRIPT_FILENAME $document_root/ginxsom.fcgi; fastcgi_param HTTP_AUTHORIZATION $http_authorization; } # GET /list/ (BUD-02) - List user's blobs location ~ "^/list/([a-f0-9]{64})$" { if ($request_method !~ ^(GET)$) { return 405; } fastcgi_pass fastcgi_backend; fastcgi_param QUERY_STRING $query_string; fastcgi_param REQUEST_METHOD $request_method; fastcgi_param CONTENT_TYPE $content_type; fastcgi_param CONTENT_LENGTH $content_length; fastcgi_param SCRIPT_NAME $fastcgi_script_name; fastcgi_param REQUEST_URI $request_uri; fastcgi_param DOCUMENT_URI $document_uri; fastcgi_param DOCUMENT_ROOT $document_root; fastcgi_param SERVER_PROTOCOL $server_protocol; fastcgi_param REQUEST_SCHEME $scheme; fastcgi_param HTTPS $https if_not_empty; fastcgi_param GATEWAY_INTERFACE CGI/1.1; fastcgi_param SERVER_SOFTWARE nginx/$nginx_version; fastcgi_param REMOTE_ADDR $remote_addr; fastcgi_param REMOTE_PORT $remote_port; fastcgi_param SERVER_ADDR $server_addr; fastcgi_param SERVER_PORT $server_port; fastcgi_param SERVER_NAME $server_name; fastcgi_param REDIRECT_STATUS 200; fastcgi_param SCRIPT_FILENAME $document_root/ginxsom.fcgi; fastcgi_param HTTP_AUTHORIZATION $http_authorization; } # PUT /mirror (BUD-04) - Mirror content location = /mirror { if ($request_method !~ ^(PUT)$) { return 405; } fastcgi_pass fastcgi_backend; fastcgi_param QUERY_STRING $query_string; fastcgi_param REQUEST_METHOD $request_method; fastcgi_param CONTENT_TYPE $content_type; fastcgi_param CONTENT_LENGTH $content_length; fastcgi_param SCRIPT_NAME $fastcgi_script_name; fastcgi_param REQUEST_URI $request_uri; fastcgi_param DOCUMENT_URI $document_uri; fastcgi_param DOCUMENT_ROOT $document_root; fastcgi_param SERVER_PROTOCOL $server_protocol; fastcgi_param REQUEST_SCHEME $scheme; fastcgi_param HTTPS $https if_not_empty; fastcgi_param GATEWAY_INTERFACE CGI/1.1; fastcgi_param SERVER_SOFTWARE nginx/$nginx_version; fastcgi_param REMOTE_ADDR $remote_addr; fastcgi_param REMOTE_PORT $remote_port; fastcgi_param SERVER_ADDR $server_addr; fastcgi_param SERVER_PORT $server_port; fastcgi_param SERVER_NAME $server_name; fastcgi_param REDIRECT_STATUS 200; fastcgi_param SCRIPT_FILENAME $document_root/ginxsom.fcgi; fastcgi_param HTTP_AUTHORIZATION $http_authorization; } # PUT /report (BUD-09) - Report content location = /report { if ($request_method !~ ^(PUT)$) { return 405; } fastcgi_pass fastcgi_backend; fastcgi_param QUERY_STRING $query_string; fastcgi_param REQUEST_METHOD $request_method; fastcgi_param CONTENT_TYPE $content_type; fastcgi_param CONTENT_LENGTH $content_length; fastcgi_param SCRIPT_NAME $fastcgi_script_name; fastcgi_param REQUEST_URI $request_uri; fastcgi_param DOCUMENT_URI $document_uri; fastcgi_param DOCUMENT_ROOT $document_root; fastcgi_param SERVER_PROTOCOL $server_protocol; fastcgi_param REQUEST_SCHEME $scheme; fastcgi_param HTTPS $https if_not_empty; fastcgi_param GATEWAY_INTERFACE CGI/1.1; fastcgi_param SERVER_SOFTWARE nginx/$nginx_version; fastcgi_param REMOTE_ADDR $remote_addr; fastcgi_param REMOTE_PORT $remote_port; fastcgi_param SERVER_ADDR $server_addr; fastcgi_param SERVER_PORT $server_port; fastcgi_param SERVER_NAME $server_name; fastcgi_param REDIRECT_STATUS 200; fastcgi_param SCRIPT_FILENAME $document_root/ginxsom.fcgi; fastcgi_param HTTP_AUTHORIZATION $http_authorization; } # GET /auth (NIP-42) - Challenge generation location = /auth { if ($request_method !~ ^(GET)$) { return 405; } fastcgi_pass fastcgi_backend; fastcgi_param QUERY_STRING $query_string; fastcgi_param REQUEST_METHOD $request_method; fastcgi_param CONTENT_TYPE $content_type; fastcgi_param CONTENT_LENGTH $content_length; fastcgi_param SCRIPT_NAME $fastcgi_script_name; fastcgi_param REQUEST_URI $request_uri; fastcgi_param DOCUMENT_URI $document_uri; fastcgi_param DOCUMENT_ROOT $document_root; fastcgi_param SERVER_PROTOCOL $server_protocol; fastcgi_param REQUEST_SCHEME $scheme; fastcgi_param HTTPS $https if_not_empty; fastcgi_param GATEWAY_INTERFACE CGI/1.1; fastcgi_param SERVER_SOFTWARE nginx/$nginx_version; fastcgi_param REMOTE_ADDR $remote_addr; fastcgi_param REMOTE_PORT $remote_port; fastcgi_param SERVER_ADDR $server_addr; fastcgi_param SERVER_PORT $server_port; fastcgi_param SERVER_NAME $server_name; fastcgi_param REDIRECT_STATUS 200; fastcgi_param SCRIPT_FILENAME $document_root/ginxsom.fcgi; fastcgi_param HTTP_AUTHORIZATION $http_authorization; } # Admin API endpoints (/api/*) location /api/ { if ($request_method !~ ^(GET|PUT|POST)$) { return 405; } fastcgi_pass fastcgi_backend; fastcgi_param QUERY_STRING $query_string; fastcgi_param REQUEST_METHOD $request_method; fastcgi_param CONTENT_TYPE $content_type; fastcgi_param CONTENT_LENGTH $content_length; fastcgi_param SCRIPT_NAME $fastcgi_script_name; fastcgi_param REQUEST_URI $request_uri; fastcgi_param DOCUMENT_URI $document_uri; fastcgi_param DOCUMENT_ROOT $document_root; fastcgi_param SERVER_PROTOCOL $server_protocol; fastcgi_param REQUEST_SCHEME $scheme; fastcgi_param HTTPS $https if_not_empty; fastcgi_param GATEWAY_INTERFACE CGI/1.1; fastcgi_param SERVER_SOFTWARE nginx/$nginx_version; fastcgi_param REMOTE_ADDR $remote_addr; fastcgi_param REMOTE_PORT $remote_port; fastcgi_param SERVER_ADDR $server_addr; fastcgi_param SERVER_PORT $server_port; fastcgi_param SERVER_NAME $server_name; fastcgi_param REDIRECT_STATUS 200; fastcgi_param SCRIPT_FILENAME $document_root/ginxsom.fcgi; fastcgi_param HTTP_AUTHORIZATION $http_authorization; } # 2. BLOB OPERATIONS (SHA256 patterns) # GET/HEAD/DELETE / (BUD-01) - Blob operations with optional file extensions location ~ "^/([a-f0-9]{64})(\.[a-zA-Z0-9]+)?$" { # Handle DELETE method via rewrite to avoid fastcgi_param in if block if ($request_method = DELETE) { rewrite ^/(.*)$ /fcgi-delete/$1 last; } # Route HEAD requests to FastCGI for metadata if ($request_method = HEAD) { rewrite ^/(.*)$ /fcgi-head/$1 last; } # Only allow GET for file serving at this point if ($request_method != GET) { return 405; } # GET requests - serve files directly with extension fallback try_files /$1.txt /$1.jpg /$1.jpeg /$1.png /$1.webp /$1.gif /$1.pdf /$1.mp4 /$1.mp3 /$1.md =404; # Cache headers for blob content add_header Cache-Control "public, max-age=31536000, immutable"; add_header Access-Control-Allow-Origin * always; add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, HEAD, OPTIONS, PATCH" always; add_header Access-Control-Allow-Headers "Authorization, Content-Type, Content-Length, Accept, Origin, User-Agent, DNT, Cache-Control, X-Mx-ReqToken, Keep-Alive, X-Requested-With, If-Modified-Since, *" always; add_header Access-Control-Max-Age 86400 always; } # Internal handler for DELETE operations location ~ "^/fcgi-delete/([a-f0-9]{64}).*$" { internal; fastcgi_pass fastcgi_backend; fastcgi_param QUERY_STRING $query_string; fastcgi_param REQUEST_METHOD DELETE; fastcgi_param CONTENT_TYPE $content_type; fastcgi_param CONTENT_LENGTH $content_length; fastcgi_param SCRIPT_NAME $fastcgi_script_name; fastcgi_param REQUEST_URI /$1; fastcgi_param DOCUMENT_URI /$1; fastcgi_param DOCUMENT_ROOT $document_root; fastcgi_param SERVER_PROTOCOL $server_protocol; fastcgi_param REQUEST_SCHEME $scheme; fastcgi_param HTTPS $https if_not_empty; fastcgi_param GATEWAY_INTERFACE CGI/1.1; fastcgi_param SERVER_SOFTWARE nginx/$nginx_version; fastcgi_param REMOTE_ADDR $remote_addr; fastcgi_param REMOTE_PORT $remote_port; fastcgi_param SERVER_ADDR $server_addr; fastcgi_param SERVER_PORT $server_port; fastcgi_param SERVER_NAME $server_name; fastcgi_param REDIRECT_STATUS 200; fastcgi_param SCRIPT_FILENAME $document_root/ginxsom.fcgi; fastcgi_param HTTP_AUTHORIZATION $http_authorization; } # FastCGI handler for HEAD requests location ~ "^/fcgi-head/([a-f0-9]{64}).*$" { internal; fastcgi_pass fastcgi_backend; fastcgi_param QUERY_STRING $query_string; fastcgi_param REQUEST_METHOD HEAD; fastcgi_param CONTENT_TYPE $content_type; fastcgi_param CONTENT_LENGTH $content_length; fastcgi_param SCRIPT_NAME $fastcgi_script_name; fastcgi_param REQUEST_URI /$1; fastcgi_param DOCUMENT_URI /$1; fastcgi_param DOCUMENT_ROOT $document_root; fastcgi_param SERVER_PROTOCOL $server_protocol; fastcgi_param REQUEST_SCHEME $scheme; fastcgi_param HTTPS $https if_not_empty; fastcgi_param GATEWAY_INTERFACE CGI/1.1; fastcgi_param SERVER_SOFTWARE nginx/$nginx_version; fastcgi_param REMOTE_ADDR $remote_addr; fastcgi_param REMOTE_PORT $remote_port; fastcgi_param SERVER_ADDR $server_addr; fastcgi_param SERVER_PORT $server_port; fastcgi_param SERVER_NAME $server_name; fastcgi_param REDIRECT_STATUS 200; fastcgi_param SCRIPT_FILENAME $document_root/ginxsom.fcgi; fastcgi_param HTTP_AUTHORIZATION $http_authorization; } # 3. UTILITY ENDPOINTS # Health check endpoint location /health { access_log off; return 200 "OK (HTTPS)\n"; add_header Content-Type text/plain; add_header Access-Control-Allow-Origin * always; add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, HEAD, OPTIONS, PATCH" always; add_header Access-Control-Allow-Headers "Authorization, Content-Type, Content-Length, Accept, Origin, User-Agent, DNT, Cache-Control, X-Mx-ReqToken, Keep-Alive, X-Requested-With, If-Modified-Since, *" always; add_header Access-Control-Max-Age 86400 always; } # List files endpoint for debugging location /debug/list { autoindex on; autoindex_format json; } # Root endpoint - Server info from FastCGI location = / { if ($request_method !~ ^(GET)$) { return 405; } fastcgi_pass fastcgi_backend; fastcgi_param QUERY_STRING $query_string; fastcgi_param REQUEST_METHOD $request_method; fastcgi_param CONTENT_TYPE $content_type; fastcgi_param CONTENT_LENGTH $content_length; fastcgi_param SCRIPT_NAME $fastcgi_script_name; fastcgi_param REQUEST_URI $request_uri; fastcgi_param DOCUMENT_URI $document_uri; fastcgi_param DOCUMENT_ROOT $document_root; fastcgi_param SERVER_PROTOCOL $server_protocol; fastcgi_param REQUEST_SCHEME $scheme; fastcgi_param HTTPS $https if_not_empty; fastcgi_param GATEWAY_INTERFACE CGI/1.1; fastcgi_param SERVER_SOFTWARE nginx/$nginx_version; fastcgi_param REMOTE_ADDR $remote_addr; fastcgi_param REMOTE_PORT $remote_port; fastcgi_param SERVER_ADDR $server_addr; fastcgi_param SERVER_PORT $server_port; fastcgi_param SERVER_NAME $server_name; fastcgi_param REDIRECT_STATUS 200; fastcgi_param SCRIPT_FILENAME $document_root/ginxsom.fcgi; fastcgi_param HTTP_AUTHORIZATION $http_authorization; } } }