justpy-org / justpy

An object oriented high-level Python Web Framework that requires no frontend programming
https://justpy.io
Apache License 2.0
1.22k stars 96 forks source link

Fix URL generation to better support serving behind proxy #451

Closed frankie567 closed 2 years ago

frankie567 commented 2 years ago

Objective

Currently, it's very hard to serve a JustPy app behind a reverse proxy.

Typically, if we want to serve the JustPy app under a path prefix. In ASGI apps, this can be handled thanks to the root_path parameter. There is a very good rationale about this in the FastAPI documentation: https://fastapi.tiangolo.com/advanced/behind-a-proxy/

However, for this to work, we need to make sure every URL are generated properly, especially by using the url_for function of Starlette.

Currently, there are many places where the URL is manually built.

Changes

The presented changes try to solve this.

  1. The URL of the WebSocket is now dynamically generated in the main.html script. For this to work, we had to add the name parameter to the WebSocket route.
  2. Every CSS and JS static files in the /templates/local folder now have a dynamically generated URL.

Feel free to make some comments about this; I'll be happy to improve my proposal so it fits well in the project.

rodja commented 2 years ago

Very interesting. I'll have look at this tomorrow. We have found a slightly different solution but maybe this is nicer.

falkoschindler commented 2 years ago

Discussion #402 seems related.

rodja commented 2 years ago

The Issue https://github.com/elimintz/justpy/issues/220 is also related.

rodja commented 2 years ago

And this pull request: https://github.com/elimintz/justpy/pull/258

rodja commented 2 years ago

@frankie567 for comparison with our internal solution I created https://github.com/elimintz/justpy/pull/459. What do you think?

rodja commented 2 years ago

@frankie567 I just pushed a reverse_proxy_demo (see https://github.com/elimintz/justpy/issues/220#issuecomment-1229119447). Unfortunately with your current solution I just see a blank page when accessing it from behind the reverse proxy.

It seems like url_for() from Starlette does not take the reverse proxied path into account (see https://github.com/encode/starlette/issues/604 for example).

frankie567 commented 2 years ago

To make it work with this solution, the root_path needs to be set with the wanted prefix. With Uvicorn, this can be done either by:

I've it working that way on a project with Docker and Traefik.

rodja commented 2 years ago

Ah of course. Setting root_path works in about 99% of all scenarios. But we for example use NiceGUI (and hence JustPy as basis) on mobile robots. These are accessable through their local wifi network (eg. http://192.168.42.1/) and through a device gateway hosted on the internet (eg. https://devices.zauberzeug.com/robots/3/). Thereby the root_path is different for different users.

frankie567 commented 2 years ago

I see, that's indeed an unusual use-case 🤔 Well, I'll let you choose the best solution then.

rodja commented 2 years ago

Ok, I think the X-Forwarded-Prefix solution is more general and flexible than using url_for. I'll close this pull request to further work on https://github.com/justpy-org/justpy/pull/459. We still need to decide whether to use tag or not.

WolfgangFahl commented 2 years ago

389 is also offering a solution