I have a FastAPI application that is behind a NextJS reverse proxy. I'm using NextJS rewrites, which sets the x-forwarded-for header to the externally-visible hostname and port. The rewrite looks like this: rewrites: async () => [ { source: "/api/:slug*", destination: "http://backend:8000/:slug*" } ] The whole lot is running in a docker stack (which is where hostnames like backend come from) and I end up with headers like this: host: backend:8000 x-forwarded-host: localhost:3000 I'm then emailing a link from the FastAPI application. I construct the URL like this: @app.get("/verify") async def verify(token: str): ... @app.post("/signup") async def signup(body: SignupRequest, request: Request) -> str: user = add_user(body.username, body.email) token = user.get_signup_token() url = request.url_for("verify").include_query_params(token=token) email_verification(body.email, url) return "" I've set up FastAPI with root_path="/api" so that the path is rewritten correctly. The resulting url is http://backend:8000/api/verify. I want it to be http://localhost:3000/api/verify (ie to have the actual hosted URL rather than the intra-docker-stack URL). I've tried adding a middleware like this: @app.middleware("http") async def rewrite_host_header(request: Request, call_next): if "x-forwarded-host" in request.headers: request.headers["host"] = request.headers["x-forwarded-host"] return await call_next(request) but this doesn't seem to make a difference. I've also tried adding request.url = request.url.replace(host=request.headers["x-forwarded-for"]) but this also doesn't change the output of request.url_for(...). How am I meant to configure this so that URLs are emitted with the right scheme, hostname and port? Edit to add: I've tried also setting X-Forwarded-Proto, X-Forwarded-Port, X-Forwarded-Prefix and X-Forwarded-For, making requests directly to FastAPI using curl and so cutting out the NextJS step. None of it makes any difference to the URLs that url_for() emits. Continue reading...