Host streamlit app at a subfolder

Let’s say I have a streamlit app running on port 5801, but somehow want it behind a proxy to be served at /myapp

So going to /myapp should show me the root of the app (just as at localhost:5801/)

How can I instruct the streamlit app that it is running at the subfolder level, so static files should be requested from /myapp/static etc? There might also need to be mappings of websockets and other URLs.

I have played around with browser.serverAddress and server.baseUrlPath but haven’t had any success. Any thoughts on configuring streamlit like this? (I appreciate exactly how to configure the proxy depends on my server etc - so to start with I’m just asking about configuring the app itself…)

Thanks,

Dan

1 Like

Hi @danlester,

Thanks for coming to the Streamlit forum!

If I’m understanding you correctly, what you’re trying to do is set up /myapp to be accessible on a normal domain name that potentially serves other things, right? Like http://greatdomain.com/myapp

To do this you’ll need to configure the web server, not Streamlit, actually. Streamlit will still run as usual, but the web server (Apache2? Nginx? whatever you have running) will be configured as a reverse proxy to redirect all requests for /myapp to the service running on port 5801.

We have some resources on our newly-created FAQ to help with this. It would mean a lot in terms of helping out Streamlit and the community if you would check out the FAQ and see if you can get help there.

Feel free to return here for more help, to comment on the usefulness of the FAQ, suggest improvements, etc. Thanks!

@nthmost Thank you very much for your reply, and for pointing me to the new FAQ page.

This has led closer to the answer, although I think there is still something missing: how can streamlit be configured to access static assets at a relative URL - /myapp/static instead of /static? By contrast, when behind the reverse proxy, the stream is accessed by the streamlit app at /myapp/stream instead of /stream (which is what I would hope). /static is still requested from /static instead of /myapp/static though - is this different treatment of the two URLs by design?

1 Like

Hey @danlester – Ah, I see what you mean. What web server are you using, and can I see your configuration?

Thanks for getting back to me. Yes, the webserver config was something I should really have included in my last post, but it always makes the post look a bit overwhelming so I decided to leave it until really needed!

I’m running nginx, currently just in a Docker container with streamlit in another container, just for proof of concept.

The relevant nginx config is:

    location /myapp {
    location /myapp/healthz {
         proxy_pass  http://host.docker.internal:8501/healthz;
    }
    location /myapp/stream {
         proxy_pass  http://host.docker.internal:8501/stream;
         proxy_http_version 1.1; 
         proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
         proxy_set_header Host $host;
         proxy_set_header Upgrade $http_upgrade;
         proxy_set_header Connection "upgrade";
         proxy_read_timeout 86400;
    }
    proxy_pass   http://host.docker.internal:8501/;
}

location ^~ /static {
    proxy_pass http://host.docker.internal:8501/static/;
}

location ^~ /vendor {
    proxy_pass http://host.docker.internal:8501/vendor;
}

(I’m not too sure where vendor needs to sit at the moment - it isn’t being requested)

The above all works correctly, as in the app functions correctly.

However, I think it would make sense for /static to really be requested by the browser at /myapp/static instead. This is likely to be by design in streamlit since you might want static to be treated globally and perhaps served through something more efficient for static files, or a content delivery network or something. Even/especially if there were multiple streamlit apps at different subfolders. By contrast the / and /stream endpoints have to be application specific.

But it would be even better if this can be configured in streamlit - just being able to tell it the base URL to access static files.

Thanks again!

Dan

2 Likes

As I’ve moved beyond proof-of-concept using nginx, I’m no longer seeing Streamlit request /static from absolute rather than relative paths. i.e. the app at /myapp does now seem to be requesting static files from /myapp/static. Not sure what has changed in my config though, sorry. I still think something in streamlit config can affect this.

These ideas are now also used in a ‘streamlit launchpad’ utility that I built:

https://github.com/ideonate/streamlit-launchpad

It allows you to ‘run a folder’ as a launchpad for any streamlit apps within it. So it presents a web page listing all .py files in the folder and you can click on any of them to launch directly in a new tab.

Ideally this functionality could be built directly into streamlit. At the moment the launchpad spawns a separate streamlit command line process for each app.

It’s very much an experimental alpha but please take a look if you are interested. It demonstrates the reverse proxy ideas discussed in this thread. Thoughts/feedback welcome!

Thanks,

Dan

2 Likes

Hi @danlester – did you set enableCORS to True? That might have changed the outcome.

Thanks for linking us to this project! Maybe I’ll get the chance to try it out during a hackathon.

enableCORS is likely to be it - I haven’t had a chance to check

Hi @danlester

I can see you need the ability to serve multiple files by one instance of Streamlit on one port. I do as well.

Please take a look at https://github.com/streamlit/streamlit/issues/543 and upvote if you need it.

I would need it for awesome-streamlit.org and at work. Being able to bookmark and share links to sub apps would be so nice to have.

I know bokeh, panel and voila all provide this so it should be doable.

@Marc, thanks for linking these together.

My project streamlit-launchpad does work like the Voila dashboard, and is now pip-installable: https://github.com/ideonate/streamlit-launchpad

This is a workaround for dev environments, but in production you’d probably want a more substantial setup, or even better if incorporated into Streamlit itself as per the issue you raised.

Anyway, I’d be really interested in your thoughts if you get a chance to try it out, and meanwhile I’ll take a look at the issue.

Dan

2 Likes

This actually looks awesome and very much as what I need.

As far as I can see from the code when looking on my phone you run each app/ Python file on a separate port and then provide them on a common port using a reverse proxy. Is that correct?

One thing I would need for my use case is to specify the server address to 0.0.0.0 instead of localhost to run inside a Docker container.

Another thing that would be nice to have would be the ability to start the launchpad from python code and specify the apps and endpoints via a dictionary like

Routes=[{‘app’: app1_func, ‘endpoint’: ‘/my/app’}, …]

The framework Panel has a similar command called panel.serve.

It would really be nice to be able to define complex endpoints like

/book/1
/book/2
/book/3

And provide the url as input to the function automatically. So that for example I can use the value 1,2 or 3 to know which book to analyze.

Yes, that’s how it’s working.

All your ideas make sense and could certainly be implemented.

Please do take a closer look and try it out if you get a chance. It would be great to hear how you get on!

I think the biggest question is really understanding the possible use cases. As I said, scalability is a bit of an unknown - as soon as you might need multiple servers, it would probably make more sense to ‘load balance’ at a network configuration level, although then the dynamic functionality of picking up any new .py script would be lost.

Dan

1 Like