Self-hosted deployments

Commercial software

Posit Connect can support a wide variety of R and Python content including Shiny applications. Since Connect can host models, APIs, apps, and datasets, it lets you easily integrate Shiny apps with other other data science tools. For example, Connect can retrain a model on a schedule, expose that model through an API, and communicate the results with a Shiny app. Posit Connect is commonly used in highly regulated environments, so can fulfill most security and compliance requirements.

There are two main ways to deploy Shiny apps to Posit Connect:

Command line deployment

  1. Install the rsconnect-python package using pip.

    pip install rsconnect-python

    Deploying Shiny Express applications requires version 1.22.0 or later of the rsconnect-python package.

  2. Generate an API key on Connect.

  3. At the command line add a nickname for your connect server with rsconnect add.

    rsconnect add -n my-connect -s <server_url> --api-key <YOUR_KEY>
  4. Deploy your application with rsconnect deploy shiny

    rsconnect deploy shiny -n my-connect

You can also deploy shiny apps from a continuous integration system using rsconnect deploy.

Git backed deployment

Posit Connect can be set up to automatically deploy content from git with git-backed deployment. If your installation is configured to use git, Posit Connect can monitor a branch of a git repo and redeploy your content when that branch changes.

  1. Use rsconnect write-manifest shiny to generate a manifest.json file and a requirements.txt. The manifest file is used by Connect to deploy your app using the correct version of Python.

  2. Check your code into git, make sure to include the manifest and requirements file.

  3. Follow the Connect instructions to link your branch with Connect.

Open source options

Posit’s mission is to create free and open-source software for data science, scientific research, and technical communication. We do this to enhance the production and consumption of knowledge by everyone, regardless of economic means, and to facilitate collaboration and reproducible research, both of which are critical to the integrity and efficacy of work in science, education, government, and industry. As a result we are committed to supporting open source hosting for all Shiny apps. You will always be able to host Shiny apps for free, and those apps will have the same capabilities as apps hosted on our commercial products. If you want to read more about our commitment to free and open source software, you can see our annual public benefit report.

Deploy to Shiny Server (open source)

Shiny Server is an open source server written in Node.js that can host multiple Shiny apps on a single port, managing the starting/stopping/restarting of each app’s Python process.

Compared to Posit Connect, deploying apps on Shiny Server is less automated and more config-file based, similar in spirit to Apache or nginx. Also note that Shiny Server can handle less traffic on a single server node, as it doesn’t know how to start multiple Python processes per app, as Posit Connect can. To be clear, Shiny Server can serve multiple apps at once, and multiple concurrent users per app; each app is just limited to the traffic that a single Python process can support before it slows unacceptably. And note that Shiny Server is designed to work well behind any proxy or load balancer that supports sticky sessions.

Install

First, download and install Shiny Server from a .deb or .rpm—but skip the instructions for installing R and Shiny for R (unless you plan to deploy both Shiny for R and Shiny for Python apps). If all goes well, you should see a welcome page on http://hostname:3838/. (Don’t worry if you see iframes with greyed-out apps; they depend on R.)

Configure Python

Next, you need to tell Shiny Server how to find Python. You can point Shiny Server at either a Python binary (e.g. /usr/bin/python3) or an absolute path to a virtualenv (e.g. /srv/shiny-server/python39-venv). You can also provide a relative path to a virtualenv (e.g. .venv) in which case, SSOS will look for that directory relative to app.py. (Don’t forget that you need to pip install shiny and any other Python packages needed by your app(s), into whichever Python installation or virtualenv(s) you intend to use.)

Edit the file /etc/shiny-server/shiny-server.conf (root privileges are required). Add a line with python <path-to-python-or-venv>; to the top of the file, leaving the rest of the file alone (at least for now). For example, if you wanted to use /usr/bin/python3, the end result might look like this:

# Use system python3 to run Shiny apps
python /usr/bin/python3;

# Instruct Shiny Server to run applications as the user "shiny"
run_as shiny;

# Define a server that listens on port 3838
server {
  listen 3838;

  # Define a location at the base URL
  location / {

    # Host the directory of Shiny Apps stored in this directory
    site_dir /srv/shiny-server;

    # Log all Shiny output to files in this directory
    log_dir /var/log/shiny-server;

    # When a user visits the base URL rather than a particular application,
    # an index of the applications available in this directory will be shown.
    directory_index on;
  }
}

Place application files

Now, clear out the contents of /srv/shiny-server/ and replace it with your own app(s).

  • If you’re only hosting a single app, you can put the app.py (and the rest of the app’s files) directly in /srv/shiny-server/, and it will be served from http://hostname:3838/.
  • If you have multiple apps, copy each app into a subdirectory; for example, /srv/shiny-server/foo/app.py would be served from http://hostname:3838/foo/. In this case, you can put static assets into the root /srv/shiny-server/ directory, like an index.html file.

If you elected to use a relative virtualenv path (e.g. python .venv;), then now is the time to create a virtualenv alongside each app.py and install the necessary Python packages. (Do not upload virtualenv directories created on other computers, as virtualenvs are not meant to be portable.)

Restart and test

Finally, you will need to restart Shiny Server for your changes to /etc/shiny-server/shiny-server.conf to take effect.

Not working for you? Look for clues in /var/log/shiny-server.log and /var/log/shiny-server/*.log.

See the Shiny Server Administrator’s Guide for other options. (Note that the Admin Guide includes documentation for the commercially licensed Professional edition of Shiny Server, and includes features marked “Pro Only”. Shiny Server Professional is no longer available for new customers, and doesn’t support Shiny for Python; our commercially licensed on-premises server these days is Posit Connect.)

Other hosting options

Shiny is built on the well-known foundation of Starlette, ASGI, and Uvicorn—the same exact stack as FastAPI. Even the shell command used to run an FastAPI server works just as well for a Shiny app:

# Assuming you have a file named app.py, with a Shiny app named app.
uvicorn app:app --host 0.0.0.0 --port 80

So any FastAPI hosting arrangement should work for Shiny as well, right? Sorry, it’s not that simple. Despite the similarities, Shiny apps are a different beast than your typical web API and cannot be deployed with the mental model one would use for FastAPI.

The two main complications are:

  1. Shiny uses WebSockets for most browser/server communication. Even as this is written in 2023, we have enterprise customers whose networks interfere with WebSocket traffic.
  2. Shiny sessions hold state in memory. Therefore, from the moment a browser tab connects to a Shiny app to the moment it disconnects, all of its server communications must go to the same server and the same Python process on that server (“sticky” load balancing).

Our hosting solutions (the ones described above) are designed with both of these bullet points in mind, and we highly recommend you use them if possible.

If not, just remember: it’s very important that whatever deployment configuration you use can support sticky sessions wherever load balancing is introduced. Whether you use an AWS ALB, an nginx proxy, or even a CDN like CloudFlare, all must use sticky sessions. Notably, this rules out the use of Gunicorn (it doesn’t support sticky sessions), at least with >1 worker.

You can use this test application to make sure that your deployment has sticky sessions configured; the application does nothing but send repeated requests to the server, which will only succeed if they connect to the same Python process that the page was loaded on.

Heroku

We have some users who have successfully deployed Shiny applications to Heroku. To test if this works on your setup, try deploying the Shiny test application using the instructions on this github repo.

AWS, Google Cloud, Azure

We don’t have any particular recommendations for deploying on cloud platforms other than the general point about using sticky-session load balancing. If you have any recipes or tips, please share!