Shiny Server Open Source (SSOS) - Introduction

Shiny Server Open Source download page: https://www.rstudio.com/products/shiny/download-server/

Shiny Server Open Source (SSOS) is the little brother of Posit Connect, similar as RStudio Server Open Source is to Posit Workbench.

SSOS is a free and AGPLv3 licensed web server optimized for hosting R content, especially Shiny apps. It uses NodeJS as the backend.

Compared to Posit Connect, SSOS lacks the following features:

This table by Posit gives a good overview comparing SSOS to Posit Connect and shinyapps.io, a hosted pay-as-you-go Posit Connect like service by Posit itself.

Our opinion

SSOS is great to explore the shiny web application framework. In addition, SSOS can suitable to host a limited number of shiny apps which are accessed infrequently and mainly used internally, i.e., in setups where developers have full control over the installation and maintainenance of the server. Due to the lack of access control and runtime configuration, SSOS quickly reaches practical limits in production scenarios. The lack of dynamic R package installations requires all R packages to be present upfront and being maintained externally which adds substantial administrative overhead. SSOS does not provide an overview of existing apps and requires the use of plain HTML to create such.

R Package Installation

SSOS does not install R packages required by apps on its own. Instead, the packages must be present within the R library of the shiny user, which is the user executing the content.

This results in the question: What is the best way, both for users and admins, to install the required R packages?

On the admin side, this is a complicated task, as the required packages change dynamically. A possible solution would be to pre-install commonly used packages during the image creation of SSOS. While this helps partially, it would not always cover all required packages.

A different approach we’ve built into our SSOS build is to scrape all library() calls of .R files within the shiny app directory during container startup. These are then being filtered for packages available on CRAN (as for others the location cannot be inferred directly) and installed in parallel via {pak}. Using Posit Package Manager binaries and parallel installation, this takes about 1 min for ~ 150 packages.

However, this task is only run once during startup and does not solve additional package requirements which are added by newly created shiny apps after startup. To account for this case, we encourage users to add the following R snippet into global.R of their respective Shiny app if the execution of Shiny app fails due to missing packages. This will do essentially the same as the startup command described above with the difference of being executed from within R and not invoked via bash (as it’s done during the container startup).

Adding this command to the Shiny app during startup will result in a small overhead to the app startup itself (the time it takes to execute the scraping command and checking if packages already exists in the R library). If this matters to you, we suggest to only include it once until all packages are resolved and then remove it again.

The command can only resolve CRAN packages. Private packages must be included within the Shiny image during built-time. If this hasn’t been done yet or you want to add a new custom package, please contact us.

pkgs=intersect(c(gsub("\"\"", "\"", gsub("^\"|\"$", "", system2("grep", c("-r", "-ho", "-P", "'library\\(\\K[^)]*'", ".", "|", "cut", "-d','", "-f1", "|", "sort", "--unique"), stdout = TRUE)))) ,available.packages()[, 'Package']); pak::pkg_install(pkgs)

Here is a breakdown of what the command does:

  1. Find all packages within library() calls below the current working directory
  2. Trim each result by the first comma (to ensure only the package name and no arguments to library() are returned)
  3. Sort the output and remove duplicates
  4. Quote all resulting names
  5. Replace duplicated quotes at the end or start of a package (e.g. "") with single occurences
  6. Remove leading and trailing quotes from vector
  7. Install the resulting packages via pak::pkg_install() (pre-installed in images)

Yes, the command is a one-liner on purpose and not easy to read. However, we prefer “copy/paste simplicity” here over readability, especially because the command should only be used selectively and removed again after all dependencies are installed.