A proxy in front of your application would normally set some headers on the fly before sending the requests to your server to let the server know that the request was forwarded by the proxy, letting it know the original (public) URL, including the domain, that it is using HTTPS, etc.
The server program (for example Uvicorn via FastAPI CLI) is capable of interpreting these headers, and then passing that information to your application.
But for security, as the server doesn't know it is behind a trusted proxy, it won't interpret those headers.
Here's a visual representation of how the proxy adds forwarded headers between the client and the application server:
The proxy intercepts the original client request and adds the special forwarded headers (X-Forwarded-*) before passing the request to the application server.
These headers preserve information about the original request that would otherwise be lost:
X-Forwarded-For: The original client's IP address
X-Forwarded-Proto: The original protocol (https)
X-Forwarded-Host: The original host (mysuperapp.com)
When FastAPI CLI is configured with --forwarded-allow-ips, it trusts these headers and uses them, for example to generate the correct URLs in redirects.
You could have a proxy that adds a path prefix to your application.
In these cases you can use root_path to configure your application.
The root_path is a mechanism provided by the ASGI specification (that FastAPI is built on, through Starlette).
The root_path is used to handle these specific cases.
And it's also used internally when mounting sub-applications.
Having a proxy with a stripped path prefix, in this case, means that you could declare a path at /app in your code, but then, you add a layer on top (the proxy) that would put your FastAPI application under a path like /api/v1.
In this case, the original path /app would actually be served at /api/v1/app.
Even though all your code is written assuming there's just /app.
And the proxy would be "stripping" the path prefix on the fly before transmitting the request to the app server (probably Uvicorn via FastAPI CLI), keeping your application convinced that it is being served at /app, so that you don't have to update all your code to include the prefix /api/v1.
Up to here, everything would work as normally.
But then, when you open the integrated docs UI (the frontend), it would expect to get the OpenAPI schema at /openapi.json, instead of /api/v1/openapi.json.
So, the frontend (that runs in the browser) would try to reach /openapi.json and wouldn't be able to get the OpenAPI schema.
Because we have a proxy with a path prefix of /api/v1 for our app, the frontend needs to fetch the OpenAPI schema at /api/v1/openapi.json.
Tip
The IP 0.0.0.0 is commonly used to mean that the program listens on all the IPs available in that machine/server.
The docs UI would also need the OpenAPI schema to declare that this API server is located at /api/v1 (behind the proxy). For example:
{"openapi":"3.1.0",// More stuff here"servers":[{"url":"/api/v1"}],"paths":{// More stuff here}}
In this example, the "Proxy" could be something like Traefik. And the server would be something like FastAPI CLI with Uvicorn, running your FastAPI application.
Alternatively, if you don't have a way to provide a command line option like --root-path or equivalent, you can set the root_path parameter when creating your FastAPI app:
So, it won't expect to be accessed at http://127.0.0.1:8000/api/v1/app.
Uvicorn will expect the proxy to access Uvicorn at http://127.0.0.1:8000/app, and then it would be the proxy's responsibility to add the extra /api/v1 prefix on top.
Keep in mind that a proxy with stripped path prefix is only one of the ways to configure it.
Probably in many cases the default will be that the proxy doesn't have a stripped path prefix.
In a case like that (without a stripped path prefix), the proxy would listen on something like https://myawesomeapp.com, and then if the browser goes to https://myawesomeapp.com/api/v1/app and your server (e.g. Uvicorn) listens on http://127.0.0.1:8000 the proxy (without a stripped path prefix) would access Uvicorn at the same path: http://127.0.0.1:8000/api/v1/app.
but this time at the URL with the prefix path provided by the proxy: /api/v1.
Of course, the idea here is that everyone would access the app through the proxy, so the version with the path prefix /api/v1 is the "correct" one.
And the version without the path prefix (http://127.0.0.1:8000/app), provided by Uvicorn directly, would be exclusively for the proxy (Traefik) to access it.
That demonstrates how the Proxy (Traefik) uses the path prefix and how the server (Uvicorn) uses the root_path from the option --root-path.
The "official" way to access the app would be through the proxy with the path prefix that we defined. So, as we would expect, if you try the docs UI served by Uvicorn directly, without the path prefix in the URL, it won't work, because it expects to be accessed through the proxy.
This is a more advanced use case. Feel free to skip it.
By default, FastAPI will create a server in the OpenAPI schema with the URL for the root_path.
But you can also provide other alternative servers, for example if you want the same docs UI to interact with both a staging and a production environment.
If you pass a custom list of servers and there's a root_path (because your API lives behind a proxy), FastAPI will insert a "server" with this root_path at the beginning of the list.
{"openapi":"3.1.0",// More stuff here"servers":[{"url":"/api/v1"},{"url":"https://stag.example.com","description":"Staging environment"},{"url":"https://prod.example.com","description":"Production environment"}],"paths":{// More stuff here}}
Tip
Notice the auto-generated server with a url value of /api/v1, taken from the root_path.
If you need to mount a sub-application (as described in Sub Applications - Mounts) while also using a proxy with root_path, you can do it normally, as you would expect.
FastAPI will internally use the root_path smartly, so it will just work. ✨