FAQ

Container did not respond in time

If you see the following error message in your browser

Error
Status code: 500
Message: Container did not respond in time

it is very likely that your container was started, but that the Shiny app itself could not be started properly.

This almost always means an R error is triggered when docker is trying to launch the Shiny app.

Typical examples are:

  • some dependencies for your Shiny application were not installed into the Docker image and therefore could not be loaded when you run your application
  • you are using non-exported functions from a package and this triggers an error
  • any other R error that is triggered prior to the proper loading of your Shiny application

The best way to pinpoint the origin of the problem is to launch the docker container ‘manually’ i.e. independently of ShinyProxy and see whether or not this succeeds.

By means of example, let’s assume the hello application of the openanalytics/shinyproxy-demo image does not work properly. In the default application.yml we can see that it is being run using

  specs:
  - id: 01_hello
    container-cmd: ["R", "-e", "shinyproxy::run_01_hello()"]
    container-image: openanalytics/shinyproxy-demo
    access-groups: [scientists, mathematicians]

In other words, the docker command (container-cmd) used is ["R", "-e", "shinyproxy::run_01_hello()"].

In order to run it ‘manually’ (using the docker command line interface) we can do the following:

sudo docker run -p 3838:3838 openanalytics/shinyproxy-demo R -e 'shinyproxy::run_01_hello()'

and this will generate the following output:

R version 3.2.4 Revised (2016-03-16 r70336) -- "Very Secure Dishes"
Copyright (C) 2016 The R Foundation for Statistical Computing
Platform: x86_64-pc-linux-gnu (64-bit)

R is free software and comes with ABSOLUTELY NO WARRANTY.
You are welcome to redistribute it under certain conditions.
Type 'license()' or 'licence()' for distribution details.

  Natural language support but running in an English locale

R is a collaborative project with many contributors.
Type 'contributors()' for more information and
'citation()' on how to cite R or R packages in publications.

Type 'demo()' for some demos, 'help()' for on-line help, or
'help.start()' for an HTML browser interface to help.
Type 'q()' to quit R.

> shinyproxy::run_01_hello()
Loading required package: shiny

Listening on http://0.0.0.0:3838

No errors in this output, but we can see exactly what happens inside the R session. This trick can come handy if you have real errors that prevent your Shiny app to come online!

Failed to start container

If you see the following error message in your browser

Error
Status code: 500
Message: Failed to start container: Request error: POST http://localhost:2376/containers/d3e0f4c02d72f71b9619e5b70a60aa1000ae5498a3743255e9afeb9ae5cbb14b/start: 500

it is very likely that shinyproxy was not able to start the container.

The first thing to check is whether the docker daemon is running. On Ubuntu 14.04 this can be done using

$ sudo service docker status
docker start/running, process 21167

When the docker service is up and running, the most common cause is that the firewall rules on the machine prevent ShinyProxy to connect to the docker API. In that case, it is worthwhile to disable the firewall temporarily and to check whether ShinyProxy is then able to start a container.

Address already in use

If you see the following information when launching ShinyProxy (e.g. in the shinyproxy.log file)

Exception in thread "main" java.lang.RuntimeException: java.lang.reflect.InvocationTargetException
at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:62)
at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)

[...]

Caused by: java.net.BindException: Address already in use
at sun.nio.ch.Net.bind0(Native Method)
at sun.nio.ch.Net.bind(Net.java:433)
at sun.nio.ch.Net.bind(Net.java:425)

[...]

this will in all likelihood mean that another application (e.g. a Tomcat application server) is already running on port 8080, the default port ShinyProxy uses.

You can either stop the other application prior to launching ShinyProxy or use a custom port (e.g. 9999) for ShinyProxy by editing the port field in the application.yml file:

proxy:
  # ...
  port: 9999

For more details, see the General section of the Configuration page.

Uploading big files does not work

Before ShinyProxy 2.4.0, this documentation contained some information about how to configure file upload using multipart properties. Starting from ShinyProxy 2.4.0 this configuration is no longer needed and should be removed, since this version does not have any restrictions on the size of file uploads. Hence, the following code should be removed from your configuration:

# Do not add this to your configuration!
spring:
  servlet:
    multipart:
      max-file-size: <value>
      max-request-size: <value>

Login does not work after upgrading from 2.3.0

If you are using custom templates (using the proxy.template-path property) and upgrade from ShinyProxy 2.3.0 to 2.3.1 or later you can face this issue. Since ShinyProxy 2.3.1, CSRF protection is enabled and therefore an update of the login template is needed.

In the login.html template replace this line:

<form class="form-signin" action="login" method="POST">

by

<form class="form-signin" th:action="@{/login}" method="POST">

The issue should now be solved.

Is it possible to run Desktop Apps?

Yes! We have an extensive demo setup containing of two desktop apps: Phaedra and Visual Studio Code. All information can be found in the repository.

The credentials of the user expire when using SAML

