Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add base URL for deployment #1820

Open
schwarbf opened this issue Jan 15, 2025 · 4 comments
Open

feat: add base URL for deployment #1820

schwarbf opened this issue Jan 15, 2025 · 4 comments

Comments

@schwarbf
Copy link

schwarbf commented Jan 15, 2025

We currently have many Streamlit applications deployed on our Kubernetes cluster. The Kubernetes Ingress routes the requests to the corresponding deployment in Kubernetes with a base URL path. This means that when we try to access https://demo.com/baseurl in our browsers, the request gets routed to the specific Kubernetes deployment where the Streamlit app is running.

This can easily be configured instreamlit using for example the config baseUrlPath (See here for more information). For example, we deploy our Streamlit app under https://demo.com/app1 by launching streamlit in the Deployment:

streamlit run /app/streamlit_dashboard.py --server.port 5000 --server.baseUrlPath /app1

We wanted to replace many of those Streamlit apps with Python Shiny apps. However, as of today, this seems not possible for us. A similar issue was posted on StackOverflow. The problem is that the Shiny doesn't provide the a equivalent parameter to baseUrlPath.

We have already unsuccessfully tried the following approaches:

1. Use --root-path flag in uvicorn
We tried to deploy the app using uvicorn shiny_demo.shiny.run:app --host 0.0.0.0 --port 5000 --root-path/shiny_demo. However, this parameter does not solve our issue. Rather, it appends the root path to every incoming request.
Shiny doesn't recognize such a path and returns a 404 error.

2. Modify the ingress to remove the base URL when it reaches the deployment
This didn't work either because Shiny tries to access several .js and .css files that do not have the base url prefix.

Any suggestion or help is highly appreciated!

@gadenbuie
Copy link
Collaborator

I don't have a any experience running Shiny apps in Kubernetes clusters, so I asked around internally at Posit and got some advice.

One immediate thing that came up is that we've also run into the same confusion/issue with uvicorn's --root-path flag. A Posit engineer submitted a PR to uvicorn that would add a new flag that would nicely cover your use case, but it hasn't been reviewed yet. That PR also suggests that without this flag, you'd have to configure your proxy layer to handle the subpath.

Another option could be to use starlette to mount the entire Shiny app at the base URL. That might look something like this:

from starlette.applications import Starlette
from starlette.routing import Mount

routes = [
    Mount("/shiny", app=my_shiny_app),
]

app = Starlette(routes=routes)

if __name__ == "__main__":
    import uvicorn

    uvicorn.run(app, host="0.0.0.0")

Hopefully that helps get you through this road block. If you find a solution, please let us know what you do and we'll see how we could use that to improve Shiny.

@gadenbuie
Copy link
Collaborator

From @amol-, if you're using nginx your proxy config might look like this

location /shiny-demo/ {
    proxy_pass http://127.0.0.1:8000/;
    rewrite ^/shiny-demo/(.*)$ /$1 break;
    proxy_set_header   Host $host;
    proxy_set_header   X-Real-IP $remote_addr;
    proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header   X-Forwarded-Proto $scheme;
}

And you'd launch the app with this (or something close to it)

uvicorn shiny_demo.shiny.run:app --proxy-headers --root-path /shiny-demo

@schwarbf
Copy link
Author

@gadenbuie @amol_, thanks a lot for your suggestions. Actually, before you responded we tried out your mounting suggestion using Starlette, because we saw that is how it could be solved for gradio as well. This worked perfectly fine. We will however monitor your PR submission and check whether they will implement a flag as suggested.

@thohan88
Copy link

From @amol-, if you're using nginx your proxy config might look like this

location /shiny-demo/ {
    proxy_pass http://127.0.0.1:8000/;
    rewrite ^/shiny-demo/(.*)$ /$1 break;
    proxy_set_header   Host $host;
    proxy_set_header   X-Real-IP $remote_addr;
    proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header   X-Forwarded-Proto $scheme;
}

And you'd launch the app with this (or something close to it)

uvicorn shiny_demo.shiny.run:app --proxy-headers --root-path /shiny-demo

This is slightly off-topic @gadenbuie and @amol-, but I had a similar use case where I wanted to make the --root-path work with a rsconnect-python-deployment. After fiddling back and forth with --entrypoint, I gave up in the end. Do you know if it is possible to modify the entrypoint at all beyond the application import string in rsconnect-python?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants