Configuration
Overview
The server configuration is mainly done in a file named application.yml
. If the default values must be overridden, this can be done by adding a file application.yml
in the same folder where you launch the shinyproxy-*.jar
file and specify properties in the YAML format. The standard configuration has the following values:
proxy:
title: Open Analytics Shiny Proxy
logo-url: https://www.openanalytics.eu/shinyproxy/logo.png
landing-page: /
heartbeat-rate: 10000
heartbeat-timeout: 60000
port: 8080
authentication: ldap
admin-groups: scientists
# Example: 'simple' authentication configuration
users:
- name: jack
password: password
groups: scientists
- name: jeff
password: password
groups: mathematicians
# Example: 'ldap' authentication configuration
ldap:
url: ldap://ldap.forumsys.com:389/dc=example,dc=com
user-dn-pattern: uid={0}
group-search-base:
group-search-filter: (uniqueMember={0})
manager-dn: cn=read-only-admin,dc=example,dc=com
manager-password: password
# Docker configuration
docker:
cert-path: /home/none
url: http://localhost:2375
port-range-start: 20000
specs:
- id: 01_hello
display-name: Hello Application
description: Application which demonstrates the basics of a Shiny app
container-cmd: ["R", "-e", "shinyproxy::run_01_hello()"]
container-image: openanalytics/shinyproxy-demo
access-groups: [scientists, mathematicians]
- id: 06_tabsets
container-cmd: ["R", "-e", "shinyproxy::run_06_tabsets()"]
container-image: openanalytics/shinyproxy-demo
access-groups: scientists
logging:
file:
name: shinyproxy.log
General
The first block of configuration in the application.yml
file concerns general configuration values for the ShinyProxy application:
title
: title that is displayed in the ShinyProxy navigation bar;logo-url
: url of the logo that is displayed in the ShinyProxy navigation bar; this can also be a local file using the file scheme (file://
)favicon-path
: path to the favicon file to be used by ShinyProxy; both relative (to the working directory of ShinyProxy) and absolute paths can be used;landing-page
: the URL to send a user to after login; default value is/
which will redirect the user to a list of the Shiny apps. Other typical values are/app/<app-name>
or/app_direct/<app-name>
which allows to immediately land on a (single) Shiny app;heartbeat-rate
: the user’s browser will sent a heartbeat call everyheartbeat-rate
milliseconds; default value is10000
(10 seconds);heartbeat-timeout
: if the server does not receive a heartbeat forheartbeat-timeout
milliseconds, the relevant proxy will be released (and the container stopped); default value is60000
(60 seconds);bind-address
: a hostname or IP address to be used as bind address for ShinyProxy; default value is0.0.0.0
(all interfaces);port
: port to be used by ShinyProxy; the default port is8080
;template-path
: optional path that can be set to customize the landing page (listing of the apps) of ShinyProxy; it refers to the folder that contains theindex.html
page and all assets needed to serve the custom landing page; for more detail see the example configuration on Github;authentication
: authentication method; one ofldap
(default),kerberos
,keycloak
,openid
,saml
,social
,simple
ornone
; see the relevant section below for configuration details regarding each of these authentication methods;admin-groups
: one or more groups (as defined in the authentication back-end) that have access to the administrative interface of ShinyProxy e.g. to view and manage active sessions; multiple groups are enclosed in square brackets and separated by commas.
Besides the basic configuration options described above, there are also some more advanced configuration options that are not part of the default configuration:
container-wait-time
: timeout for the container to be available to ShinyProxy; defaults to 20s (20000
):
proxy:
[...]
container-wait-time: 20000
Note that a container is considered to be ‘available’ if its HTTP listener responds with status 200.
hide-navbar
: boolean; if set totrue
the navigation bar at the top will be hidden; this may be useful when ShinyProxy is deployed as part of larger applications
Note:
- ShinyProxy will run by default on the ‘/’ context path; the context path can
be configured using a
server.servlet.context-path
setting that should always start with a leading slash (as in/abcd
):
server:
servlet:
context-path: /abcd
Authentication
Note:
-
To establish a TLS connection between Shinyproxy and the authentication server (such as Keycloak), you should configure the Shinyproxy with a Trust Store containing the certificates of the target authentication server. Please refer to https://docs.oracle.com/cd/E19906-01/820-4916/geygn/index.html for details.
-
However, if the Shinyproxy is connecting with the authentication server over plain HTTP it’s not necessary to add certificates in the Trust Store e.g. if both Shinyproxy and Keycloak are in a Kubernetes cluster, there is no need for TLS between them.
LDAP
When using LDAP authentication, ShinyProxy will use the provided LDAP url to:
- Authenticate users by attempting to bind with their login name and password.
- Authorize users to access apps by searching for any LDAP groups they are a member of, and matching those group names to the list of group names configured for the app.
With the default values (authentication: ldap
), authentication will be done against the LDAP server at ldap.forumsys.com; to log in one can use the user name “tesla” and password “password”.
In order to use it with your own LDAP directory, you can use the following fields:
url
: the LDAP connection string, composed of the URL and base DN of the LDAP directory;user-dn-pattern
: pattern of the distinguished name for a user. Use this if all your users are in a single LDAP location;user-search-filter
: LDAP filter to search for users. Use this if your users are in different LDAP locations, and you cannot useuser-dn-pattern
;user-search-base
: search base to search for users. Only used ifuser-search-filter
is set;group-search-filter
: LDAP filter used to search for group memberships;group-search-base
: search base to search for groups. Only used ifgroup-search-filter
is set;manager-dn
: the distinguished name of the user used to bind to the LDAP directory; leave empty if the initial bind is anonymous;manager-password
: the password of the user used to bind to the LDAP directory; can be omitted ifmanager-dn
is empty (i.e. when the initial bind is anonymous).
Notes:
- the base DN given in the
url
(e.g.dc=example,dc=com
inldap://ldap.forumsys.com:389/dc=example,dc=com
) does not have to be repeated inuser-search-base
orgroup-search-base
. However, it must be repeated in themanager-dn
. user-dn-pattern
anduser-search-filter
support the placeholder{0}
which will be replaced with the user’s login name.group-search-filter
supports three placeholders:{0}
maps to the user’s DN,{1}
maps to the user’s login name, and{2}
maps to the user’s CN.
Environment Variables
When a user is authenticated, the following environment variables will be available in any Shiny application launched by the user:
SHINYPROXY_USERNAME
: the name of the user, as used when logging inSHINYPROXY_USERGROUPS
: the groups the authenticated user is a member of, as a comma-separated value
Multiple LDAP providers
When multiple LDAP providers need to be configured (e.g. to support different domains or forests), this can be done using
proxy:
ldap:
- url: ldap://ldap.forumsys.com:389/dc=example,dc=com
...
- url: ldap://another.ldap.server:389/...
...
instead of the single LDAP configuration
proxy:
ldap:
url: ldap://ldap.forumsys.com:389/dc=example,dc=com
...
StartTLS
Using LDAP with StartTLS can be achieved by adding a setting
proxy:
ldap:
starttls: simple
This setting may have the following values:
simple
: StartTLS is enabled, using simple client authentication;true
: same as simple;external
: StartTLS is enabled, using external (certificate) client authentication;- (None): if the property is absent (default), StartTLS is disabled.
More information on the StartTLS extension can be found here.
Note:
- LDAPS and LDAP with StartTLS are mutually exclusive; it is not possible to combine the two mechanisms.
Example: FreeIPA
When using a FreeIPA server for managing identities (e.g. the standard on RHEL), the configuration with the default directory tree will be:
ldap:
url: ldaps://example.com:636/dc=example,dc=com
manager-dn: uid=shinyproxy,cn=sysaccounts,cn=etc,dc=example,dc=com
manager-password: xxxxxxxxxxxx
user-dn-pattern: uid={0},cn=users,cn=accounts
group-search-filter: (member={0})
group-search-base: cn=groups,cn=accounts
Notes:
- in this example
uid=shinyproxy,cn=sysaccounts,cn=etc,dc=example,dc=com
is a specific system account created to bind against the FreeIPA LDAP directory on behalf of ShinyProxy;
Example: Active Directory
ldap:
url: ldaps://example.com:3269/dc=example,dc=com
manager-dn: cn=shinyproxy,ou=Service Accounts,dc=example,dc=com
manager-password: xxxxxxxxxxxx
user-search-filter: (sAMAccountName={0})
group-search-filter: (member={0})
group-search-base: ou=Groups
Notes:
sAMAccountName
is often used as the unique login name in Active Directory environments. That’s why it is used here in theuser-search-filter
.3269
is the SSL-enabled port for the Global Catalog.
Kerberos
A second type of authentication is Kerberos based authentication which offers single-sign on on top of the authentication and authorization.
Kerberos-based authentication can be configured using
proxy:
[...]
authentication: kerberos
in the application.yml
file.
The configuration details for Kerberos should be set in a separate kerberos
block:
proxy:
[...]
kerberos:
auth-service-principal: HTTP/shinyproxy.yourdomain.com
auth-service-keytab: /etc/security/keytabs/shinyproxy-http.keytab
deleg-service-principal: shinyproxy-service
deleg-service-keytab: /etc/security/keytabs/shinyproxy-service.keytab
client-ccache-path: /path/to/folder
In order to use it with your own Kerberos server, you can use the following fields:
auth-service-principal
: principal name of the Kerberos entity that processes authentication requests;auth-service-keytab
: path to the keytab file containing the secret of theauth-service-principal
;deleg-service-principal
: principal name of the Kerberos entity that obtains delegated service tickets for the user; if not specified the value of theauth-service-principal
will be used also for thedeleg-service-principal
;deleg-service-keytab
: path to the keytab file containing the secret of thedeleg-service-principal
; if not specified the value of theauth-service-keytab
is used as thedeleg-service-keytab
;backend-principals
: array of service principals for which delegated service tickets should be obtained e.g.["HTTP/your-api-server.com", "postgres/your-postgres-server.com"]
client-ccache-path
: absolute or relative path to a folder where user-specific credential caches are maintained; these are mounted automatically as volumes in the container, and contain service tickets for the configuredbackend-principals
;ticket-renew-interval
: interval in milliseconds for automatically renewing the backend service tickets; the default is28800000
which corresponds to 8 hours.
Notes:
SPNEGO
The browser must support the SPNEGO protocol for single-sign on authentication to work.
krb5.conf
- For Active Directory you must explicitly enable forwardable tickets with the
following setting in the
/etc/krb5/krb5.conf
file:
[libdefaults]
forwardable = true
The logic used by ShinyProxy to locate and load the krb5.conf
file is
described
here
Environment Variables
When a user is authenticated, the following environment variables will be available in any Shiny application launched by the user:
SHINYPROXY_USERNAME
: the name of the user, as used when logging in;SHINYPROXY_USERGROUPS
: the groups the authenticated user is a member of, as a comma-separated value.
Single-Sign On / Keycloak
A third type of authentication is Keycloak authentication, a very powerful option that delegates authentication and authorization to the open source identity and access management system Keycloak supported by Red Hat. Many advanced features are available to ShinyProxy such as User Federation, Identity Brokering and Social Login.
Keycloak authentication can be configured using
proxy:
[...]
authentication: keycloak
in the application.yml
file. The details related to the application identifiers and secrets for each
of the social platforms can be configured in a separate keycloak
block:
proxy:
[...]
keycloak:
realm: yoursso
auth-server-url: http://yoururl.com:8180/auth
resource: yourresource
credentials-secret: your-credentials-secret
There are also the following optional settings:
ssl-required
: one can set the SSL/HTTPS mode to one ofnone
,all
orexternal
(default). These options are documented here;proxy.keycloak.name-attribute
: name of the attribute to use as the user’s name; one ofname
(default, current behaviour),preferred_username
,nickname
oremail
use-resource-role-mappings
: boolean value to use either client roles (true
) or realm roles (false
; default); see also the relevant Keycloak documentation.
Note:
- the user name of the authenticated user is made available to the Shiny
application via the environment variable
SHINYPROXY_USERNAME
; - the roles the authenticated user has been assigned to are made
available to the Shiny application via the environment variable
SHINYPROXY_USERGROUPS
.
Further documentation on setting up Keycloak can be found here.
OpenID Connect (OIDC)
OpenID Connect is a modern authentication protocol based on the OAuth2 standard. It uses tokens, removing the need to store passwords and offering a single-sign-on experience for desktop, web and mobile apps.
More information about OIDC can be found on the OpenID website.
To configure OIDC in ShinyProxy, several steps must be performed:
- Register your ShinyProxy installation with an OIDC provider.
- Obtain the configuration parameters for your OIDC provider that ShinyProxy requires.
- (Optional) For group-based authorization, add a custom claim in the OIDC ID Token.
Enable OIDC authentication
OIDC authentication can be enabled by setting
proxy:
[...]
authentication: openid
in the application.yml
file.
Register with an OIDC Provider
Some examples of well-known OIDC providers are: Auth0, Okta, Google, Microsoft, and many more social platforms. Of course, you can also deploy your own OpenID identity provider.
When registering the application, make sure to select the type ‘web application’. This allows you to specify a callback URL. The URL should look like this:
http(s)://(your-shinyproxy-url)/login/oauth2/code/shinyproxy
Defining an incorrect callback URL will result in authentication errors in ShinyProxy.
Set OIDC configuration parameters
Your OIDC provider should offer you the following parameters for your newly registered app:
- Auth Endpoint URL: The URL where OIDC initiates authentication flows. ShinyProxy will redirect here when an unauthenticated user accesses a page.
- Token Endpoint URL: The URL where tokens can be retrieved or exchanged. This is used during the authentication process.
- JSON Web Key Set (jwks) URL: The URL where the provider’s public certificates can be found. This is used during the authentication process.
- Client ID: A unique ID generated by the provider for your application.
- Client Secret: A secret generated by the provider for your application.
Enter these parameters into ShinyProxy’s application.yml file. An example for Google is given below:
proxy:
openid:
auth-url: https://accounts.google.com/o/oauth2/v2/auth
token-url: https://www.googleapis.com/oauth2/v4/token
jwks-url: https://www.googleapis.com/oauth2/v3/certs
client-id: ***
client-secret: ***
Similarly, an example for Microsoft Azure B2C:
proxy:
openid:
auth-url: https://login.microsoftonline.com/<your-tenant-id>/oauth2/authorize
token-url: https://login.microsoftonline.com/<your-tenant-id>/oauth2/token
jwks-url: https://login.microsoftonline.com/common/discovery/keys
client-id: ***
client-secret: ***
Note: replace <your-tenant-id>
with the ID of your Azure tenant.
Group-based authorization
While OIDC specifies an authentication flow, it has no notion of ‘user groups’ or ‘permission levels’. To achieve this in ShinyProxy, you must use custom claims. Claims are pieces of information about the user that are included in the ID Token returned by the OIDC provider. Common claims include first name, last name, email address, etc.
Adding a custom claim to an ID Token is specific to each OIDC provider. Several examples are given below.
Note: the value of the custom roles claim must be an array!
Auth0
- Go to the user management page, select a user, and scroll down to the
app_metadata
block. Enter the following JSON:
{
"shinyproxy_roles": [ "scientists", "mathematicians" ]
}
- Go to the rules page and create a new rule that attaches this information to the ID Token upon authentication:
function (user, context, callback) {
context.idToken['https://shinyproxy.io/shinyproxy_roles'] = user.app_metadata.shinyproxy_roles;
callback(null, user, context);
}
Note that custom claims must have a URI-like namespace. In this example, we use the name https://shinyproxy.io/shinyproxy_roles
.
- In ShinyProxy’s
application.yml
file, enter the full name of the custom claim containing the user’s roles:
proxy:
openid:
roles-claim: https://shinyproxy.io/shinyproxy_roles
Amazon AWS Cognito
Cognito already provides this information in the claim cognito:groups
.
For more information, see AWS Cognito: User Pools.
Miscellaneous settings
logout-url
: URL to be used for logging out of the OpenId session on the OpenId provider back-end; for an Auth0 back-end one can specify e.g.
proxy:
openid:
logout-url: https://YOUR_AUTH0_DOMAIN/v2/logout?returnTo=http%3A%2F%2Fwww.yourshinyproxyserver.com
username-attribute
: name of the attribute to be used as the user’s name; one ofemail
(default),name
,nickname
,preferred_username
, etc.; a complete list is provided in the OpenId Connect specification.
Environment Variables
When a user is authenticated, the following environment variables will be available in any Shiny application launched by the user:
SHINYPROXY_USERNAME
: the name of the user, as used when logging inSHINYPROXY_USERGROUPS
: the groups the authenticated user is a member of, as a comma-separated valueSHINYPROXY_OIDC_ACCESS_TOKEN
: the OpenId connect access token that can be reused to invoke another API from within the Shiny app
SAML 2.0
ShinyProxy supports authentication and authorization using an IDP (Identity Provider) conforming to the SAML 2.0 specification.
SAML authentication can be enabled by setting
proxy:
[...]
authentication: saml
in the application.yml
file.
The basic settings (under proxy.saml
) are:
idp-metadata-url
: the URL where the IDP’s metadata can be retrievedapp-entity-id
: the entity ID of this application, must match the AudienceRestriction in the SAML assertion received from the IDPapp-base-url
: the application’s base URL. Some IDPs require that you specify valid callback URLs. This must match a valid callback URL.name-attribute
: the name of the attribute in the SAML assertion containing the usernameroles-attribute
: the name of the attribute in the SAML assertion containing the user roleslogout-url
: optional URL to which the user will be redirected when they logout
If the IDP sends back encrypted SAML assertions, ShinyProxy must be configured with additional settings to be able to decrypt the assertion:
keystore
: path to the JKS keystorekeystore-password
: password to access the keystore. If omitted,encryption-cert-password
will be used insteadencryption-cert-name
: name of the certificate whose public key the SAML Assertion is encrypted withencryption-cert-password
: password of the certificate whose public key the SAML Assertion is encrypted with
Note:
- there are two ways of doing authorization: using group memberships and using application roles
- when using Azure AD in combination with group membership based authorization, ShinyProxy will receive group GUIDs instead of names; in that case, the application can query the MS Graph API to resolve the group GUID (if needed)
Example: Auth0
An example configuration using Auth0 as an IDP is given below.
- Application type:
Regular Web Application
- Domain:
my-shinyproxy-setup.eu.auth0.com
- Allowed Callback URLs:
http://localhost:8080/saml/SSO
- Addons: enable
SAML2 Web App
- Addon settings: Application Callback URL:
http://localhost:8080/saml/SSO
(same as Allowed Callback URLs) - Addon settings: Settings JSON:
{ "audience": "urn:my-shinyproxy-setup.eu.auth0.com" }
(same as Domain)
In ShinyProxy’s application.yml
:
proxy:
saml:
idp-metadata-url: https://my-shinyproxy-setup.eu.auth0.com/samlp/metadata/<client-id>
app-entity-id: urn:my-shinyproxy-setup.eu.auth0.com
app-base-url: http://localhost:8080
name-attribute: http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress
roles-attribute: http://schemas.auth0.com/shinyproxy_roles
logout-url: https://my-shinyproxy-setup.eu.auth0.com/v2/logout?client_id=<client_id>&returnTo=http://localhost:8080/
Example: Azure AD
An example configuration using Azure AD as an IDP is given below.
First, create a directory in Azure AD and define several users (not in scope of this document).
Then, under App registrations, register a new app of the type Web app / API
. Provide the following configuration:
- Settings > Properties > Homepage URL:
http://localhost:8080
- Manifest: to enable role-based authorization, fill out the
appRoles
block:
{
"appRoles": [
{
"allowedMemberTypes": [
"User"
],
"displayName": "Mathematicians",
"id": "2e7e882c-6645-4a58-b92d-2e2dbe02bd87",
"isEnabled": true,
"description": "These are mathematicians",
"value": "mathematicians"
},
{
"allowedMemberTypes": [
"User"
],
"displayName": "Scientists",
"id": "e858ca1b-66a3-43f0-aa4c-deed69750550",
"isEnabled": true,
"description": "These are scientists",
"value": "scientists"
}
],
}
In ShinyProxy’s application.yml
:
proxy:
saml:
idp-metadata-url: https://login.microsoftonline.com/<tenant-ID>/FederationMetadata/2007-06/FederationMetadata.xml
app-entity-id: <see App ID URI in your Azure application properties>
app-base-url: http://localhost:8080
roles-attribute: http://schemas.microsoft.com/ws/2008/06/identity/claims/role
Social Authentication
A sixth type of authentication offered by ShinyProxy besides LDAP, Kerberos, Keycloak, OpenID Connect and SAML 2.0 is so-called social authentication. This type of authentication allows users to log in with
- Facebook,
- Twitter,
- Google,
- Github or
accounts into ShinyProxy.
Social authentication can be configured using
proxy:
[...]
authentication: social
in the application.yml
file. The details related to the application identifiers and secrets for each
of the social platforms can be configured in a separate social
block:
proxy:
[...]
social:
facebook:
app-id: yourfacebookappid
app-secret: yourfacebookappsecret
twitter:
app-id: yourtwitterappid
app-secret: yourtwitterappsecret
google:
app-id: yourgoogleappid
app-secret: yourgoogleappsecret
github:
app-id: yourgithubappid
app-secret: yourgithubappsecret
linkedin:
app-id: yourlinkedinappid
app-secret: yourlinkedinappsecret
Since no authorization is offered by the social platforms, authorization logic is not implemented and authenticated users will be able to access all public applications.
Note:
- the user name of the authenticated user is made available to the Shiny
application via the environment variable
SHINYPROXY_USERNAME
.
Web Service Based Authentication
Amongst the different authentication methods, ShinyProxy also offers the possibility to use a custom web service that handles authentication with a HTTP POST call returning a session id and user information.
In order to select this authentication method, one needs to choose the
webservice
authentication method:
proxy:
[...]
authentication: webservice
in the application.yml
file.
The details related to the web service can be configured as:
proxy:
webservice:
authentication-url: https://your-auth-server.com/login
authentication-request-body: '{"username": "%s", "password": "%s"}'
The authentication-request-body
is a customizable JSON body that gets POSTed
to the authentication-url
.
If the HTTP response code is 200, the authentication is considered successful while all other response codes result in an authentication error. Since no authorization is offered by this type of web services, authorization logic is not implemented and authenticated users will be able to access all public applications.
Note:
- the user name of the authenticated user is made available to the Shiny
application via the environment variable
SHINYPROXY_USERNAME
.
Simple Authentication
Besides LDAP and social authentication, ShinyProxy also offers the possibility to define users and groups inside the application.yml
file. In order to select this authentication method, one needs to choose the
simple
authentication method:
proxy:
[...]
authentication: simple
The example configuration demonstrates how users and groups can be specified:
proxy:
users:
- name: jack
password: password
groups: scientists
- name: jeff
password: password
groups: mathematicians
Multiple groups can be specified for a user, by separating the groups with commas (do not use square brackets) as in this example:
proxy:
users:
- name: jack
password: password
groups: scientists
- name: jeff
password: password
groups: mathematicians, physicists
Since passwords are contained in clear text in the application.yml
file, this is not a secure way to set up authentication, but can be useful for demonstration purposes (e.g. in the absence of a network connection) or for very specific use cases.
Note:
- the user name of the authenticated user is made available to the Shiny
application via the environment variable
SHINYPROXY_USERNAME
; - the groups the authenticated user is member of are made available to the Shiny
application via the environment variable
SHINYPROXY_USERGROUPS
. The group names are converted into capital letters (e.g.MATHEMATICIANS
)
No authentication
In some scenarios, one wants to disable the ShinyProxy authentication. This can be done using
proxy:
[...]
authentication: none
Note:
- with
authentication: none
the environment variableSHINYPROXY_USERNAME
inside the Docker container will contain a random hash instead of the user name; if a user name needs to be passed from an external application it may be more useful to pass this information to the Shiny application via the URL (see this article).
Container Back-ends
ShinyProxy supports multiple container back-ends to run the Shiny apps, namely
- a plain Docker host (default)
- a Docker Swarm cluster and
- a Kubernetes cluster
The backend can be configured using
proxy:
container-backend: docker
The container-backend
can be one of docker
(default), docker-swarm
or
kubernetes
. The specific configuration these back-ends is
documented below.
Docker
The Docker back-end is the default back-end for ShinyProxy.
In order to specify it explicitly, one can set
proxy.container-backend
to docker
.
The configuration of the back-end can be done using the following properties:
cert-path
: path to the folder that contains the certificate files (ca.pem
,cert.pem
andkey.pem
) used for encrypted traffic to the docker daemon; if the files have other names or are located in different folders, symbolic links can be used (forca.pem
,cert.pem
andkey.pem
) that point to the actual certificate files. If a non-existing path is used ascert-path
, traffic will not be encrypted; the default value forcert-path
is set to/home/none
; this property can be omitted when not applicable;url
: URL and port on which to connect to the docker daemon; the default value of http://localhost:2375 does not connect over TLS; this is not recommended for production environments;container-protocol
: optional setting to indicate the protocol to be used to communicate with the containers; can be one ofhttp
orhttps
; if not set, the protocol is derived from theurl
specified (cf. above);container-memory-request
: maps to the--memory-reservation
argument ofdocker run
, see the Docker documentation ;container-memory-limit
: maps to the--memory
argument ofdocker run
, see the Docker documentation ; note that this replaces the oldcontainer-memory
setting;container-cpu-limit
: maps to a combination of--cpu-period
and--cpu-quota
, see the Docker documentation ;privileged
: run all containers with extended privileges (true
) or not (false
; default value);port-range-start
: every docker container will be assigned a port on the docker host to which the ShinyProxy will proxy the traffic of a particular user; the value ofport-range-start
will be the port assigned to the first container that is started; by default the first port will be20000
(second20001
, third20002
etc.).port-range-max
: maximum port number to be handled by ShinyProxy (e.g.20099
, which allows to run a maximum of 100 containers ifport-range-start
is set to the default value20000
); this allows to limit the number of concurrent apps that can be managed by a single ShinyProxy instance or, in case multiple ShinyProxy instances launch docker containers on a shared Docker Swarm, can prevent the same port number being used by multiple such instances; the default value ofport-range-max
is-1
(no maximum). If the port pool is exhausted, the following error message will appear:
Cannot start container: all allocated ports are currently in use. Please try again later or contact an administrator.
internal-networking
: set this totrue
if ShinyProxy will run as a container on the same Docker host; default value isfalse
.
Note:
- when
internal-networking
istrue
, no ports will be allocated per proxy and the port range settings are ignored (port-range-start
andport-range-max
); also, the proxy target URLs will use the container host name.
Docker Swarm
In order to use a Docker Swarm back-end, set proxy.container-backend
to
docker-swarm
. The configuration of the back-end is not different from the
configuration of a plain Docker back-end (cf. supra).
Note:
- when
internal-networking
istrue
, no ports will be allocated per proxy and the port range settings are ignored (port-range-start
andport-range-max
); also, the proxy target URLs will use the container name.
Kubernetes
In order to use a Kubernetes back-end, set proxy.container-backend
to
kubernetes
. The configuration of the back-end can be done using the following
properties:
proxy.kubernetes.url
: the URL of the apiserverproxy.kubernetes.cert-path
: the path to a dir containingca.pem
,cert.pem
andkey.pem
to be used if url is httpsproxy.kubernetes.namespace
: the namespace to create pods in; the default value isdefault
proxy.kubernetes.api-version
: the API version to use; the default value isv1
proxy.kubernetes.image-pull-policy
: the pull policy for images; the default value isIfNotPresent
proxy.kubernetes.image-pull-secret
: the name of a secret to use for pulling images from a registryproxy.kubernetes.image-pull-secrets
: see above, but for multiple secretsproxy.kubernetes.privileged
: run all containers with extended privileges (true
) or not (false
; default value);proxy.kubernetes.internal-networking
: set this totrue
if ShinyProxy will run inside the cluster itself; default value isfalse
proxy.kubernetes.container-protocol
: the protocol to use when accessing a container; can be one ofhttp
(default) orhttps
proxy.kubernetes.port
: the TCP port to access on the container; the default port is3838
proxy.kubernetes.node-selector
: comma-separated list of key=value pairs that are matched with node labels to select specific nodes in the cluster; see the relevant Kubernetes documentation.proxy.kubernetes.debug-patches
: boolean (true/false) controlling whether the kubernetes-pod-patches feature should output debug output. If enabled the specification of pods is printed to the log before a patch is applied and after a patch is applied.proxy.kubernetes.pod-wait-time
: the time ShinyProxy waits for a Kubernetes Pod to become ready (in milliseconds). By default this is 60 seconds. This option should be changed when your Pods take more than 60 seconds to startup. For example if you use very large images.
An example configuration is:
proxy:
container-backend: kubernetes
kubernetes:
cert-path: /etc/certs
url: https://1.2.3.4
Note:
- when
internal-networking
istrue
, no ports will be allocated per proxy and the proxy target URLs will use the Pod IP.
Apps
Every single Shiny app served by Shiny Proxy has its own configuration block
under specs
:
specs:
- id: 01_hello
container-cmd: ["R", "-e", "shinyproxy::run_01_hello()"]
container-image: openanalytics/shinyproxy-demo
access-groups: [scientists, mathematicians]
- id: 06_tabsets
container-cmd: ["R", "-e", "shinyproxy::run_06_tabsets()"]
container-image: openanalytics/shinyproxy-demo
access-groups: [scientists]
For each app, the following basic configuration fields can be specified:
id
: the identifier of the applicationdisplay-name
: the name that will be displayed for the app on the ShinyProxy landing page as well as in the browser tab (once the application is opened);container-cmd
: the command that will be run when the Docker container is launched; typically this command will be the R command ("R"
) as well as the command that will launch the Shiny app ("-e", "shinyproxy::run_01_hello()"
);container-image
: name of the docker image to be started for every new user of this app; by default a demo image (openanalytics/shinyproxy-demo
) will be used;container-privileged
: run the container for this app with extended privileges (true
) or not (false
; default value);container-memory-request
: maps to--memory-reservation
on Docker and tospec.containers[].resources.requests.memory
, on Kubernetes see the documentationcontainer-memory-limit
: maps to--memory
on Dockerspec.containers[].resources.limits.memory
on Kubernetes, see the documentationcontainer-cpu-request
: does nothing in Docker; maps tospec.containers[].resources.requests.cpu
on Kubernetes, see the documentationcontainer-cpu-limit
: maps to a combination ofcpu-period
andcpu-quota
and is equivalent to the--cpus
setting (available since Docker 1.13), maps tospec.containers[].resources.limits.cpu
on Kubernetes, see the documentationaccess-groups
: one or more groups (e.g. LDAP groups) a user needs to belong to in order to gain access to the app; multiple groups are enclosed in square brackets and separated by commas; this field allows to authorize access per app; to test the authorization with LDAP authentication, one can usegauss
with passwordpassword
as an example mathematician; usertesla
with passwordpassword
is one of the example scientists. Other users are described here.
Note:
- apps for which
access-groups
are not specified will be handled as “public” applications in the sense that all authenticated users will be able to access these applications.
Besides the basic configuration options described above, there are also some more advanced configuration options that are not part of the default configuration:
container-dns
: a comma-separated list of IP addresses that are added asserver
lines in the/etc/resolv.conf
file of the container; this is the equivalent of launching the container with a--dns
option.container-env
: one or more environment variables specified as
container-env:
VAR1: VALUE1
VAR2: VALUE2
and that will be passed to the container; this is equivalent to docker run --env
.
container-env-file
: a path to a file in which environment variables are specified to be passed to the container; this can be configured using
container-env-file: /path/to/env-file
and is equivalent to docker run --env-file
.
container-memory
: memory limit for the Shiny application (e.g.256m
or4g
); units can be one ofb
,k
,m
, org
and the minimum is4m
. This is the equivalent of launching the container with a--memory
option.container-network
: facilities to set the networking of the container. This is the equivalent of launching the container with a--network
option (and defaults tobridge
which is also the Docker default).container-volumes
: list of docker volumes to mount into the container; can be specified along
container-volumes: [ "/host/path1:/container/path1", "/host/path2:/container/path2" ]
and implements the functionality of docker run --volume
.
logo-url
: the URL to an image that can be used as the logo for an application; this can also be a local file using the file scheme (file://
); if none of the applications in theapplication.yml
specifies alogo-url
field, the landing page will present the applications as a bullet list (cf. the default presentation in theopenanalytics/shinyproxy-demo
image).port
: the port on which the app is listening in the container; this setting will override the default port (3838)labels
: a map of labels which are added to every instance of the pod. For example:
labels:
role: shinyproxy-app
component: shinyproxy
Note: when using Kubernetes ShinyProxy adds the app
label (containing the ID of the container) to every pod it launches. Therefore it’s impossible to specify a label named app
.
Note: ShinyProxy automatically adds extra labels (such as the proxy-id
) to apps it launches. These labels are prefixed by openanalytics.eu/sp
to prevent collisions.
kubernetes-pod-patches
: this option is only used when using the Kubernetes container backend. It allows to apply JSON Patches to the Kubernetes Pod created for this app. The parameter is a string which should contain a YAML array. For example the following patch performs:- add a ServiceAccount
- change the namespace
- add Volume + VolumeMount
- add an Environment variable
- add a secret as an Environment Variable
kubernetes-pod-patches: |
- op: add
path: /spec/serviceAccountName
value: my-serviceaccount
- op: replace
path: /metadata/namespace
value: my-namespace
- op: add
path: /spec/volumes
value:
- name: cache-volume
emptyDir: {}
- op: add
path: /spec/containers/0/volumeMounts
value:
- mountPath: /cache
name: cache-volume
- op: add
path: /spec/containers/0/env/-
value:
name: ADDED_VAR
value: VALUE
- op: add
path: /spec/containers/0/env/-
value:
- name: SOME_PASSWORD
valueFrom:
secretKeyRef:
name: some-password
key: password
kubernetes-additional-manifests
: this option is only used when using the Kubernetes container backend. This option contains a list of Kubernetes manifests, which are created when the app starts and destroyed when the app stops. For example the following configuration creates a PersistentVolumeClaim and a Secret.
kubernetes-additional-manifests:
- |
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: manifests-pvc
spec:
storageClassName: standard
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 5Gi
- |
apiVersion: v1
kind: Secret
metadata:
name: manifests-secret
type: Opaque
data:
password: cGFzc3dvcmQ=
The resource will be created in the namespace specified in the manifest.
If no namespace is provided, ShinyProxy will use the namespace of the app (even if this namespace is changed using kubernetes-pod-patches
).
Starting from ShinyProxyx 2.4.2, both the kubernetes-additional-manifests
and kubernetes-pod-patches
support the use of pring Expression Language.
Therefore you can reference values from the ContainerSpec
, Proxy
and ProxySpec
objects.
The following example demonstrates the use of this feature to create a PVC (Persisent Volume Claim) and mount it as home volume into the Shiny app.
In addition it adds the id of the proxy as environment variable.
- id: 01_hello_manifests_espression
container-specs:
- image: "openanalytics/shinyproxy-demo"
cmd: ["R", "-e", "shinyproxy::run_01_hello()"]
port-mapping:
default: 3838
kubernetes-pod-patches: |
- op: add
path: /spec/containers/0/env/-
value:
name: PROXY_ID
value: "#{proxy.id}"
- op: add
path: /spec/volumes
value:
- name: "home-dir-pvc-#{proxy.userId}"
persistentVolumeClaim:
claimName: "home-dir-pvc-#{proxy.userId}"
- op: add
path: /spec/containers/0/volumeMounts
value:
- mountPath: "/home/#{proxy.userId}"
name: "home-dir-pvc-#{proxy.userId}"
kubernetes-additional-manifests:
- |
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: "home-dir-pvc-#{proxy.userId}"
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 5Gi
Logging
Basic settings
By default, information about various application events will be logged into the standard output stream of the ShinyProxy process. If you are running ShinyProxy in a console or shell, you will see the logging appear there.
In addition, you can also send the logging to a file, using the logging.file
setting.
For ShinyProxy releases up to 2.3.1, use the following code:
logging:
file: shinyproxy.log
For ShinyProxy releases starting at 2.4.0, use:
logging:
file:
name: shinyproxy.log
This file will be ‘rolled over’ on two events:
- When the file reaches a size of 10MB
- When a new day begins
Rollover means that the existing log file will be archived (e.g. shinyproxy.log.yyyy-MM-dd.0.gz
) and a new file will be created to log into. You can change the maximum file size using the logging.file.max-size
setting:
logging:
file:
max-size: 50MB
The amount of information being logged is also configurable. ShinyProxy and its underlying components emit logging information of various ‘levels’, the most important ones being ERROR
, WARN
, INFO
and DEBUG
. By default, the level being logged is INFO
which includes all levels above it.
You can change the log level using the logging.level
setting:
logging:
level:
org.springframework.security.ldap: DEBUG
The setting can be made for specific components (in the example above, org.springframework.security.ldap
) or for the whole application by using the name root
:
logging:
level:
root: DEBUG
Some of the important components of ShinyProxy include:
eu.openanalytics
: the code relating to ShinyProxy itselfio.undertow
: the HTTP server componentcom.spotify.docker
: the component for controlling docker containersio.fabric8.kubernetes
: the component for controlling kubernetes podsorg.springframework
: the framework dealing with many different aspects, such as security
Advanced settings
Instead of using the settings described above, you can also provide a completely custom configuration.
ShinyProxy uses the Logback logging framework, which can be customized in many ways.
To do this, create an XML file and specify it with the logging.config
setting:
logging:
config: logback.xml
An example logback config is given below. For more information, see Logback appenders.
<configuration>
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>shinyproxy.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>logFile.%d{yyyy-MM-dd}.log</fileNamePattern>
<maxHistory>30</maxHistory>
<totalSizeCap>3GB</totalSizeCap>
</rollingPolicy>
<encoder>
<pattern>%-4relative [%thread] %-5level %logger{35} - %msg%n</pattern>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="FILE" />
</root>
</configuration>
Request dumping
In some cases, you may want to obtain detailed information about all incoming requests (and outgoing responses). For this scenario, the following setting can be enabled:
logging:
requestdump: true
By toggling this setting on, the Undertow RequestDumpingHandler
will be enabled, and verbose request information
will be printed to the application log, including headers, cookies and body.
Application Container Logs
ShinyProxy can be configured to store log files of running containers. These
log files contain the stdout
and stderr
output of the R process running the
Shiny app.
local file back-end
To enable the storing of container log files, use the following configuration:
proxy:
container-log-path: ./container-logs
If enabled, ShinyProxy will create log files in the configured directory, using the following naming pattern:
<specId>_<proxyId>_<startupTime>_stdout.log
<specId>_<proxyId>_<startupTime>_stderr.log
s3 back-end
It is also possible to store the container log files in an S3 back-end using the following settings:
proxy:
container-log-path: s3://bucketName/path/to/store/at
container-log-s3-access-key: ...
container-log-s3-access-secret: ...
Optionally one can also set
container-log-s3-sse
: defaultfalse
container-log-s3-endpoint
: defaulthttps://s3-eu-west-1.amazonaws.com
See the Amazon docs for more information on server-side encryption.
Note: on a Kubernetes container back-end, the output for the logs is buffered at 1Mb; if the output stays below the 1 Mb buffer until the container stops, it will be force-flushed when the container stops.
Reporting Issues
ShinyProxy can be configured to allow end users to send feedback or bug reports of the Shiny applications that are deployed on ShinyProxy.
In order to do so, a proxy.support
block needs to be added to the application.yml
file:
proxy:
support:
mail-to-address: some.user@somedomain.com
When ShinyProxy is started with this configuration, an extra ‘Report Issue’ link will be displayed in the navigation bar.
Users can click the link to send custom messages and these messages will be sent to the configured e-mail address (some.user@somedomain.com
in the example configuration). The information that will be sent to the support address will
include:
- user name: name of the authenticated user that sends the issue
- app name: only if user was running an app when he clicked the ‘Report Issue’ button
- location: the URL in the user’s browser
- custom message: the message that the user entered in the Report Issue dialog
These log files will be attached to support mails automatically.
The configuration of the mail server settings can be done in a separate spring.mail
block, e.g.
spring:
mail:
host: smtp.gmail.com
# TLS: 587 SSL: 465 Plain: 25
port: 465
username: my_username
password: my_password
properties:
# For StartTLS
mail.smtp.starttls.enable: true
# For SSL
#mail.smtp.socketFactory.class: javax.net.ssl.SSLSocketFactory
More information on these properties can be found here.
Note:
Optionally, one can also define the ‘from’ address to be used for the e-mail messages in the proxy.support
block:
proxy:
support:
mail-from-address: issues@shinyproxy.io
Usage Statistics
ShinyProxy supports the tracking and saving of usage statistics to see which apps are popular and by whom these are used.
Currently, the following backends are supported:
More details on setting up databases for usage statistics tracking are given in a dedicated Usage Statistics section.
Proxy API
ShinyProxy exposes an API, a set of endpoints that can be called programmatically to launch, retrieve, and stop proxies. This is useful, for example, if you want to embed ShinyProxy into a larger web application, and you want to control the lifecycle of proxies in the context of this larger application.
To get an overview and detailed information about the API and its components, have a look at this page.
Endpoint URLs
In common use ShinyProxy offers the Shiny app under two URLs:
/app/<app_name>
: used in the standard ShinyProxy interface which contains a toolbar and makes the Shiny app available via an iframe/app_direct/<app_name>
: can be used as an alternative to directly access the Shiny app without the iframe and navigation bar offered via/app/<app_name>
Note that within the iframe that is displayed under /app/<app_name>
, the
/app_direct/<app_name>
link is used to display the Shiny app.
For embedding apps via the API, a different approach should be taken,
namely via /api/route
as documented in the example
on
Github.
Authorization
By default, the ShinyProxy API uses the same authentication framework as the web interface, as configured in the authentication: ...
setting. This may work well in simple cases (e.g. when using authentication: none
), but has limitations.
For a better integration experience, you can instead use OAuth2. This can be enabled by making the following configuration:
proxy:
oauth2:
resource-id: your-resource-id
jwks-url: your-jwks-url
For this to work, you must register your ShinyProxy installation as a resource with an OAuth2 provider, such as Auth0.
The resource-id
is the unique identifier you give it during registration, and the jwks-url
is a provider-specific URL.
E.g. for Auth0, the URL is https://your-tenant-name.auth0.com/.well-known/jwks.json
.
You can then access the API by including a valid OAuth2 access token in your requests. For an example, see example 08-api-oauth2.
Miscellaneous Settings
Long sessions
By default a session of the HTTP engine embedded in ShinyProxy will time out
after 30 minutes. To change this e.g. to 60 minutes, one can use the
servlet.session.timeout
and set it to 3600
in the
application.yml
file (measured in seconds):
server:
servlet.session.timeout: 3600
If there should be no timeout, use 0
, but beware of session leaks in that
case.
Session Persistence
Session persistence in ShinyProxy is supported by using Redis. Configuration depens on the type of the Redis deployment. The most basic configuration (e.g. using a single Redis instance) is:
spring:
session:
store-type: redis
redis:
host: redis
password: redis_password
When running a Redis cluster the configuration should look like:
spring:
session:
store-type: redis
redis:
cluster:
# add all hosts of the cluster here (including the port)
nodes: host1:port1, host2:port2, host3:port3
Finally, when running Redis using SSL/TLS make sure this is reflected in the ShinyProxy configuration:
spring:
session:
store-type: redis
redis:
ssl: true
Note that ShinyProxy will hang when this option is not specified but you are using a SSL/TLS enabled Redis server.