Files
indee-demo/nginx.conf
Dorian faa419fc28 fix: serve service worker with no-cache headers via exact-match location
The sw.js and workbox-*.js files were being caught by the immutable
static asset regex (expires 1y), causing stale service workers and
potential 502 errors during re-registration. Use location = /sw.js
(exact match, highest Nginx priority) and a regex for workbox files
that appears before the asset cache block.

Also removes the dead duplicate location blocks at the bottom of
the config that were never reached due to regex priority.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-13 22:16:13 +00:00

155 lines
5.6 KiB
Nginx Configuration File

server {
listen 7777;
server_name _;
root /usr/share/nginx/html;
index index.html;
# Gzip compression
gzip on;
gzip_vary on;
gzip_min_length 1024;
gzip_types text/plain text/css text/xml text/javascript application/javascript application/xml+rss application/json application/vnd.apple.mpegurl video/MP2T;
# Security headers
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
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";
add_header Content-Type application/manifest+json;
}
# ── Service Worker — must be exact-match to avoid the immutable
# caching regex below. Browsers require fresh SW scripts.
location = /sw.js {
add_header Cache-Control "no-cache, no-store, must-revalidate";
expires off;
access_log off;
}
location ~* ^/workbox-.*\.js$ {
add_header Cache-Control "no-cache, no-store, must-revalidate";
expires off;
access_log off;
}
# Static assets — long-lived immutable cache
location ~* \.(?:js|css|woff2|woff|ttf|otf|eot|svg|png|jpg|jpeg|gif|ico)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
# ── Backend API proxy ──────────────────────────────────────
location /api/ {
resolver 127.0.0.11 valid=30s ipv6=off;
set $api_upstream http://api:4000;
rewrite ^/api(.*) $1 break;
proxy_pass $api_upstream;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# Trust the outer reverse proxy's X-Forwarded-Proto when present,
# otherwise fall back to the connection scheme.
proxy_set_header X-Forwarded-Proto $http_x_forwarded_proto;
# Preserve the original /api prefix so NIP-98 URL verification
# can reconstruct the URL the client actually signed.
proxy_set_header X-Forwarded-Prefix /api;
proxy_read_timeout 300s;
proxy_send_timeout 300s;
# Handle large video uploads (up to 5GB)
client_max_body_size 5g;
}
# ── MinIO storage proxy (public bucket) ────────────────────
# Serves poster images, HLS segments, etc. with caching
# ^~ ensures this prefix takes priority over the static-asset
# regex that would otherwise intercept .jpg/.png requests.
location ^~ /storage/ {
resolver 127.0.0.11 valid=30s ipv6=off;
set $minio_upstream http://minio:9000;
rewrite ^/storage/(.*) /indeedhub-public/$1 break;
proxy_pass $minio_upstream;
proxy_http_version 1.1;
proxy_set_header Host minio:9000;
# Cache static assets aggressively
proxy_cache_valid 200 1d;
proxy_cache_valid 404 1m;
expires 1d;
add_header Cache-Control "public, max-age=86400";
add_header X-Cache-Status $upstream_cache_status;
}
# ── MinIO storage proxy (private bucket -- for HLS key delivery) ─
location ^~ /storage-private/ {
resolver 127.0.0.11 valid=30s ipv6=off;
set $minio_upstream http://minio:9000;
rewrite ^/storage-private/(.*) /indeedhub-private/$1 break;
proxy_pass $minio_upstream;
proxy_http_version 1.1;
proxy_set_header Host minio:9000;
# Do NOT cache private content
add_header Cache-Control "no-store";
}
# ── WebSocket proxy to Nostr relay (Docker service) ────────
location /relay {
resolver 127.0.0.11 valid=30s ipv6=off;
set $relay_upstream http://relay:8080;
rewrite ^/relay(.*) /$1 break;
proxy_pass $relay_upstream;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_read_timeout 86400s;
proxy_send_timeout 86400s;
}
# ── Vue Router - SPA fallback ──────────────────────────────
location / {
try_files $uri $uri/ /index.html;
}
# Health check endpoint
location /health {
access_log off;
return 200 "healthy\n";
add_header Content-Type text/plain;
}
}