You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
After making a complex web app in NiceGUI much more easily than any other web framework, I've found one of the few things that were a bit hard to do was having it work correctly when hosted behind a reverse proxy under a prefix path in the URL (e.g. /ng/).
I think I've mostly figured it out, so I thought I'd show and discuss an example below to help others (and for others to check if there are flaws in my assumptions/conclusions!).
Just for reference, all my testing was done with NiceGUI 2.13.0 and uvicorn 0.34.1 (since I see from previous discussions that uvicorn version made a difference: #2813).
TL;DR for hosting behind a prefix:
You can't just add the prefix to everything manually as you have to use root_path for any of the NiceGUI internals to work correctly (i.e. /_nicegui paths, including websocket)
Using root_path could either mean ui.run(root_path="/prefix") (or the equivalent configured directly in FastAPI/uvicorn), or using X-Forwarded-Prefix headers
NiceGUI will then automatically add the root_path prefix whenever it has control over the URL, e.g. ui.page, ui.navigate, app.add_static_files and any reference to static content by ui.image, etc.
However, you have to manually add the prefix for other cases such as: html.img (even when referencing NiceGUI's static content), any links in ui.markdown, any URLs in .props() (e.g. href=...), if you use FastAPI's RedirectResponse, etc.
Hopefully this is correct and if so maybe some of this could be added to the documentation or in the future maybe some features could help simplify this?
Small Example
Caddy
For a reverse proxy I'll use Caddy. Its config consists of one file named Caddyfile which contains this:
# Host server on a different port (8123) from the NiceGUI app we'll be forwarding to (8080):8123 {
# Route prefix /ng/ to our NiceGUI app handle/ng/* {
# Have to strip the prefix when using `root_path` in NiceGUI (with uvicorn `0.34.11 - if that matters?) uri strip_prefix /ng # Automatically also handles websockets reverse_proxy http://127.0.0.1:8080
}
# Handle all other routes with a static message handle {
respond"[Not Found]" 404
}
}
This app includes the components or use cases that gave me a bit more trouble:
fromfastapi.responsesimportRedirectResponsefromniceguiimportapp, Client, html, ui# Has to match prefix in proxyURL_PREFIX="/ng"# Where we host static content through NiceGUISTATIC_PATH="/static"# NiceGUI handles prefix here@ui.page("/")defpath_root():
withui.element("q-breadcrumbs"):
# We have to add prefix hereui.element("q-breadcrumbs-el").props(f"label=Home icon=home href='{URL_PREFIX}/'")
ui.button("Button1", on_click=lambda: ui.notify("Button1 clicked!"))
withui.card():
# NiceGUI handles prefix hereui.image(source=f"{STATIC_PATH}/image.png").classes("w-[100px] h-[100px]")
# and hereui.button("Redirect", on_click=lambda: ui.navigate.to("/redirect"))
@ui.page("/other")defpath_other():
withui.element("q-breadcrumbs"):
ui.element("q-breadcrumbs-el").props(f"label=Home icon=home href='{URL_PREFIX}/'")
ui.element("q-breadcrumbs-el").props(f"label=Other")
ui.button("Button2", on_click=lambda: ui.notify("Button2 clicked!"))
withui.card():
# We have to add prefix herehtml.img(src=f"{URL_PREFIX}/{STATIC_PATH}/image.png")
# and hereui.markdown(f"Link to [Home]({URL_PREFIX}/)")
# NiceGUI handles prefix hereui.button("Return to Home", on_click=lambda: ui.navigate.to("/"))
@ui.page("/redirect")defredirect(client: Client):
# RedirectResponse that takes root_path / URL_PREFIX into accountredirect_url="/other"# We have to add prefix herereturnRedirectResponse(client.request.scope.get("root_path", "") +redirect_url)
# NiceGUI handles prefix hereapp.add_static_files(STATIC_PATH, "./static")
ui.run(
uvicorn_logging_level="info",
root_path=URL_PREFIX,
)
NOTE: this example also requires you to place an image in a local folder at static/image.png.
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
Uh oh!
There was an error while loading. Please reload this page.
-
After making a complex web app in NiceGUI much more easily than any other web framework, I've found one of the few things that were a bit hard to do was having it work correctly when hosted behind a reverse proxy under a prefix path in the URL (e.g.
/ng/
).I think I've mostly figured it out, so I thought I'd show and discuss an example below to help others (and for others to check if there are flaws in my assumptions/conclusions!).
Just for reference, all my testing was done with NiceGUI
2.13.0
and uvicorn0.34.1
(since I see from previous discussions that uvicorn version made a difference: #2813).TL;DR for hosting behind a prefix:
root_path
for any of the NiceGUI internals to work correctly (i.e./_nicegui
paths, including websocket)root_path
could either meanui.run(root_path="/prefix")
(or the equivalent configured directly in FastAPI/uvicorn), or usingX-Forwarded-Prefix
headersroot_path
(see: root_path, X-Forwarded-Prefix and relative URLs #2813)root_path
prefix whenever it has control over the URL, e.g.ui.page
,ui.navigate
,app.add_static_files
and any reference to static content byui.image
, etc.html.img
(even when referencing NiceGUI's static content), any links inui.markdown
, any URLs in.props()
(e.g.href=...
), if you use FastAPI'sRedirectResponse
, etc.Hopefully this is correct and if so maybe some of this could be added to the documentation or in the future maybe some features could help simplify this?
Small Example
Caddy
For a reverse proxy I'll use Caddy. Its config consists of one file named
Caddyfile
which contains this:And I then ran it in docker with this command:
docker run --rm --name caddy \ --network host \ -p 8123:8123 \ -v $(pwd)/Caddyfile:/etc/caddy/Caddyfile -v caddy_data:/data -v caddy_config:/config \ caddy
I think the equivalent config in nginx might be (not fully tested):
NiceGUI app
This app includes the components or use cases that gave me a bit more trouble:
NOTE: this example also requires you to place an image in a local folder at
static/image.png
.Beta Was this translation helpful? Give feedback.
All reactions