proxy: fix double-prefix when outer proxy mounts a tool at the same name

The 0.1.24 nesting blindly appended the bundled sub-app name to the incoming
X-Forwarded-Prefix, which double-counted it when the outer proxy mounts the app
under the SAME name and proxies to our /<app>/ path (topology B): outer sends
"/township" -> container emitted "/township/township", so every township
fetch() 404'd ("Not found" -> JSON parse error in the UI).

Per-app maps now only append our name when the incoming prefix doesn't already
end in it, so both topologies work: outer-wraps-everything ("/ai" -> "/ai/town
ship") and outer-mounts-same-name ("/township" -> "/township"). Direct (no outer
proxy) still yields "/township".
Co-Authored-By: 's avatarClaude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RdMufYvtTbtGDWsiZVoXce
parent f177d01d
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
# Canonical product version for CoderAI — single source of truth. Both the API # Canonical product version for CoderAI — single source of truth. Both the API
# metadata and the admin web UI read from here. # metadata and the admin web UI read from here.
__version__ = "0.1.24" __version__ = "0.1.25"
# Configure the CUDA caching allocator BEFORE torch is imported anywhere. # Configure the CUDA caching allocator BEFORE torch is imported anywhere.
# expandable_segments lets the allocator return freed pages to the driver even # expandable_segments lets the allocator return freed pages to the driver even
......
...@@ -58,13 +58,35 @@ http { ...@@ -58,13 +58,35 @@ http {
default $host; default $host;
"~." $http_x_forwarded_host; "~." $http_x_forwarded_host;
} }
# Incoming sub-path prefix from the outer proxy (trailing slash stripped), # Incoming sub-path prefix from the outer proxy (trailing slash stripped).
# so we can NEST our own mount prefixes under it (e.g. outer "/ai" + our # Empty when there is no outer prefix.
# "/township" -> "/ai/township"). Empty when there is no outer prefix.
map $http_x_forwarded_prefix $fwd_prefix { map $http_x_forwarded_prefix $fwd_prefix {
"~^(?<p>.*?)/?$" $p; "~^(?<p>.*?)/?$" $p;
} }
# Per-app public prefix. Two valid outer-proxy topologies must both work:
# (A) outer wraps the WHOLE container under one prefix and proxies to our
# root: outer sends e.g. "/ai" -> the app's public prefix is
# "/ai/<app>", so we APPEND.
# (B) outer mounts the app at the SAME name and proxies to our "/<app>/"
# path: outer sends e.g. "/township" (or "/ai/township") that ALREADY
# ends in our app name -> use it AS-IS, never append (appending would
# emit "/township/township" and every fetch() would 404).
# Rule: if the incoming prefix already ends in "/<app>", pass it through;
# otherwise append. Empty incoming -> just "/<app>" (direct, no outer proxy).
map $fwd_prefix $xfp_editor {
"~/editor$" $fwd_prefix;
default $fwd_prefix/editor;
}
map $fwd_prefix $xfp_videogen {
"~/videogen$" $fwd_prefix;
default $fwd_prefix/videogen;
}
map $fwd_prefix $xfp_township {
"~/township$" $fwd_prefix;
default $fwd_prefix/township;
}
# Shared proxy headers. CoderAI builds public URLs from these # Shared proxy headers. CoderAI builds public URLs from these
# (codai/api/urlutils.py); the tools honour X-Forwarded-Prefix for sub-paths. # (codai/api/urlutils.py); the tools honour X-Forwarded-Prefix for sub-paths.
proxy_http_version 1.1; proxy_http_version 1.1;
...@@ -73,9 +95,9 @@ http { ...@@ -73,9 +95,9 @@ http {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $fwd_proto; proxy_set_header X-Forwarded-Proto $fwd_proto;
proxy_set_header X-Forwarded-Host $fwd_host; proxy_set_header X-Forwarded-Host $fwd_host;
# Pass the outer prefix through unchanged at the root; sub-apps override this # Pass the outer prefix through unchanged at the root (trailing slash
# with their own nested value below. # stripped); sub-apps override this with their own value below.
proxy_set_header X-Forwarded-Prefix $http_x_forwarded_prefix; proxy_set_header X-Forwarded-Prefix $fwd_prefix;
upstream coderai { server 127.0.0.1:18776; } upstream coderai { server 127.0.0.1:18776; }
upstream editor { server 127.0.0.1:8420; } upstream editor { server 127.0.0.1:8420; }
...@@ -90,7 +112,7 @@ http { ...@@ -90,7 +112,7 @@ http {
# --- Video editor: https://host:8776/editor/ ------------------------- # --- Video editor: https://host:8776/editor/ -------------------------
location /editor/ { location /editor/ {
proxy_pass http://editor/; # trailing slash strips the prefix proxy_pass http://editor/; # trailing slash strips the prefix
proxy_set_header X-Forwarded-Prefix "${fwd_prefix}/editor"; # nest under outer prefix proxy_set_header X-Forwarded-Prefix $xfp_editor; # smart nest (see map above)
proxy_request_buffering off; # stream large uploads through proxy_request_buffering off; # stream large uploads through
proxy_buffering off; # SSE progress proxy_buffering off; # SSE progress
} }
...@@ -98,7 +120,7 @@ http { ...@@ -98,7 +120,7 @@ http {
# --- Videogen studio: https://host:8776/videogen/ ------------------- # --- Videogen studio: https://host:8776/videogen/ -------------------
location /videogen/ { location /videogen/ {
proxy_pass http://videogen/; proxy_pass http://videogen/;
proxy_set_header X-Forwarded-Prefix "${fwd_prefix}/videogen"; # nest under outer prefix proxy_set_header X-Forwarded-Prefix $xfp_videogen; # smart nest (see map above)
proxy_request_buffering off; proxy_request_buffering off;
proxy_buffering off; proxy_buffering off;
} }
...@@ -106,7 +128,7 @@ http { ...@@ -106,7 +128,7 @@ http {
# --- Township fighters: https://host:8776/township/ ---------------- # --- Township fighters: https://host:8776/township/ ----------------
location /township/ { location /township/ {
proxy_pass http://township/; proxy_pass http://township/;
proxy_set_header X-Forwarded-Prefix "${fwd_prefix}/township"; # nest under outer prefix proxy_set_header X-Forwarded-Prefix $xfp_township; # smart nest (see map above)
proxy_request_buffering off; proxy_request_buffering off;
proxy_buffering off; proxy_buffering off;
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment