Summary
(uv) extension iframes are hardcoded to http://127.0.0.1:7769/{package_name}/. This makes them unusable in any deployment where the user's browser isn't running on the same host as the container — i.e. essentially every cloud GPU deployment (RunPod, Vast.ai, Simplepod, etc.). The browser interprets 127.0.0.1 as the user's own machine and either fails ("connection refused") or hits whatever happens to be listening on the user's local 7769.
The same problem applies to GRADIO_TREE_PORT — it's a fixed port number, but cloud platforms typically assign random external ports per launch, so even mapping 7769 externally doesn't reliably give the browser the correct URL.
Reproduction
- Run TTS-WebUI on any cloud GPU host with port-mapping (e.g. external port 20005 → container 7770).
- Browse to
http://<external-host>:20005/.
- Install any
(uv) extension (e.g. OmniVoice).
- Click Start. The iframe attempts to load
http://127.0.0.1:7769/tts_webui_extension.omnivoice/.
- Browser errors out (
refused to connect if nothing is on local 7769).
Root cause
tts_webui/gradio_proxy_tree/main.py:
GRADIO_TREE_PORT = 7769
GRADIO_TREE_HOSTNAME = "127.0.0.1"
tts_webui/extensions_loader/setup_proxy_extension.py:
iframe = f'<iframe src="http://{GRADIO_TREE_HOSTNAME}:{GRADIO_TREE_PORT}/{package_name}/" style="width: 100%; height: 100vh;"></iframe>'
The iframe URL is rendered server-side using container-local values, but the iframe is loaded by the user's browser which has no way to reach 127.0.0.1 of the container.
Suggested fix
Make the iframe URL relative so the browser auto-uses the parent page's host/port:
iframe = f'<iframe src="/{package_name}/" style="width: 100%; height: 100vh;"></iframe>'
For the relative URL to work, the proxy tree and the main Gradio app must share a single port. Two options:
-
Front Gradio with the proxy tree on the user-facing port. Move main Gradio to an internal-only port (e.g. 7771), bind the proxy tree on the user-facing port (7770), and add a fallback route forwarding unmatched paths to the relocated Gradio:
GRADIO_TREE_PORT = 7770 # was 7769
def _setup():
gradio_proxy_tree.add_route("/main-app", 7771)
gradio_proxy_tree.add_route("", 7771) # fallback to main Gradio
gradio_proxy_tree.start_background()
And update Gradio's default server_port to 7771 in tts_webui/config/load_config.py.
-
Mount the proxy tree's _RouteDispatcher as ASGI middleware on Gradio's FastAPI app. Cleaner architecturally (single uvicorn, no extra port juggling), but requires hooking into Gradio's launch path.
Either way, the iframe URL becomes relative and the deployment becomes portable.
Workaround (sed-patch in Dockerfile, option 1)
Confirmed working on Simplepod with random external port assignment:
RUN sed -i 's|"server_port": 7770,|"server_port": 7771,|' \
tts_webui/config/load_config.py && \
sed -i \
-e 's|^GRADIO_TREE_PORT = 7769$|GRADIO_TREE_PORT = 7770|' \
-e 's|gradio_proxy_tree.add_route("/main-app", 7770)|gradio_proxy_tree.add_route("/main-app", 7771)\n gradio_proxy_tree.add_route("", 7771)|' \
tts_webui/gradio_proxy_tree/main.py && \
sed -i 's|http://{GRADIO_TREE_HOSTNAME}:{GRADIO_TREE_PORT}/|/|g' \
tts_webui/extensions_loader/setup_proxy_extension.py
Environment
- OS: Ubuntu 22.04 (Docker,
nvidia/cuda:12.8.0-devel-ubuntu22.04)
- Python: 3.10
- tts-webui: main
- Cloud platform: Simplepod (random external port mapping per
EXPOSEd container port)
Summary
(uv)extension iframes are hardcoded tohttp://127.0.0.1:7769/{package_name}/. This makes them unusable in any deployment where the user's browser isn't running on the same host as the container — i.e. essentially every cloud GPU deployment (RunPod, Vast.ai, Simplepod, etc.). The browser interprets127.0.0.1as the user's own machine and either fails ("connection refused") or hits whatever happens to be listening on the user's local 7769.The same problem applies to
GRADIO_TREE_PORT— it's a fixed port number, but cloud platforms typically assign random external ports per launch, so even mapping7769externally doesn't reliably give the browser the correct URL.Reproduction
http://<external-host>:20005/.(uv)extension (e.g. OmniVoice).http://127.0.0.1:7769/tts_webui_extension.omnivoice/.refused to connectif nothing is on local 7769).Root cause
tts_webui/gradio_proxy_tree/main.py:tts_webui/extensions_loader/setup_proxy_extension.py:The iframe URL is rendered server-side using container-local values, but the iframe is loaded by the user's browser which has no way to reach
127.0.0.1of the container.Suggested fix
Make the iframe URL relative so the browser auto-uses the parent page's host/port:
For the relative URL to work, the proxy tree and the main Gradio app must share a single port. Two options:
Front Gradio with the proxy tree on the user-facing port. Move main Gradio to an internal-only port (e.g. 7771), bind the proxy tree on the user-facing port (7770), and add a fallback route forwarding unmatched paths to the relocated Gradio:
And update Gradio's default
server_portto7771intts_webui/config/load_config.py.Mount the proxy tree's
_RouteDispatcheras ASGI middleware on Gradio's FastAPI app. Cleaner architecturally (single uvicorn, no extra port juggling), but requires hooking into Gradio's launch path.Either way, the iframe URL becomes relative and the deployment becomes portable.
Workaround (sed-patch in Dockerfile, option 1)
Confirmed working on Simplepod with random external port assignment:
Environment
nvidia/cuda:12.8.0-devel-ubuntu22.04)EXPOSEd container port)