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 (NEW — required) proxy_set_header X-Ingress-Path %%ingress_entry%%; # Prevent timeouts proxy_read_timeout 86400; proxy_send_timeout 86400; # sub_filter setup proxy_set_header Accept-Encoding ""; sub_filter_once off; sub_filter_types *; # HTML attribute rewrites sub_filter href=\"/ href=\"%%ingress_entry%%/; sub_filter src=\"/ src=\"%%ingress_entry%%/; sub_filter src=\"'/ src=\"'%%ingress_entry%%/; sub_filter action=\"/ action=\"%%ingress_entry%%/; # JavaScript string rewrites (needed for Vite dynamic imports) sub_filter EventSource('/ EventSource('%%ingress_entry%%/; sub_filter fetch('/ fetch('%%ingress_entry%%/; # Backtick template literal rewrites 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; # Streaming/EventSource fix sub_filter window.location.origin} window.location.origin}%%ingress_entry%%; } }