Skip to content

Commit

Permalink
Add deployment overview doc (#166)
Browse files Browse the repository at this point in the history
This is to provide a single URL that we can point at for people to
learn about our deployment options.
  • Loading branch information
jcheng5 committed Jun 25, 2024
1 parent 345fc3e commit c274048
Show file tree
Hide file tree
Showing 3 changed files with 29 additions and 158 deletions.
2 changes: 2 additions & 0 deletions _quarto.yml
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,8 @@ website:
icon: code-square
- text: "Deploy"
menu:
- text: "Overview"
href: docs/deploy.qmd
- docs/deploy-cloud.qmd
- docs/deploy-on-prem.qmd
- docs/shinylive.qmd
Expand Down
10 changes: 6 additions & 4 deletions docs/deploy-on-prem.qmd
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@ title: "Self-hosted deployments"

# Commercial software

[Posit Connect](https://posit.co/products/enterprise/connect/) can support a wide variety of R and Python content including Shiny applications.
[Posit Connect](https://posit.co/products/enterprise/connect/) is our flagship publishing platform for the work your teams create in Python or R.
With Posit Connect, you can share Shiny applications, [Quarto](https://quarto.org) reports, dashboards and plots, as well as Flask, Dash, Streamlit and Bokeh apps, in one convenient place.
Features include scheduled execution of reports and flexible security policies to bring the power of data science to your entire enterprise.

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.
Expand Down Expand Up @@ -61,9 +64,8 @@ If you want to read more about our commitment to free and open source software,
[Shiny Server](https://posit.co/products/open-source/shinyserver/) 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.

- Shiny Server v1.5.19 or later is required for Shiny for Python apps.
Deploying [Shiny Express](https://shiny.posit.co/blog/posts/shiny-express/) applications requires Shiny Server v1.5.22 or later.
You can find [the lastest version of Shiny Server here](https://dailies.rstudio.com/shiny-server/).
- Shiny Server v1.5.22 or later is required for Shiny for Python apps.
You can find [the latest version of Shiny Server here](https://posit.co/download/shiny-server/).
- Linux only (see [Platform Support](https://posit.co/about/platform-support/) for a list of supported distributions).

Compared to Posit Connect, deploying apps on Shiny Server is less automated and more config-file based, similar in spirit to Apache or nginx.
Expand Down
175 changes: 21 additions & 154 deletions docs/deploy.qmd
Original file line number Diff line number Diff line change
@@ -1,171 +1,38 @@
---
title: Deploying Shiny
title: Hosting and deployment
description: When it's time to put your Shiny app on the web, you can choose to deploy on your own servers or on our hosting service.
---

(This page is about doing traditional Shiny application deployments. If you want to do a Shinylive deployment, see the [Shinylive](shinylive.qmd) page.)

:::{.lead}
When it's time to put your Shiny app on the web, you can choose to deploy on your own servers or on our hosting service.
:::

## Deploy to shinyapps.io (cloud hosting)

The quickest way to get started is [shinyapps.io](https://www.shinyapps.io/), which is our hosted service for deploying Shiny applications. With shinyapps.io, you don't need to set up a server; you just need to make an account on the site and then deploy the application there. Both free and paid tiers of service are available.

To use shinyapps.io, see the [shinyapps.io documentation](https://docs.rstudio.com/shinyapps.io/getting-started.html#working-with-shiny-for-python).


## Deploy to Shiny Server (open source)

[Shiny Server](https://www.rstudio.com/products/shiny/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.

* Shiny Server v1.5.19 or later is required.
* Linux only (see [Platform Support](https://www.rstudio.com/about/platform-support/) for a list of supported distributions).

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](https://support.rstudio.com/hc/en-us/articles/213733868-Running-Shiny-Server-with-a-Proxy) that supports sticky sessions.

### Install

First, [download](https://www.rstudio.com/products/shiny/download-server/) and [install](https://docs.rstudio.com/shiny-server/#installation) 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](install.html) 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:

```default
# 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](https://docs.rstudio.com/shiny-server/#stopping-and-starting) 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](https://docs.rstudio.com/shiny-server/) 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.)

## Deploy to Posit Connect (commercial)

[Posit Connect](https://www.rstudio.com/products/connect/) is a publishing platform for data science and analytics. If you have a server running Posit Connect, you can deploy your Shiny for Python applications to it.

* Connect version 2022.07 or later is required.
* Linux only (see [Platform Support](https://www.rstudio.com/about/platform-support/) for a list of supported distributions).


### Install `rsconnect-python`

Install the `rsconnect-python` package:

```bash
pip install rsconnect-python --upgrade
```


### Register your Connect server/account

This step will need to be done just once with your user account on your computer; afterward, you will be able to deploy Shiny applications without needing to do this again.

Assuming you have publishing rights on an Posit Connect instance, log into that instance and create an API key ([instructions](https://docs.rstudio.com/connect/user/api-keys/#api-keys-creating)). Copy the newly created API key to the clipboard.

From the terminal, register the Connect server and your account by running:

```bash
rsconnect add -n <server-nickname> -s <server-url> -k <api-key>
```

For example, you might run the following to register connect.rstudioservices.com under the nickname "rstudioservices":

```bash
rsconnect add -n rstudioservices -s https://connect.rstudioservices.com/ -k <api-key>
```


### Create a requirements.txt

In the same directory as your `app.py`, include a `requirements.txt` that might look something like:

```default
shiny
```

If your app uses any other packages, add them to the `requirements.txt` file. You can specify a version number if desired. For example:

```default
scipy==1.8.0
pandas>=1.4.1
```


### `rsconnect deploy`

To actually deploy the app, `cd` to the app directory and run:

```bash
rsconnect deploy shiny . --entrypoint app:app
```

If your application object is named `app` and is in `app.py`, you can omit `--entrypoint app:app`.
If you have more than one Connect server defined, add `-n <server-nickname>` to the above to successfully publish.


## Other hosting options

Shiny is built on the well-known foundation of [Starlette](https://www.starlette.io/), [ASGI](https://asgi.readthedocs.io/), and [Uvicorn](https://www.uvicorn.org/)---the same exact stack as [FastAPI](https://fastapi.tiangolo.com/). Even the shell command used to run an FastAPI server works just as well for a Shiny app:
## Cloud hosting

```sh
# Assuming you have a file named app.py, with a Shiny app named app.
uvicorn app:app --host 0.0.0.0 --port 80
```
The easiest deployment option to get started with is cloud hosting.
Since you don't need to run your own server, you can have your Shiny app up and running in minutes!

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](https://fastapi.tiangolo.com/).
Shiny cloud hosting may not be right for you if your app must run within your datacenter or virtual private cloud; please see the next option if that's the case.

The two main complications are:
<a class="btn btn-outline-dark btn-sm mt-3 no-icon" href="deploy-cloud.qmd">Learn more</a>

1. Shiny uses WebSockets for most browser/server communication. Even as this is written in 2022, we have enterprise customers whose networks interfere with WebSocket traffic.
2. Shiny sessions hold reactive state in RAM. 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).
## Self-hosted deployments

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 you prefer to run your own server, or you must run your apps inside your network or virtual private cloud, then a self-hosted (or on-premises) deployment may be right for you.
Posit offers both open source (Shiny Server) and commercial/enterprise (Posit Connect) options for Shiny app hosting.

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.
<a class="btn btn-outline-dark btn-sm mt-3 no-icon" href="deploy-on-prem.qmd">Learn more</a>

You can use this [test application](https://github.com/posit-dev/py-shiny/blob/7ba8f90a44ee25f41aa8c258eceeba6807e0017a/examples/load_balance/app.py) 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.
## Static hosting

#### Heroku
Some Shiny apps can be converted into completely static web pages (HTML, CSS, and JavaScript), with no need for Python to be running on the server.
This is made possible by running the Shiny app's Python logic entirely inside of the browser, using the magic of WebAssembly.
We call this mode ShinyLive, and it has great benefits for making hosting cheaper, simpler, and practically infinitely scalable.

We had high hopes for Heroku, as they have a documented option for session affinity. However, for reasons we don't yet understand, the test application consistently fails to pass. We'll update this page as we find out more.
<a class="btn btn-outline-dark btn-sm mt-3 no-icon" href="shinylive.qmd">Learn more</a>

#### AWS, Google Cloud, Azure
## More resources

We don't have anything to report on these cloud platforms yet (other than to again remind you to use sticky-session load balancing); if you beat us to a successful deployment, please [get in touch](https://github.com/posit-dev/py-shiny/issues) about your experiences!
See [a comparison of Posit's hosting and deployment options for Shiny](https://posit.co/products/open-source/shinyserver/).
If you have any questions about which product is the right fit for you, please email <a href="mailto:[email protected]">[email protected]</a>.

0 comments on commit c274048

Please sign in to comment.