Configuration behind nginx reverse proxy with root_path

I’m trying to deploy a Starlette web app under a prefix with nginx, but cannot make the router to resolve the path correctly for me.

Minimal setup:

# nginx location block.
location /prefix {
    proxy_pass http://127.0.0.1:8000;
}
from starlette.applications import Starlette
from starlette.responses import Response

app = Starlette()

@app.route("/")
async def root(request):
    return Response("root")
$ uvicorn --root-path /prefix app:app

But http://localhost/prefix returns 404 for me:

INFO:     Started server process [2224]
INFO:     Waiting for application startup.
INFO:     Application startup complete.
INFO:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
INFO:     127.0.0.1:44154 - "GET /prefix/prefix HTTP/1.0" 404 Not Found

Am I doing something wrong? The log shows Starlette prepending the prefix to the path, but I’d expect it to strip the prefix instead. With WSGI I know I’d pass the SCRIPT_NAME header from nginx to the runner, but I’m not sure what the equivalent is in ASGI.

I think I got it now. root_path does not actively strip the request URL when it comes in (unlike SCRIPT_NAME in WSGI), so I need to do that myself in nginx:

location ~ /prefix/(.*) {
    proxy_pass http://127.0.0.1:8000/$1;
}

The root_path value is prepended to all routing-related stuff, so

  • nginx gets http://localhost/prefix/
  • nginx passes / to the ASGI app
  • root_path is prepended to make the path /prefix/
  • The router makes @app.route('/') match /prefix/