Shiny Server enables users to host and manage Shiny applications on the Internet. Shiny is an R package which uses a reactive programming model to simplify the development of R-powered web applications. Shiny Server can manage R processes running various Shiny applications over different URLs and ports. Using Shiny Server offers a variety of benefits over simply running Shiny in R directly. These features allow the administrator to:
Shiny Server is currently only supported on the Linux operating system. We officially support the following distributions:
We currently only support the x86-64 architecture. As described in the Installation section, you will install R and the Shiny package prior to installing Shiny Server. Root privileges will be required both in the installation process and also at runtime.
The Shiny Server installer does not come with R, nor does it provide the Shiny R package. Below are the steps for installing each of them separately.
If you had previously installed Shiny Server 0.3.5 from npm
, please see the section on [Upgrading from Shiny Server 0.3.5] before proceeding with the installation.
Installing R
Shiny Server requires an installation of R version 2.15.1 or higher. To install the latest version of R you should first add the CRAN repository to your system as described here:
You can then install R using the following command:
$ sudo apt-get install r-base
NOTE: if you do not add the CRAN Debian or Ubuntu repository as described above this command will install the version of R corresponding to your current system version. Since this version of R may be a year or two old it is strongly recommended that you add the CRAN repositories so you can run the most up to date version of R.
At this point, follow the instructions in Install Shiny to setup the necessary packages in R.
Once Shiny is installed, you can begin the installation of Shiny Server. You should have been provided with a .deb
installer for Shiny Server. If you only have a link to this file, you can use wget
to download the file to the current directory. You will need to first install the gdebi-core
package to install Shiny Server and its dependencies. Once the .deb
file is available locally, run the following commands to complete the installation of Shiny Server.
sudo apt-get install gdebi-core
sudo gdebi shiny-server-0.4.1.deb
Prerequisites
Shiny Server has several dependencies on packages (including R itself) found in the Extra Packages for Enterprise Linux (EPEL) repository. If you don't already have this repository available you should add it to your system using the instructions found here: https://fedoraproject.org/wiki/EPEL
After enabling EPEL you should then ensure that you have installed the version of R available from EPEL. You can do this using the following command:
$ sudo yum install R
At this point, follow the instructions in Install Shiny to setup the necessary packages in R.
Once Shiny has been installed, you can begin the installation of Shiny Server. You should have been provided with an RPM file which contains Shiny Server and all of its dependencies (other than R and Shiny). You can install this rpm file using yum
. If you have only a link to the RPM file, you can use wget
to download the file to the current directory.
$ sudo yum install --nogpgcheck shiny-server-0.4.1.rpm
This completes the installation of Shiny Server.
Before Shiny Server can be installed, the Shiny package must be installed in the system library; you typically need sudo
privileges to install to this library. Shiny Server currently requires Shiny version 0.7.0 or later. The following command will download and install the shiny
package from CRAN in the system library.
$ sudo su - \
-c "R -e \"install.packages('shiny', repos='http://cran.rstudio.com/')\""
Once this command completes, you can continue with the installation of Shiny Server.
The installer will automatically deploy the necessary scripts to ensure that Shiny Server is started automatically on boot. When possible, we use the Upstart system to manage the shiny-server
service. If Upstart is not available, we will deploy an init.d
script to automatically start and stop the service.
Upstart is a system used to automatically start, stop and manage services. The installer will automatically deploy an Upstart script to /etc/init/shiny-server.conf
. This script will initialize shiny-server
as soon as the network is activated on the machine and stop when the machine is being shut down. The Upstart script will also ensure that shiny-server
is respawned if the process is terminated for some reason.
To start or stop the server, run the following commands, respectively.
$ sudo start shiny-server
$ sudo stop shiny-server
To restart the server, you can run:
$ sudo restart shiny-server
If you wish to keep the server and all Shiny processes running without interruption, but reload the configuration, you can use the reload
command as in:
$ sudo reload shiny-server
This will cause the server to re-read the configuration file but will not interrupt the current processes and outstanding connections to the server.
Known Bug: Due to a bug in the version of Upstart which comes with Ubuntu 13.04, reload
will not behave as expected on that platform and should not be used.
To check the status or retrieve the Process ID associated with shiny-server
, run the following:
$ status shiny-server
On some older Operating Systems (such as RedHat 5) the Upstart system may not be available. These systems will require the use of a script in /etc/init.d/
to start and manage the shiny-server
daemon. This script does not have the capability to automatically restart the shiny-server
daemon if it terminates unexpectedly. The installer uses chkconfig
to ensure that shiny-server
will start automatically on boot.
To start or stop the server, use the following commands, respectively:
$ sudo /sbin/service shiny-server start
$ sudo /sbin/service shiny-server stop
To restart the server, you can run:
$ sudo /sbin/service shiny-server restart
If you wish to keep the server and all Shiny processes running without interruption, but reload the configuration, you can use reload
:
$ sudo /sbin/service shiny-server reload
This will cause the server to re-read the configuration file but will not interrupt the current processes and outstanding connections to the server.
To check the status or retrieve the Process ID associated with shiny-server
, run the following:
$ /sbin/service shiny-server status
Initially, Shiny Server uses the following configuration file. Some users will find that this configuration meets their needs; others may find it useful to create a custom configuration. Details about each available setting and parameter are available in the Appendix. As a brief introduction, however, the following configuration file is the default used if no other configuration file is provided:
# Define the user we should use when spawning R Shiny processes
run_as shiny;
# Define a top-level server which will listen on a port
server {
# Instruct this server to listen on port 3838
listen 3838;
# Define the location available at the base URL
location / {
# Run this location in 'site_dir' mode, which hosts the entire directory
# tree at '/srv/shiny-server'
site_dir /srv/shiny-server;
# Define where we should put the log files for this location
log_dir /var/log/shiny-server;
# Should we list the contents of a (non-Shiny-App) directory when the user
# visits the corresponding URL?
directory_index on;
}
}
Lines beginning with a #
are treated as comments and not parsed when configuring the server. Shiny Server can be configured to host multiple server
s on different ports or hostnames. Each server
can have location
s which are capable of serving Shiny Applications and potentially static assets, as well. Individual applications can also override the settings applied to their parent location
. These concepts are explained in further detail in the Server Hierarchy section. The default configuration above will create a single server listening on port 3838, serving any application contained within /srv/shiny-server/
at the root URL (/
). Each possible setting in the configuration file is explained in the Appendix.
Most users will want to customize the configuration to meet their needs. The server will attempt to load its configuration from a file stored at /etc/shiny-server/shiny-server.conf
; it is in this location that you should place your custom Shiny Server configuration. If this file is not found, the default will be used.
Detailed descriptions of all available parameters are available in the appendix, but it is important to understand the overall hierarchy of the Shiny Server configuration file when editing the file.
The server setting defines an HTTP server which will listen on a port/IP address combination. For example, the following lines:
server {
listen 80;
}
define a server that would listen on port 80. A server can also define a server_name
to limit the virtual hostnames on which it listens, as described in the Virtual Hosts section.
The location
setting is defined within a server
and defines how a particular URL path should be served. For instance, the following settings:
server {
...
# Define the location '/specialApp'
location /specialApp {
# Run this location in 'app_dir' mode, which will host a single Shiny
# Application available at '/srv/shiny-server/myApp'
app_dir /srv/shiny-server/myApp
}
# Define the location '/otherApps'
location /otherApps {
# Run this location in 'site_dir' mode, which hosts the entire directory
# tree at '/srv/shiny-server/apps'
site_dir /srv/shiny-server/apps;
}
...
}
would define two locations, one which serves (potentially) a multitude of applications at the URL /otherApps/
, and another which serves a single application at the URL /specialApp/
.
The various hosting models which can be applied to a location are described in the section on Hosting Models.
The
application
setting has been deprecated and will be removed in subsequent versions of Shiny Server.
The application
block is specified within a location
and defines the settings related to a particular application. The application is referenced by the directory in which it is stored. For example, the following configuration could be used to modify the application housed at /srv/shiny-server/app1
.
...
location / {
# Define rules to apply to one application, stored at '/srv/shiny-server/app1'
application /srv/shiny-server/app1 {
simple_scheduler;
}
}
...
This block would specify that, within this location
, the referenced application should use the Simple Scheduler. This setting would have no effect on the other applications hosted in this location
block.
run_as
Understanding which user will execute the R Shiny processes is important for a variety of reasons. For one, the paths in which R will look for packages (.libPaths()
) are often user-dependent. In order to ensure that the libraries required to run a Shiny application are installed, you must first understand which user will be running the application. Additionally, directories will likely have restrictions regarding which users are able to read or write in them. The server should be configured in such a way that the user running the Shiny applications has the minimal privileges to do the work required by those applications.
location
s configured with user_apps
will be executed as the user in whose home directory the application was found. For locations configured with site_dir
and app_dir
, the run_as
setting will be used to determine which user should spawn the R Shiny processes. This setting can be configured globally, or for a particular server
or location
. For example, the following configuration:
location / {
run_as tim;
}
would execute all applications contained within this scope as the user tim
with all of tim
's relevant .libPath
s.
In order to spawn processes as other users (as is required in the user_apps
scenario), shiny-server
must be run as root
. For configurations not requiring user_apps
, shiny-server
can be executed as any user, as long as the user specified in run_as
does not conflict.
In the global configuration file, the allow_app_override
setting can be specified to enable local app configurations. If present, this setting enables owners of Shiny applications to customize the properties of their own applications using a file named .shiny_app.conf
. This file can be placed within an application directory (alongside the server.R
and ui.R
files) and can contain any setting permitted within an application
block.
This behavior is controlled by the allow_app_override
setting which is disabled by default. In order to enable local application configurations, you can add to your configuration file allow_app_override true;
(or just allow_app_override;
for short).
Server administrators should be mindful of the fact that allowing application owners to specify their own scheduler parmeters has potential performance implications, as an application owner could enable his or her application to consume more resources than is desired. It is thus recommended that write privileges on the .shiny_app.conf
files be granted judiciously in the underlying filesystem.
There are currently four different methods of configuring a location, three of which serve Shiny applications. These three are described below; see the following section on Redirecting to learn about a fourth mode.
A location which uses site_dir
will host an entire directory tree -- both Shiny Apps and static assets. This is the location used to serve an asset or application in /srv/shiny-server/
in the default configuration that ships with Shiny Server.
# Define the location '/'
location / {
site_dir /srv/shiny-server/
}
The above configuration would instruct Shiny Server to make the /srv/shiny-server/
directory available at the base URL. Any Shiny applications stored in this directory (or any subdirectory), along with any static assets (including images, data, JavaScript/CSS files, etc.) will be made available at the corresponding URL. For example, see the following directory tree:
+---/srv/shiny-server
| +---shinyApp1
| +---server.R
| +---ui.R
| +---shinyApp2
| +---server.R
| +---ui.R
| +---assets
| +---style.css
| +---script.js
If this server were available at http://server.com
, the location
settings above would make the following (along with any other file in the tree) publicly available to the user.
URL | Definition |
---|---|
http://server.com/shinyApp1 |
Serve the Shiny App defined in 'shinyApp1' |
http://server.com/shinyApp2 |
Serve the Shiny App defined in 'shinyApp2' |
http://server.com/assets/style.css |
Serve this static CSS file |
http://server.com/assets/script.js |
Serve this static JS file |
A location configured to use app_dir
will attempt to serve a single application hosted at the given directory. For instance,
# Define the location '/specialApp'
location /specialApp {
app_dir /srv/shiny-server/myApp;
}
will configure the location
responsible for the path /specialApp
to use this app_dir
router which serves a single application stored in the directory /srv/shiny-server/myApp
. This configuration would presume a server.R
file (and corresponding ui.R
file) would be available at /srv/shiny-server/myApp/server.R
. If so, the application saved there would be available at a URL like http://server.com/specialApp
.
A location configured to use user_apps
will allow users on the system to create and manage their own Shiny applications available in their home directories. This directive will host any application stored in an eligible user's ~/ShinyApps
directory publicly at a URL prefaced by their username.
This privilege can be restricted only to users of particular groups using the members_of
restriction. For instance, the following configuration:
# Define the root location
location / {
user_apps;
# Only allow members of the 'shinyUsers' group to host personal applications.
members_of shinyUsers;
}
will -- for any user who is a member of the shinyUsers
group -- publicly host any Shiny application available in the user's ~/ShinyApps
directory. For instance, if tina
is a user on this system and is also a member of the shinyUsers
group, any application stored in /home/tina/ShinyApps/
, such as the shinyApp1
application, would be available on this server at a URL like http://server.com/tina/shinyApp1
, assuming /home/tina
was tina
's home directory.
The final mode in which a location can operate is to redirect to another URL. Such locations will immediately send a response to the client informing them of the URL to which they should redirect and the status code that should be used when informing the client of the redirection. Typically, a redirect will use the 301
status code for a permanent redirect, or a 302
status code for a temporary redirect. The final option when configuring a location for redirection is whether or not it should use exact matching. If a redirecting location is configured to use exact matching, only requests for that exact URL will be redirected. If not, any requests for that URL path or any subpath of that URL will be redirected. For example,
# Define a location at the base URL of this 'server'
location / {
# Redirect traffic from '/shinyApp1/' to 'http://server.com' temporarily.
redirect /shinyApp1 {
redirect "http://server.com" 302 true;
}
}
will redirect any requests for the exact path /shinyApp1
to http://server.com
temporarily.
The server_name
setting allows Shiny Server to route incoming requests to a particular server
element based on the hostname of the request. This will serve as an additional level of filtering on incoming traffic. Bear in mind that traffic must be destined for this server (i.e. traffic which was bound for the IP address and port on which this server was listening) in order to even be evaluated for a matching hostname.
The example below may clarify the configuration
server {
# Instruct this server to listen to port 80
listen 80;
# Only accept requests for the hostname 'server1.com'
server_name server1.com;
# Define the location for this server.
location / {
site_dir /srv/shiny-server1;
log_dir /var/log/shiny-server1;
}
}
server {
# Instruct this server to listen to port 80
listen 80;
# Only accept requests for the hostname 'server2.com'
server_name server2.com;
# Define the location for this server.
location / {
site_dir /srv/shiny-server2;
log_dir /var/log/shiny-server2;
}
}
This example presupposes that, on this network, the domains server1.com
and server2.com
both resolve to the same IP address. In the configuration above, we first create a server that listens on port 80
and will only accept traffic whose hostname matches server1.com
. We then configure a server which will also listen on port 80
and require that it only accept traffic whose hostname equals server2.com
.
This configuration would allow an application stored in /srv/shiny-server1/shinyApp
to be accessible at http://server1.com/shinyApp
and an application stored in /srv/shiny-server2/shinyApp
to be accessible at http://server2.com/shinyApp
.
All information related to Shiny Server, rather than a particular Shiny application, is logged in the global system log stored in /var/log/shiny-server.log
. This log should be checked often to ensure Shiny Server is performing as expected. Any errors and warnings which Shiny Server needs to communicate will be written here.
An access log can be configured globally using the acces_log
parameter. This log is not enabled by default. This setting controls the location of the access log as well as the format used. The access log can be useful to audit the security and activity taking place on your Shiny Server installation. These logs can be audited manually or automatically to inspect how often various resources are being accessed, or by whom they are being accessed (using the originating IP address). Currently, one access log is created for the entire Shiny Server process; all Shiny applications share this access log.
The access logs will be written using the Connect logging libraries, so additional details can be found in their documentation in the "Formats" section. In brief, there are four pre-defined logging formats for access logs specified in the documentation referenced above:
default
':remote-addr - - [:date] ":method :url HTTP/:http-version" :status :res[content-length] ":referrer" ":user-agent"'short
':remote-addr - :method :url HTTP/:http-version :status :res[content-length] - :response-time ms'tiny
':method :url :status :res[content-length] - :response-time ms'dev
concise output colored by response status for development useFor example, the following would configure an access log that uses the tiny
format:
access_log /var/log/shiny-server/access.log tiny;
server {
...
We strive to expose most settings through the configuration file described previously. However, there are some settings that we don't include in the configuration file which some users may still wish to change. Where possible, we'll allow users to configure these settings using environment variables. Some of these environment variables will later be promoted to configuration directives, but will be documented here until that time.
Typically, it is best to define these environment variables in the startup script used to run Shiny Server (often either /etc/init.d/shiny-server
or /etc/init/shiny-server.conf
, depending on whether or not you're using Upstart).
SHINY_LOG_LEVEL
Defines the verbosity of logging which will be used by Shiny Server. Valid options -- in level of increasing verbosity -- are TRACE
, DEBUG
, INFO
, WARN
, and ERROR
. More verbose levels of logging (such as TRACE
) may be helpful when debugging an issue or trying to understand exactly what Shiny Server is doing, but will likely be far too much information for a system with even moderate load.
The default if this environment variable is not found is to use INFO
.
R
Defines the path to the R executable which should be used when running Shiny. Systems which have multiple versions of R installed, or don't wish to place R on the path before starting Shiny Server can override this setting to point to a particular version of R.
If no environment variable is found, Shiny Server will expect an executable named R
to be on the path.
A scheduler is responsible for fulfilling incoming requests to a particular application. Each version of an application (see below) will have its own associated scheduler. Each scheduler can have different properties to control things like how many concurrent connections it should accept.
A scheduler can be specified at many locations in the configuration file and will be inherited to inner blocks. For instance, a scheduler definition found in a server
block will be applied to every location
and application
in that server
, unless overridden.
Some changes you make to the code, assets, or environment of an application will require the application's R processes to be restarted for the changes to take effect. These include upgrades to packages that are used by the application, changes to .Renviron
/.Rprofile
or other R source files, or modifications to data files that are read only at startup time.
(Fortunately, Shiny applications generally do not need to be restarted when changes to ui.R
or server.R
are made, as Shiny will check for changes to these files on page load.)
An application can be restarted by altering the "modified time" on a file named restart.txt
in the application's directory. This can most easily be done using the touch
utility as in touch restart.txt
which will update the modified timestamp on this file to the current time. Upon the next new connection to the application, Shiny Server will spawn a new R process to run the "new" (restarted) Shiny Application for this and future users. When this occurs, the old processes will remain unaltered, and open connections will remain active and valid until the last connection closes itself.
This can cause unintuitive consequences regarding the number of processes that may be running for a given application. Even if using a single-process Simple Scheduler for an application, it is possible that there would be multiple R processes associated with this application, each corresponding to a separate restart timestamp. This behavior is likely to change in future versions of Shiny Server.
The Simple Scheduler is the only scheduler available in the Open Source edition of Shiny Server. It associates a single R process with a single Shiny application. This scheduler accepts a single parameter which specifies the maximum number of concurrent sessions. Once this number is reached, users attempting to create a new session on this application will receive a 503 error page.
# Define a new location at the base URL
location / {
# Define the scheduler to use for this location
simple_scheduler 15;
...
}
In this example, the location
defined at the base URL in this server
will be configured to use the Simple Scheduler and to limit each application to a maximum of 15 simultaneous connections -- meaning that if there are 15 active connections on the application when a user attempts to visit this application, that user will receive a 503 error page. When one of the 15 active connections is disconnected, one new "seat" will be available for another user to connect to the application.
Each Shiny Application has two timeouts associated with it:
app_init_timeout
-- Describes the amount of time (in seconds) to wait for an application to start. After this many seconds if the R process still has not become responsive, it will be deemed an unsuccessful startup and the connection will be closed.app_idle_timeout
-- Defines the amount of time (in seconds) an R process with no active connections should remain open. After the last connection disconnects from an R process, this timer will start and, after the specified number of seconds, if no new connections have been created, the R process will be killed.Typically, these two parameters will be correlated. Shiny Applications which involve little processing to start (therefore have a small app_init_timeout
) can often be closed with minimal concern (thus would have a small app_idle_timeout
). Conversely, applications which require a substantial amount of data to be loaded on startup may merit a longer app_init_timeout
to give the data time to load, and a longer app_idle_timeout
as the task of spawning a new process is more expensive and should be minimized.
Error logs are created for each R Shiny process separately. For locations configured to use user_apps
, these logs are created in each user's ~/ShinyApps/log/
directory. For location
s configured with app_dir
or site_dir
, the directory in which these logs are created is managed by the log_dir
setting, which can be specified globally, for a particular server
, or for a particular location
. For these location
s, the log_dir
can be specified in the following way:
location / {
log_dir /var/log/shiny-server/;
}
The log files will be created in the following format:
<application directory name>-YYYMMDD-HHmmss-<port number or socket ID>.log
Log files will be created for each R process when it is started. However, if a process closes successfully, the error log associated with that process will be automatically deleted. The only error log files that will remain on disk are those associated with R processes that did not exit as expected.
Shiny Server is capable of automatically inserting the necessary JavaScript code to enable Google Analytics tracking globally or for a particular server
or location
. This is managed by the google_analytics_id
setting which can be used as follows:
location / {
google_analytics_id UA-12345-1;
}
The reactivity log is a great browser-based tool for analyzing and debugging reactive dependencies in a Shiny Application. We strongly recommend that you read the Overview of Reactivity in the Shiny tutorial to get the most out of the reactivity log. The symbols and representations introduced in that article are reused in the log. This tool should not be used in a production environment, as it exposes details that should not be publicly available. Many application authors find it to be a useful tool to use locally, however.
Currently, reactivity logs are maintained for an entire R process. Therefore, it should be used in a fresh R session in which only one Shiny application is active. To enable the reactivity log, run the command options(shiny.reactlog=TRUE)
before running your application. Once you've started your application and are viewing it in a browser, you can use Ctrl+F3
(or Command+F3
for Mac users) to view the reactivity log. This visualization creates a snapshot of all reactive activity that had occurred up to the moment it was created. If you want to view the reactive activity that has occurred since opening the reactivity log, you'll need to refresh the browser.
The showReactLog()
function exposes this functionality from within R and can be used outside of strictly Shiny contexts to generate a static HTML file visualizing reactivity. You can see the full documentation using ?showReactLog
in R.
As the reactivity log exposes the architecture and some of the code behind your application, it would likely be unwise to enable this feature in a production environment. Unless explicitly enabled by the user, Shiny Server will not enable this functionality. We recomend using the reactivity log in a local R process not managed by Shiny Server.
Shiny Server 0.4 includes many major changes to the architecture of Shiny Server. There are a few things to be aware of when upgrading from Shiny Server 0.3.x.
First, Shiny Server is now distributed via deb
and rpm
installers, rather than using npm
. Thus, you'll first want to uninstall the old version of Shiny Server which was installed from npm
.
$ sudo npm uninstall -g shiny-server
Shiny Server no longer requires node.js to be installed on the system either. If you have no other need for node.js, you can uninstall it at this time, as well.
Running the Shiny Server 0.4 installer will replace the scripts at /etc/init/shiny-server.conf
or /etc/init.d/shiny-server
. If you have made any modifications to these startup scripts that you wish to keep, please save a copy of these files before running the installer.
The default directories for logging and Shiny application hosting have also moved in this release. The default logging directory used to be /var/shiny-server/log
, it is now /var/log/shiny-server
. The default hosting directory was previously /var/shiny-server/www
and is now /srv/shiny-server/
. If you have not explicitly overridden these directories in the /etc/shiny-server/shiny-server.conf
file, the new location will be created and used in Shiny Server 0.4.
Finally, Shiny Server 0.4 now requires the Shiny package to be at least version 0.7.0. You can check the system-wide version of Shiny you have installed using the following command on the command line.
$ sudo su - -c "R -e \"packageVersion('shiny')\""
(Running this command using the sudo su - -c
preface will allow you to see the system-wide version of Shiny. Individual users could have installed more recent versions of Shiny in their own R libraries.) If the installed version of Shiny predates 0.7.0, you should follow the instructions in Install Shiny to update to the most recent version.
At this point, you can proceed with the Installation instructions associated with your Operating System.
The performance footprint of a Shiny application is almost entirely dependent upon the Shiny application code. There are two factors to consider when selecting the hardware platform for Shiny Server.
RAM
The memory requirements of a Shiny application depend heavily on the data loaded when running the application. Often users find that a Shiny R process requires a minimum of 50MB of RAM -- beyond this, the amount of memory consumed by an application is determined by the data loaded or generated by that application. The Scoping Section of the Shiny Tutorial describes in detail how to take advantage of Shiny's scoping rules to share data across multiple Shiny sessions. This enables application developers to load only one copy of data into memory but still share this data with multiple shiny sessions.
CPU
R is fundamentally a single-threaded application. Unless parallel packages and tools are specifically selected when designing a Shiny application, the average R process (and the associated Shiny application) will be run serially on a single processing core. Thus, the typical Shiny application may saturate the processing core to which it's assigned, but will be unable to leverage other cores on the server which may be idle at that time.
Absolutely. Many customers deploy Shiny Server and Shiny Server Professional on the Amazon Web Services (AWS) framework.
Of course. Shiny Server does not require a connection to the Internet in order to work properly, so you are free to deploy it in whatever sort of network configuration you would like. Offline activation is also available for Shiny Server Professional customers.