From 3e4279e2526cd0348a6ef196f339149fdf522ef2 Mon Sep 17 00:00:00 2001 From: Dorian Date: Fri, 13 Feb 2026 20:36:03 +0000 Subject: [PATCH] Fix 405 on thumbnail uploads: move MinIO proxy above static asset regex MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Nginx regex locations are evaluated in order — the static asset caching rule (.jpg, .png, etc.) was matching image upload URLs before the MinIO bucket proxy could handle them, causing PUT requests to return 405. Moved the /indeedhub-*/ proxy location to the top of the regex block. Co-authored-by: Cursor --- docker-compose.yml | 2 +- nginx.conf | 46 +++++++++++++++++++++++----------------------- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 7505098..f912b9e 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -20,7 +20,7 @@ services: context: . dockerfile: Dockerfile args: - CACHEBUST: "9" + CACHEBUST: "10" VITE_USE_MOCK_DATA: "false" VITE_CONTENT_ORIGIN: ${FRONTEND_URL} VITE_INDEEHUB_API_URL: /api diff --git a/nginx.conf b/nginx.conf index 604a245..a3e4f6c 100644 --- a/nginx.conf +++ b/nginx.conf @@ -16,6 +16,29 @@ server { add_header X-XSS-Protection "1; mode=block" always; add_header Referrer-Policy "no-referrer-when-downgrade" always; + # ── MinIO direct proxy (for presigned URL uploads/downloads) ── + # MUST appear before the static-asset regex locations below, + # otherwise image uploads (.jpg, .png, etc.) match the asset + # caching rule first and return 405 on PUT. + location ~ ^/(indeedhub-private|indeedhub-public)/ { + resolver 127.0.0.11 valid=30s ipv6=off; + set $minio_upstream http://minio:9000; + + proxy_pass $minio_upstream; + proxy_http_version 1.1; + # Pass the original Host so MinIO's signature verification matches + # the host the presigned URL was generated for. + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + + # Allow large file uploads (up to 5GB per chunk) + client_max_body_size 5g; + + # No caching for upload responses + add_header Cache-Control "no-store"; + } + # PWA Support - proper MIME types location ~* \.(?:manifest|webmanifest|json)$ { add_header Cache-Control "public, max-age=3600"; @@ -84,29 +107,6 @@ server { add_header Cache-Control "no-store"; } - # ── MinIO direct proxy (for presigned URL uploads/downloads) ── - # The backend generates presigned URLs pointing to the public domain. - # This location proxies those requests to MinIO WITHOUT rewriting the - # path, so the S3v4 signature (which includes the path) stays valid. - location ~ ^/(indeedhub-private|indeedhub-public)/ { - resolver 127.0.0.11 valid=30s ipv6=off; - set $minio_upstream http://minio:9000; - - proxy_pass $minio_upstream; - proxy_http_version 1.1; - # Pass the original Host so MinIO's signature verification matches - # the host the presigned URL was generated for. - proxy_set_header Host $host; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - - # Allow large file uploads (up to 5GB per chunk) - client_max_body_size 5g; - - # No caching for upload responses - add_header Cache-Control "no-store"; - } - # ── WebSocket proxy to Nostr relay (Docker service) ──────── location /relay { resolver 127.0.0.11 valid=30s ipv6=off;