preview

If your’re using Streamlit at work, chances are you have multiple applications. However, adding new apps often comes with increased hosting costs. In this blog post, I’ll show you how to host multiple Streamlit applications in the same server so you can keep costs in control without losing the flexibility of keeping applications separate.

This approach is particularly beneficial for organizations or individuals managing several smaller Streamlit apps that don’t require dedicated servers. Instead of paying for separate hosting environments for each app, you can efficiently run them all on a single, more powerful server.

The following sections cover the technical details, which are useful if you need to customize the template. If you need help with customization, contact us.

If you want to see this up and running scroll to the deployment section.

Setup

We’ll explore how to run multiple Streamlit applications on a single server using Docker, NGINX, and Supervisor. We’ll set up a containerized environment that hosts two separate Streamlit apps, each running in its own Python virtual environment. NGINX will act as a reverse proxy, routing requests to the appropriate Streamlit app based on the URL path. Supervisor will manage the processes, ensuring our NGINX server and Streamlit apps start automatically and stay running. This setup provides a scalable and efficient way to deploy multiple Streamlit apps, making it ideal for projects that require separate but related data visualization or analysis tools.

Here’s what we’ll cover:

  1. Dockerizing our environment with a custom Dockerfile
  2. Configuring NGINX as a reverse proxy
  3. Setting up Supervisor to manage our processes
  4. Running two Streamlit apps with different dependencies
  5. Deploying the entire setup with a single command

By the end of this tutorial, you’ll have a robust system for hosting multiple Streamlit apps, which can be easily deployed to various cloud platforms or run locally for development and testing.

Docker

We’ll highlight the most important parts of our Dockerfile (you can see the full Dockerfile on GitHub):

First, we create two virtual environments (one per app) and install dependencies:

RUN python -m venv /venvs/first
RUN python -m venv /venvs/second

COPY apps/requirements-first.txt /apps/requirements-first.txt
COPY apps/requirements-second.txt /apps/requirements-second.txt

RUN /venvs/first/bin/pip install -r /apps/requirements-first.txt
RUN /venvs/second/bin/pip install -r /apps/requirements-second.txt

Then, we copy the NGINX, Supervisor configuration and all our source code:

COPY nginx.conf /etc/nginx/nginx.conf
COPY supervisord.conf /etc/supervisord.conf

COPY apps/ /apps

Finally, we expose port 80 from the container and run the command that starts Supervisor:

EXPOSE 80
CMD ["/usr/bin/supervisord", "-c", "/etc/supervisord.conf"]

NGINX Configuration

We’ll use NGINX to route requests to the correct app, here’s the relevant configuration for the first app:

location /first {
    proxy_pass http://127.0.0.1:6060;
    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_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    proxy_read_timeout 86400;
}

The configuration enables NGINX to listen to requests in /first and route them to the first application. The configuration for the second application is identical, except it routes requests to the second application.

Supervisor Configuration

Supervisor allows us to ensure NGINX and our two applications are running (and restarts them if they crash). Here’s the NGINX section:

[program:nginx]
command=nginx -g 'daemon off;'
autostart=true
autorestart=true
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0

We also need two sections (one per app), they’re almost the same:

[program:first]
command=/venvs/first/bin/streamlit run first.py --server.port=6060 --server.baseUrlPath=/first --server.headless=true --server.address=0.0.0.0 --browser.gatherUsageStats=false --server.enableStaticServing=true --server.fileWatcherType=none --client.toolbarMode=viewer
directory=/apps
autostart=true
autorestart=true
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0

Streamlit Applications

For the sake of example, we created two applications that generate a scatter plot when clicking a button. The first one uses matploblib and the second one plotly.

Deployment

Option 1: Quick Deploy

Click here to automatically deploy this Streamlit app on Ploomber’s platform.

Option 2: Manual Deployment

Use the following commands to deploy the application (source code here):

# install ploomber cloud cli
pip install ploomber-cloud

# download example
ploomber-cloud examples streamlit/multiple-streamlit
cd multiple-streamlit

Note that you’ll need a Ploomber Cloud account to continue:

# initialize the project
ploomber-cloud init

# deploy
ploomber-cloud deploy

After a few minutes, you’ll have the application up and running!