server { listen %%interface%%:%%port%% default_server; include /etc/nginx/includes/server_params.conf; include /etc/nginx/includes/proxy_params.conf; location / { proxy_pass http://localhost:8080/; rewrite ^%%ingress_entry%%/?(.*)$ /$1 break; # Disable buffering (required for SSE and sub_filter) proxy_buffering off; proxy_request_buffering off; proxy_cache off; # WebSocket support proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $connection_upgrade; 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; # Tell BirdNET-Go its proxy prefix. Upstream honours X-Ingress-Path # in internal/api/server.go and rewrites HTML href/src/action # attributes itself, so we no longer duplicate that work here. proxy_set_header X-Ingress-Path %%ingress_entry%%; # Prevent timeouts proxy_read_timeout 86400; proxy_send_timeout 86400; # sub_filter setup: keep gzip off and the type filter wide so JS gets # touched too (the upstream HTML rewriter does not look inside JS). proxy_set_header Accept-Encoding ""; sub_filter_once off; sub_filter_types *; # JS string-literal rewrites — paths embedded in JS code are not # touched by upstream's HTML rewriter, so we patch them here. sub_filter EventSource('/ EventSource('%%ingress_entry%%/; sub_filter fetch('/ fetch('%%ingress_entry%%/; sub_filter `/api/v `%%ingress_entry%%/api/v; sub_filter "'/api/v" "'%%ingress_entry%%/api/v"; sub_filter \"/api/v \"%%ingress_entry%%/api/v; sub_filter `/u `%%ingress_entry%%/u; sub_filter "'/u" "'%%ingress_entry%%/u"; sub_filter \"/u \"%%ingress_entry%%/u; sub_filter `/asset `%%ingress_entry%%/asset; sub_filter "'/asset" "'%%ingress_entry%%/asset"; sub_filter \"/asset \"%%ingress_entry%%/asset; sub_filter window.location.origin} window.location.origin}%%ingress_entry%%; } }