We have found that ‘prefix’ in panel.serve causes problems when trying to run apps at a subfolder URL behind a reverse proxy. Or it is possible there is some extra configuration in the Bokeh server that I haven’t been able to find…
Let’s say I have a panelscript.py to run a simple Panel server:
import panel as pn
def app1():
return pn.pane.Markdown("# Hello From App1")
def app2():
return pn.pane.Markdown("# Hello From App2")
ROUTES = {
"app1": app1, "app2": app2
}
pn.config.sizing_mode="stretch_width"
opts = {
'port': 5006,
'title': "Example",
'websocket_origin': ['localhost:8888', 'localhost:5006'],
'show': False,
'index': None
}
pn.serve(ROUTES, **opts)
If I run this with python3 panelscript.py
then I can access the apps fine at localhost:5006/ as expected, including the default Panel index_html page, linking to /app1 and /app2:
The problem I’m about to describe was encountered within a JupyterHub environment where each user’s server is at a sub-folder URL, so we can borrow some components from JupyterHub to set up a simple reverse proxy.
pip install jhsingle-native-proxy==0.3.1
export JUPYTERHUB_SERVICE_PREFIX=/subfolder
jhsingle-native-proxy --port=8888 --destport=5006 --authtype=none python3 panelscript.py
If I access localhost:8888/subfolder/ this seems to work, except that the index page links app1 to the URL /app1. This is incorrect, as localhost:8888/subfolder/app1 is the correct user-facing URL to the sub-app. If I access /subfolder/app1 directly, that works fine.
So maybe I’m supposed to supply a prefix to panel.serve, adding the following just before pn.serve:
opts['prefix'] = '/subfolder'
But now the index page appears at localhost:8888/subfolder/subfolder/ and the sub-app at localhost:8888/subfolder/subfolder/app1. The index page itself still doesn’t link to a working app - it links to {{ prefix }}/app1, i.e. /subfolder/app1 which isn’t where the app is served since prefix is added both to the server-side routes AND to the user-facing HTML.
The index_html template could be fixed by changing to relative URLs (’.’ instead of ‘{{ prefix }}’ in the template), although I don’t know if that could upset anything else.
Or is there some server configuration that allows me to separate out server-side and user-facing prefixes?
For example in Voila, I can run it like this:
voila file.ipynb --Voila.base_url="/subfolder" --Voila.server_url="/"
meaning that the server itself should serve at the root URL ‘/’ as normal, but any user-facing URLs, e.g. within HTML, should be written with the prefix /subfolder.
This example has emerged from @Marc experimenting with deployment of Panel through ContainDS Dashboards, a method of leveraging your JupyterHub to serve non-Jupyter web apps to authenticated users on your JupyterHub. The GitHub issue is here.