Port Binding Issue – Uvicorn app running but Space shows 404 (Docker / FastAPI)

With just the minimal fix below, something somewhat GUI-like appeared.


Fix: set routing in the Space’s README and give / something to serve. Labels are ignored. No proxy “reattach” is required.

What’s happening

  • Docker Spaces read the runtime port and the initial URL from the README front-matter: sdk: docker, app_port, and optional base_path. They do not read LABEL huggingface.co/*. Default port is 7860. The Space loads / unless base_path is set. (Hugging Face)
  • FastAPI serves docs at /docs by default. If your app only exposes /api/v1/*, a request to / returns 404. The Space shows that 404. (FastAPI)

Minimal, reliable fix

A. Update README front-matter so the proxy targets 7860 and the iframe opens /docs instead of /:

---
sdk: docker
app_port: 7860
base_path: /docs
---

This is the supported configuration for Docker Spaces; base_path defines the initial URL the Space renders. Example Spaces set app_port and base_path the same way. (Hugging Face)

B. Optional FastAPI root handler if you prefer not to use base_path:

# FastAPI's Swagger UI lives at /docs by default
# docs: https://fastapi.tiangolo.com/tutorial/metadata/
from fastapi import FastAPI
from fastapi.responses import RedirectResponse

app = FastAPI()
@app.get("/", include_in_schema=False)
def root():
    return RedirectResponse("/docs")

This makes GET / return 302→/docs, eliminating the 404. (FastAPI)

Notes on your Dockerfile

  • Keep EXPOSE 7860.

  • Keep your uvicorn command. To be robust behind proxies you can add:

    --proxy-headers --forwarded-allow-ips="*"
    

    These flags make Uvicorn honor forwarded headers through the Space’s proxy. (Uvicorn)

  • Ignore the labels. Spaces routing is driven by the README (app_port, base_path) and your container’s CMD/ENTRYPOINT. (Hugging Face)

Verification checklist

  • Root now loads docs: GET https://huggingface.co/proxy/petsage-petsage-brain-v30.hf.space/ → Swagger UI if you set base_path or added the redirect. FastAPI serves /docs by default. (FastAPI)
  • Health endpoint OK: GET /api/v1/health returns JSON 200.
  • Logs still show Uvicorn on 0.0.0.0:7860.
  • No change needed to Hugging Face proxy. The proxy already connects to app_port (default 7860). (Hugging Face)

Common pitfalls

  • Missing or wrong README front-matter. Docker Spaces require the YAML block; app_port is used only when sdk: docker is set there. Community threads and commits confirm that setting app_port in README fixes routing. (Hugging Face Forums)
  • Expecting Docker LABEL huggingface.co/port or huggingface.co/entrypoint to control routing. They don’t. Use README and your container’s CMD. (Hugging Face)

Quick template you can drop in

README.md

---
title: PetSage Brain v30
sdk: docker
app_port: 7860
base_path: /docs
---

Optional main.py addition

from fastapi.responses import RedirectResponse
@app.get("/", include_in_schema=False)
def root():
    return RedirectResponse("/docs")

Extra references

  • Docker Spaces guide and setup. (Hugging Face)
  • Spaces configuration reference for app_port and base_path. (Hugging Face)
  • FastAPI docs and OpenAPI endpoints (/docs, /openapi.json). (FastAPI)
  • Uvicorn proxy header handling. (Uvicorn)

Outcome: declare port and initial path in README or add a / route. Labels are ignored. After this, the Space root stops 404ing and your API is reachable at the public URL.