By: Peter Solymos
Shiny Server is a free and open-source option for self hosting Shiny
apps and it is one of the 3 options listed on the Shiny
website. In a previous
post
you saw how to secure Shiny Server with a custom domain. Here you will
lear how to add and update Shiny apps to your server.
Follow the instructions from the previous post or spin up a brand new
virtual machine on DigitalOcean using the RStudio 1-click
app in minutes.
The index.html
file for the Shiny Server's landing page and the
hello
and rmd
apps are in the /srv/shiny-server/
folder:
$ ls /srv/shiny-server/
index.html sample-apps
$ ls /srv/shiny-server/sample-apps/hello
server.R ui.R
$ ls /srv/shiny-server/sample-apps/rmd
index.Rmd
These directories map to the server path as:
-
http://$HOST
is the landing page (index.html
), -
http://$HOST/sample-apps/hello/
is thehello
app, -
http://$HOST/sample-apps/rmd/
is thermd
app.
$HOST
is the custom domain (e.g. yourdomain.com
) your Shiny Server
server is using. You can see that the folder structure inside
/srv/shiny-server/
directly translates to the server paths. How do you
add more apps to the server? Just copy the Shiny apps directly into
folders within the /srv/shiny-server/
directory. Here are three
options for doing it.
Edit text files on the server
Let's add an app called histogram
to the http://$HOST/histogram/
path:
mkdir /srv/shiny-server/histogram
cd /srv/shiny-server/histogram
touch app.R
nano app.R
Copy-paste the Shiny app from below into app.R
that you just opened
with nano
(Ctrl+O to save, Ctrl+X to exit nano
):
library(shiny)
ui = fluidPage(
mainPanel(
sliderInput("obs",
"Number of observations",
min = 1,
max = 5000,
value = 100),
plotOutput("distPlot")
)
)
server = function(input, output) {
output$distPlot = renderPlot({
dist = rnorm(input$obs)
hist(dist,
col="purple",
xlab="Random values")
})
}
shinyApp(ui = ui, server = server)
Now if you visit http://$HOST/histogram/
you'll see a range slider
controlling sample size and a purple coloured histogram of a Normal
distribution that must be familiar from a previous
post.
Secure copy the files
You can use scp
to copy local files to the server. Let's create a
small Shiny app on your local machine. Use the same code as for the
purple histogram, but change some of the settings:
mkdir pink
touch pink/app.R
nano pink/app.R
Copy this code into the file pink/app.R
:
library(shiny)
ui = fluidPage(
mainPanel(
sliderInput("obs",
"Number of observations",
min = 1,
max = 1000,
value = 100),
plotOutput("distPlot")
)
)
server = function(input, output) {
output$distPlot = renderPlot({
dist = runif(input$obs)
hist(dist,
col="pink",
xlab="Random values")
})
}
shinyApp(ui = ui, server = server)
The following script copies the local pink
directory over to the
pinkhist
directory of the Shiny Server (this use of scp
assumes you
access the server using your ssh
key pair, otherwise you'll be
prompted to provide your username/password):
export APPDIR="pink"
export SHINYDIR="pinkhist"
scp -r $APPDIR root@$HOST:/srv/shiny-server/$SHINYDIR
Visiting the http://$HOST/pinkhist/
address should reveal the new app:
Note that the scp
protocol uses port 22 similarly to ssh
and sftp
.
If you are using the non-secure FTP protocol to copy the files, make
sure port 21 of your server is open for incoming traffic.
Git based deployment
Set up git
so you can work with your public and private repositories
(git
is already installed, this is a one-time setup for each user):
git config --global user.email "you@example.com"
git config --global user.name "Your Name"
Change to your home directory with cd ~
and run the following script.
This will clone the GitHub repository specified in the environment
variables, or pull changes if the directory already exists; then makes a
directory for Shiny Server if that directory is not already there, then
copies the app files ($APPDIR
can be empty):
#!/bin/bash
export GITHOST="https://github.com"
export GITUSER="analythium"
export GITREPO="covidapp-shiny"
export APPDIR="02-shiny-app/app"
export SHINYDIR="covidapp"
# clone or pull repo
if [[ ! -e $GITREPO ]]; then
git clone $GITHOST/$GITUSER/$GITREPO.git
else
cd $GITREPO
git pull
cd ..
fi
# make dir if not already there
mkdir -p /srv/shiny-server/$SHINYDIR
# copy repo contents to Shiny Server
cp -rf $GITREPO/$APPDIR/* /srv/shiny-server/$SHINYDIR
You can modify this script for other repositories and save in a file,
e.g. update_covid.sh
. Then you can run bash update_covid.sh
every
time you need the app to be updated. It is also possible to set up a
cron job to update the app daily
or tie the script to a webhook event triggered by a successful GitHub
action.
But before you do any of that, check if the app is running fine at
http://$HOST/covidapp/
. If all went wrong, you should see this
message:
This happened because the Shiny Server setup only included the most
basic R packages and we missed the forecast package required by the
COVID-19 app. Let's remedy this:
R -q -e "install.packages('forecast')"
If you refresh the page now the app should work fine.
This immediately highlights one of the shortcomings of Shiny Server when
it comes to continuous integration and delivery (CICD). You need to be
extra careful when managing packages, R and package versions, etc. when
you have multiple apps with possibly conflicting dependencies.
Dockerizing Shiny apps is one solution to isolate your applications.
License
R and the shiny R package are both licensed under the GNU General
Public License that permits
making a modified version and letting the public access it on a server
without ever releasing its source code to the public. However, it is
important to note that the open source version of Shiny Server is
licensed under the GNU Affero General Public
License (AGPLv3).
AGPL closes the application service
provider
(ASP) loophole and has a controversial reputation in tech circles, see
for example Google's
policy on banning
the license. We are not providing legal advice on this matter here,
merely stating what the license says:
The GNU General Public License permits making a modified version and
letting the public access it on a server without ever releasing its
source code to the public. The GNU Affero General Public License is
designed specifically to ensure that, in such cases, the modified
source code becomes available to the community. It requires the
operator of a network server to provide the source code of the
modified version running there to the users of that server. Therefore,
public use of a modified version, on a publicly accessible server,
gives the public access to the source code of the modified version. –
AGPLv3 Preamble
The interpretation of modified source code and public accessibility on a
server leaves a lot of room for interpretation (see some discussions
here)
which might or might not bother you depending on your intentions and
corporate environment. RStudio offers paid exception to the AGPL license
in the form of RStudio
Connect
– this model called dual-licensing (read about it
here).
Summary
The open-source Shiny Server is an easy way to self-host Shiny apps on a
low-cost virtual machine. You can set up the server yourself or use an
existing image and deploy apps in seconds. Some care must be taken with
dependencies, so it is good practice to use git
or do periodic backups
of the server to revert any breaking changes.
If you have followed this tutorial by spinning up your server that you
don't need any more, don't forget to destroy the server after you are
finished to avoid surprise billing.
Further reading
- The official Shiny Server docs
- Useful tips for logging and user permissions from Dean Attali
- Multiple users managing their apps on the same server
Top comments (0)