diff --git a/deploy/ecosystem/nginx.conf b/deploy/ecosystem/nginx.conf index 5f8b685..41a7dbc 100644 --- a/deploy/ecosystem/nginx.conf +++ b/deploy/ecosystem/nginx.conf @@ -31,49 +31,24 @@ # read the note at the top of that file first. # # `nginx -t` catches the second and not the first. Run it anyway, every time. - -# maven. → mavweb (docker-compose.yml publishes it on 127.0.0.1:9201). -# Same bind + ACL as the siblings, and for a stronger reason: mavweb serves -# POST /tools, which defines argv that internal/tool EXECUTES, plus POST -# /routines, /api/revert and /api/chat (Vikunja #317). Without -# -webauthn-origin/-webauthn-rpid mavweb has no auth of its own, so this block -# is the auth. If you add TLS and a basic-auth/oauth2-proxy layer, keep the -# allow/deny anyway — belt and braces on an RCE surface. # -# WebSocket upgrade matters here: /ws carries push-to-talk audio, so the -# Upgrade/Connection headers below are required, not decoration. They reference -# $connection_upgrade, which this file does NOT define — see -# nginx-upgrade-map.conf and point 2 above. +# BLOCK ORDER IS LOAD-BEARING. nginx serves the first block for a given listen +# address when no server_name matches, so whichever block comes first here +# answers requests with an unknown or absent Host header. That must not be +# mavweb: it is the one surface in this file that can define and run argv. The +# nexus block is marked default_server so the choice is explicit rather than a +# consequence of file order, and the maven block sits last as a second guard. +# If you add a block, do not put it above nexus. If another site file already +# claims default_server on 10.42.0.1:80 or 192.168.1.104:80, nginx refuses to +# start with "a duplicate default server" — drop the two keywords here and rely +# on the block order instead. +# +# Every server_name below is a literal for kvmx.ru even though the comments +# write maven.. This file reads like a template and is not one. server { - listen 10.42.0.1:80; - listen 192.168.1.104:80; - server_name maven.kvmx.ru; - - allow 10.42.0.0/24; - allow 192.168.1.0/24; - deny all; - - # push-to-talk uploads raw PCM; the default 1m is enough for a short - # utterance but not for a long one. - client_max_body_size 32m; - - location / { - proxy_pass http://127.0.0.1:9201; - 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; - proxy_read_timeout 300s; # an LLM turn can take minutes on the iGPU - } -} - -server { - listen 10.42.0.1:80; - listen 192.168.1.104:80; + listen 10.42.0.1:80 default_server; + listen 192.168.1.104:80 default_server; server_name nexus.kvmx.ru; allow 10.42.0.0/24; @@ -124,3 +99,47 @@ server { proxy_set_header X-Forwarded-Proto $scheme; } } + +# maven. → mavweb (docker-compose.yml publishes it on 127.0.0.1:9201). +# Same bind + ACL as the siblings, and for a stronger reason: mavweb serves +# POST /tools, which defines argv that internal/tool EXECUTES, plus POST +# /routines, /api/revert, /api/chat, /api/ptt and /ws (Vikunja #317). Without +# -webauthn-origin/-webauthn-rpid mavweb has no auth of its own, so this block +# is the auth. If you add TLS and a basic-auth/oauth2-proxy layer, keep the +# allow/deny anyway — belt and braces on an RCE surface. +# +# WebSocket upgrade matters here: /ws carries push-to-talk audio, so the +# Upgrade/Connection headers below are required, not decoration. They reference +# $connection_upgrade, which this file does NOT define — see +# nginx-upgrade-map.conf and point 2 above. + +server { + listen 10.42.0.1:80; + listen 192.168.1.104:80; + server_name maven.kvmx.ru; + + allow 10.42.0.0/24; + allow 192.168.1.0/24; + deny all; + + # push-to-talk uploads raw PCM; the default 1m is enough for a short + # utterance but not for a long one. + client_max_body_size 32m; + # A 32m upload over a slow link outlives the 60s default on the two body + # timeouts, and nginx cuts it at exactly 60s with a 408 or a 504 that looks + # like the turn failed. Raise them with the size, not just proxy_read_timeout. + client_body_timeout 300s; + + location / { + proxy_pass http://127.0.0.1:9201; + 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; + proxy_send_timeout 300s; # pushing the PCM upstream, same reason + proxy_read_timeout 300s; # an LLM turn can take minutes on the iGPU + } +}