worker_processes auto; pid /tmp/nginx.pid; error_log /dev/stderr warn; events { worker_connections 256; } http { include /etc/nginx/mime.types; types { application/javascript mjs; } default_type application/octet-stream; access_log off; server_tokens off; client_body_temp_path /tmp/client_temp; proxy_temp_path /tmp/proxy_temp; fastcgi_temp_path /tmp/fastcgi_temp; uwsgi_temp_path /tmp/uwsgi_temp; scgi_temp_path /tmp/scgi_temp; server { listen 8080; root /usr/share/nginx/html; absolute_redirect off; add_header X-Content-Type-Options nosniff always; add_header Referrer-Policy no-referrer always; add_header Cache-Control "no-cache, no-store, must-revalidate" always; # Delegation by the parent is additionally required for framed capture. add_header Permissions-Policy "camera=(self), microphone=(self), display-capture=(self), picture-in-picture=(self), geolocation=(), payment=(), usb=(), serial=()" always; # The broker is on the same node at a different port. It validates its # parent independently. Keep script execution same-origin, without eval. add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'wasm-unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob: https:; media-src 'self' blob: mediastream:; connect-src 'self' wss: https:; worker-src 'self'; frame-src 'self' http: https:; font-src 'self'; object-src 'none'; base-uri 'none'; form-action 'none'" always; location = / { return 302 /j/; } location = /j { return 308 /j/; } location = /healthz { try_files /j/index.html =503; } location = /nostr-provider.js { alias /bridge/nostr-provider.js; } location /j/ { try_files $uri $uri/ =404; } # No pretend success for missing TURN, meeting-code or upload services. location / { return 404; } } }