By default SAML credentials are valid for a certain amount of time. This also means that those credentials have an “age’. When a user tries to login into ShinyProxy it could be possible that the IDP still has some valid (i.e. not expired) credentials for this user. In that case the IDP may provide these existing credentials to ShinyProxy. When validating these credentials, ShinyProxy checks the age of the credentials to make sure these are not too old. By default ShinyProxy rejects credentials that are older than two hours. However, the IDP is unaware of this restriction and thus may provide ShinyProxy credentials that are older than these two hours.

If you are experiencing this problem, the user is faced with a page that contains a stacktrace containing the following error:

org.springframework.security.saml.SAMLStatusException: Response has invalid status code urn:oasis:names:tc:SAML:2.0:status:Responder, status message is null

In the ShinyProxy log the following errors are logged:

org.springframework.security.authentication.CredentialsExpiredException: Authentication statement is too old to be used with value ...

There are two ways to solve this:

  • enable the proxy.saml.force-authn property. This option ensures that ShinyProxy asks the IDP to provide fresh credentials, even if the IDP believes the credentials are still valid. We have good experience with this option using Microsoft ADFS and Microsoft Azure AD. However, the downside of this option is that the user may have to refill their username and password, even if they are still logged in.

    Note: it seems that some IDPs ignore this option, e.g. Google ignores it.

  • set the proxy.saml.max-authentication-age option to a value greater or equal to the maximal age of the credentials provided by the IDP. This value is specified in seconds. This has the advantage that the user is not forced to refill their username and password.

How do I create a keystore for signing SAML messages?

By default SAML messages sent by ShinyProxy are not signed. However, the SAML standard makes it mandatory that an application signs the messages used to sign-out a user. Therefore, when you use the SAML Logout feature, you must provide ShinyProxy with a keystore. When your IDP encrypts the SAML messages, you already have a keystore and should not create a separate one. In the other case you do have to create a new keystore. This section describes the process of generating such a keypair, using the keytool utility included in Java.

The tool can be used as follows:

keytool -deststoretype pkcs12 \
  -genkeypair \
  -keyalg RSA \
  -keysize 4096 \
  -sigalg SHA256withRSA \
  -validity 1460 \
  -alias shinyproxy-saml \
  -keypass changeme \
  -keystore samlKeystore.jks
  • validity: how long the certificate is valid, specified in days. In the example this is about 4 years.
  • keyalg: use RSA instead of DSA (note: DSA does not work for ShinyProxy, EC may not work with Active Directory products)
  • keysize: use sensible keysize
  • sigalg: use a secure signature algorithm
  • alias: a name for your keypair
  • keypass: the password used to encrypt the private key
  • keystore: the filename of the keystore

The tool now aks to provide a password for the complete keystore after which it asks for some attribute to specify in the certificate. In theory, all these values are optional. You could specify your domain name as the value for the first attribute (common name) in order to easily identify the certificate.

If you wish you can now export the certificate and inspect it (e.g. to verify the remaining lifetime):

keytool -exportcert -alias shinyproxy-saml -keystore samlKeystore.jks -rfc -file cert.pem
openssl x509 -noout -text -in cert.pem

In order to configure ShinyProxy to use this keystore, use:

proxy:
  saml:
    keystore: /path/to/samlKeystore.jks
    keystore-password: changeme # the password you provided when the keytool asked for it
    encryption-cert-password: changeme # the password provided after the keypass parameter of the keytool
    encryption-cert-name: shinyproxy-saml # the alias of the certificate

The assets of my Shiny app sometimes fail to load (HTTP error 503)

This issue is most likely caused by bug in a library used by the HTTP server used by the Shiny package. This library validates that the header size of an incoming HTTP request is not too big. However, it seems that this validation is not 100% correct, especially when the TCP connection is re-used for multiple HTTP requests. Fortunately, it is possible to disable this validation, by providing a build parameter when installing Shiny.

In order to disable the check, install Shiny using the following snippet in your Dockerfile:

RUN R -e "install.packages(c('withr'), repos='https://cloud.r-project.org/')"
RUN R -e "withr::with_makevars(c(PKG_CPPFLAGS='-DHTTP_MAX_HEADER_SIZE=0x7fffffff'), {install.packages(c('shiny'), repos='https://cloud.r-project.org/')}, assignment = '+=')"

Note: disabling this validation does not introduce any security issues, when running the Shiny app using ShinyProxy, since ShinyProxy contains the same validation. (however, since the check is disabled there will be no check when running the app standalone.)

References:

How to embed ShinyProxy using an iframe on a different domain?

It is possible to embed ShinyProxy using an iframe in the same way as any website, however, when this iframe is hosted on a different domain (or origin), this requires some extra configuration of the security features of ShinyProxy. In addition, it is required that ShinyProxy is accessed over a secure connection (HTTPS). Note that these settings require ShinyProxy 2.6.0 or later.