# Custom log format to show which location matched log_format debug_log '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" "$http_user_agent" ' 'location="$location_name"'; server { listen 80; server_name localhost; # Allow large client request bodies for file uploads in commits client_max_body_size 100G; # Root directory for the built Vue.js application root /usr/share/nginx/html; index index.html; # Default location name set $location_name "unknown"; # Use custom log format for debugging access_log /var/log/nginx/access.log debug_log; # ================================================================= # API PROXY RULES # # These specific locations are evaluated BEFORE the general SPA rule. # The order of these proxy rules matters - most specific first. # ================================================================= # 1. API endpoints (all routes under /api/) # Covers: /api/auth/*, /api/repos/*, /api/models/*, /api/datasets/*, # /api/spaces/*, /api/users/*, /api/organizations/*, /api/whoami-v2, etc. location /api/ { set $location_name "api"; proxy_pass http://hub-api:48888; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } # 2. Admin API endpoints (mounted at /admin/api/) # Covers: /admin/api/users/*, /admin/api/quota/*, /admin/api/stats location /admin/api/ { set $location_name "admin_api"; proxy_pass http://hub-api:48888; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } # 3. Organization API endpoints (mounted at /org/) # Covers: /org/create, /org/{name}, /org/{name}/members, /org/users/{username}/orgs location /org/ { set $location_name "org_api"; proxy_pass http://hub-api:48888; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } # 4. Git HTTP Smart Protocol endpoints # Covers: /{namespace}/{name}.git/info/refs, /{namespace}/{name}.git/git-upload-pack, etc. # This enables native Git clone/push operations # Pattern matches: /anything/anything.git/endpoint (hyphens, numbers, letters all OK) location ~ \.git/(info/refs|git-upload-pack|git-receive-pack|HEAD) { set $location_name "git_http"; proxy_pass http://hub-api:48888; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; # Disable buffering for streaming Git protocol proxy_buffering off; proxy_request_buffering off; # Pass through authentication proxy_set_header Authorization $http_authorization; proxy_pass_header Authorization; # Git protocol specific headers proxy_set_header Content-Type $content_type; # Cloudflare compatibility - prevent caching and compression # Add these headers to tell Cloudflare not to cache Git protocol responses add_header Cache-Control "no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0" always; add_header X-Content-Type-Options "nosniff" always; add_header X-Accel-Buffering "no" always; # Ensure proper content type is preserved proxy_hide_header X-Content-Type-Options; proxy_hide_header Cache-Control; } # 5. Git LFS endpoints # Covers: /{type}s/{namespace}/{name}.git/info/lfs/* and /{namespace}/{name}.git/info/lfs/* location ~ \.git/info/lfs/ { set $location_name "git_lfs"; proxy_pass http://hub-api:48888; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; # Important for large file uploads proxy_request_buffering off; client_body_buffer_size 128k; } # 6. Public file resolution routes (no /api prefix) # These are public-facing download endpoints # Pattern: /{type}s/{namespace}/{name}/resolve/{revision}/{path} location ~ ^/(models|datasets|spaces)/[^/]+/[^/]+/resolve/ { set $location_name "public_resolve_typed"; proxy_pass http://hub-api:48888; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } # 7. Legacy public file resolution route (no /api prefix, no type prefix) # Pattern: /{namespace}/{name}/resolve/{revision}/{path} # Must come AFTER the specific routes to avoid catching frontend routes location ~ ^/[^/]+/[^/]+/resolve/ { set $location_name "public_resolve_legacy"; proxy_pass http://hub-api:48888; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } # ================================================================= # ADMIN FRONTEND SPA # # Serve admin portal at /admin (before main SPA fallback) # ================================================================= location /admin { set $location_name "admin_spa"; alias /usr/share/nginx/html-admin/; try_files $uri $uri/ /admin/index.html; } # ================================================================= # MAIN FRONTEND SINGLE PAGE APP (SPA) # # This is the final fallback. If no API rule above matched, # Nginx assumes it's a frontend route and serves the main SPA. # ================================================================= location / { set $location_name "main_spa"; try_files $uri $uri/ /index.html; } }