From 4af38a9ddcd67a8b55bc852fd137fc354d750d40 Mon Sep 17 00:00:00 2001 From: Daniel Cox Date: Wed, 12 Aug 2026 10:05:53 +0930 Subject: [PATCH] fix: replace FORWARDED_ALLOW_IPS with nginx map, add .dockerignore HTTPS proxy handling moved entirely to nginx (map $http_x_forwarded_proto). - .dockerignore to exclude models/data/lora/output from build context - nginx: manifest.json returns proper JSON for PWA, favicon returns 204 - docker-compose: drop version key, remove FORWARDED_ALLOW_IPS env var - README: update HTTPS troubleshooting (nginx map handles it now) --- .dockerignore | 24 ++++++++++++++++++++++++ docker/README.md | 4 ++-- docker/docker-compose.yml | 8 +------- docker/nginx.conf | 23 ++++++++++++++++++++++- lora_ft_webui.py | 2 -- 5 files changed, 49 insertions(+), 12 deletions(-) create mode 100644 .dockerignore diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..b9f323e --- /dev/null +++ b/.dockerignore @@ -0,0 +1,24 @@ +# Model weights (mounted at runtime via volumes) +models/ +data/ +lora/ +output/ + +# Git history +.git/ + +# Python cache +__pycache__/ +*.pyc +*.pyo +*.egg-info/ +.venv/ + +# Docker config (not needed inside image) +docker/docker-compose.yml +docker/nginx.conf +docker/README.md + +# IDE / OS +.DS_Store +.vscode/ diff --git a/docker/README.md b/docker/README.md index 40570b3..b7bbd0e 100644 --- a/docker/README.md +++ b/docker/README.md @@ -121,7 +121,7 @@ docker run --gpus all -p 7860:7860 \ |----------|---------|-------------| | `GRADIO_SERVER_PORT` | `7860` | Port for the WebUI server | | `GRADIO_ROOT_PATH` | `""` | URL prefix when behind a reverse proxy (e.g., `/webui`) | -| `FORWARDED_ALLOW_IPS` | `*` | IPs allowed to set `X-Forwarded-Proto`. Set to `*` when behind a Docker reverse proxy so Gradio generates `https://` file URLs. | +| `VOXCPM_LANG` | `zh` | Default UI language (`zh` or `en`) | ## Reverse Proxy @@ -154,4 +154,4 @@ docker compose -f docker/docker-compose.yml logs -f training-webui - **WebUI not accessible**: Check that port 80 (nginx) or 7860 (direct) isn't blocked by a firewall. - **WebSocket errors behind proxy**: Ensure your proxy forwards `Upgrade` and `Connection` headers (the included nginx.conf handles this). - **Health check failing**: Ensure nginx is running — `curl http://localhost/` should return `OK`. -- **Mixed-content / audio not playing over HTTPS**: Gradio generates `http://` file URLs because uvicorn doesn't trust the `X-Forwarded-Proto` header from the Docker bridge network. The compose file sets `FORWARDED_ALLOW_IPS=*` to fix this. If you run without compose, pass `-e FORWARDED_ALLOW_IPS=*` to `docker run`. +- **Mixed-content / audio not playing over HTTPS**: The nginx config uses `map $http_x_forwarded_proto` to pass the correct protocol through to Gradio. This ensures `https://` file URLs are generated when accessed via HTTPS through a load balancer. diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index 8fea42d..5eb013a 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -1,5 +1,3 @@ -version: "3.8" - services: training-webui: build: @@ -32,11 +30,7 @@ services: environment: - GRADIO_SERVER_PORT=7860 - GRADIO_ROOT_PATH=/webui # Matches nginx location block - # Tell uvicorn to trust X-Forwarded-Proto from any IP (nginx in Docker - # connects from 172.x.x.x, not 127.0.0.1). Without this, Gradio - # generates http:// file URLs even when accessed over HTTPS, causing - # mixed-content errors that block audio playback in the browser. - - FORWARDED_ALLOW_IPS=* + # - VOXCPM_LANG=en # Uncomment for English UI (default: zh) restart: unless-stopped nginx: diff --git a/docker/nginx.conf b/docker/nginx.conf index 5e5ea01..33fedd1 100644 --- a/docker/nginx.conf +++ b/docker/nginx.conf @@ -1,19 +1,40 @@ +# Preserve X-Forwarded-Proto from upstream load balancer (e.g. AWS ALB). +# If ALB already set it to "https", pass that through instead of $scheme +# (which is "http" since ALB→nginx is unencrypted). Falls back to $scheme +# when accessed directly (no upstream proxy). +map $http_x_forwarded_proto $forwarded_proto { + default $http_x_forwarded_proto; + "" $scheme; +} + server { listen 80; server_name _; + absolute_redirect off; + # Health check for load balancers (AWS ALB, etc.) location = / { return 200 'OK\n'; add_header Content-Type text/plain; } + location = /manifest.json { + return 200 '{"name":"VoxCPM Training","short_name":"VoxCPM","start_url":"/webui/"}'; + default_type application/json; + } + + location = /favicon.ico { + return 204; + access_log off; + } + location /webui/ { proxy_pass http://training-webui:7860/; 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_set_header X-Forwarded-Proto $forwarded_proto; # WebSocket support (required for Gradio) proxy_http_version 1.1; diff --git a/lora_ft_webui.py b/lora_ft_webui.py index 47a4079..69f272a 100644 --- a/lora_ft_webui.py +++ b/lora_ft_webui.py @@ -1323,9 +1323,7 @@ with gr.Blocks(title="VoxCPM LoRA WebUI", theme=gr.themes.Soft(), css=custom_css ) if __name__ == "__main__": - # Ensure lora directory exists os.makedirs("lora", exist_ok=True) - port = int(os.environ.get("GRADIO_SERVER_PORT", "7860")) root_path = os.environ.get("GRADIO_ROOT_PATH", "")