Docker

Introduction

Starting with version 2.2.0 of the operator, the operator can run on pure Docker hosts. Such a setup provides many of the benefits of running ShinyProxy on Kubernetes, without the complexity of running Kubernetes. Deploying ShinyProxy with the operator is the recommended approach. See the Features page for an overview of all benefits.

Tutorial

Installing the operator

  1. Prepare a server with your favorite Linux distribution. If you don’t know which distribution to pick, we advice to start with Ubuntu Server LTS.

  2. Install Docker on Debian, Ubuntu, CentOS or RHEL. It’s recommended to use the Docker binaries provided by the Docker website and not by your Linux distribution. When using Ubuntu, make sure to not use the Docker snap as this can cause problems as well.

  3. The operator creates some directories and files, it’s important that these files are owned by a non-root user. Therefore, make sure to have a non-root user ready. Create a user. if you don’t have a user yet (i.e. you are logged root):

    sudo useradd -m shinyproxy
    

    The remainder of this tutorial assumes that you are using a user called shinyproxy, with the home directory /home/shinyproxy/shinyproxy. If you continue with a different user or home directory, make sure to change this in the upcoming commands.

  4. Create a (global) storage directory for ShinyProxy:

    sudo mkdir -p /opt/shinyproxy-docker-operator/data
    sudo chown -R shinyproxy:shinyproxy /opt/shinyproxy-docker-operator
    
  5. Get the id of the shinyproxy user:

    sudo id -u shinyproxy
    
  6. Get the id of the docker group:

    sudo getent group docker | cut -d: -f3
    
  7. As the shinyproxy user, create a directory for the configuration files of ShinyProxy:

    sudo -u shinyproxy mkdir -p /home/shinyproxy/shinyproxy/input
    
  8. Inside the home directory of the non-root user (i.e. /home/shinyproxy/shinyproxy), create the docker-compose.yml file. Make sure to fill in the ids of step 5 and 6 in the highlighted lines:

    sudo -u shinyproxy nano /home/shinyproxy/shinyproxy/docker-compose.yml
    
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    
    services:
      shinyproxy-operator:
        image: openanalytics/shinyproxy-operator:2.2.0
        environment:
          SPO_ORCHESTRATOR: docker
          SPO_DOCKER_GID: 1234 # replace by the id of step 6
        volumes:
          - ./input:/opt/shinyproxy-docker-operator/input
          - /var/run/docker.sock:/var/run/docker.sock:ro
          - /opt/shinyproxy-docker-operator/data:/opt/shinyproxy-docker-operator/data
        group_add:
          - 1234 # replace by the id of step 6
        networks:
          - sp-shared-network
        restart: always
        labels:
          app: shinyproxy-operator
        user: "1234" # replace by the id of step 5 (must be a sting)
    networks:
      sp-shared-network:
        name: sp-shared-network
    
  9. Start the ShinyProxy Operator

    sudo docker compose -f  /home/shinyproxy/shinyproxy/docker-compose.yml up -d
    

The operator is now running. It’s a good idea to have a look at the logs to ensure no warnings or errors are logged:

sudo docker compose -f /home/shinyproxy/shinyproxy/docker-compose.yml logs -f

On startup, the operator logs all its configuration parameters. The last few log lines should look similar to:

07:54:42.291 [main           ] INFO  eu.op.sh.Main                        - Starting background processes of ShinyProxy Operator
07:54:42.304 [main           ] INFO  eu.op.sh.im.so.FileSource            - No input files found
07:54:42.305 [main           ] INFO  eu.op.sh.im.so.FileSource            - FileSource ready
07:54:42.306 [main           ] INFO  eu.op.sh.im.do.DockerOrchestrator    - Initializing DockerOrchestrator
07:54:42.762 [main           ] INFO  eu.op.sh.im.do.RedisConfig           - Re-using password from Redis state
07:54:43.483 [atcher-worker-1] INFO  eu.op.sh.Main                        - Starting ShinyProxy Operator
07:54:43.485 [atcher-worker-1] INFO  eu.op.sh.co.ShinyProxyController     - Starting ShinyProxyController

See the troubleshooting section if you see an error in the logs.

As the operator is now running, you are ready to deploy a ShinyProxy server, this is explained in the next section.

Deploying a ShinyProxy server

To deploy a ShinyProxy server using the operator, you must create a configuration file in the input (/home/shinyproxy/shinyproxy/input) directory. This file is similar to the application.yml file used by ShinyProxy itself, although a few additional properties are supported.

Before starting the deployment, you should decide on a domain name to use for the server. If you are running this tutorial on your laptop, you can simply use localhost. Otherwise, you can use the IP address of the server (use ip addr to find it). If you want to expose this server to the network (internet or LAN), you must use a domain name (e.g. shinyproxy.example.com) and setup the DNS records. The remainder of this tutorial assumes the domain name is localhost.

Next, create the input file /home/shinyproxy/shinyproxy/input/localhost.shinyproxy.yaml, with the following demo configuration:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
spring:
  session:
    store-type: redis
proxy:
  store-mode: Redis
  docker:
    internal-networking: true
  stop-proxies-on-shutdown: false
  authentication: simple
  realm-id: localhost
  users:
    - name: jack
      password: password
      groups: scientists
    - name: jeff
      password: password
      groups: mathematicians
  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
image: openanalytics/shinyproxy:3.2.0
fqdn: localhost

The important parts of this configuration file are:

  • lines 1-8: these properties are required when using the operator. Don’t remove or change these lines.
  • line 9: specifies the realm-id of the server. This is used to identify the server in logs, the monitoring stack and Redis. Choose a short and simple string.
  • line 29: specifies the Docker image to use for the ShinyProxy server
  • line 30: specifies the domain name (fqdn) to use

The other parts of the file are the normal ShinyProxy configuration properties. In this case, we configure two users and two apps. Every minute, ShinyProxy checks the input directory for new files. Look at the logs of the operator ( using sudo docker compose -f /home/shinyproxy/shinyproxy/docker-compose.yml logs -f) and wait for the operator to create the new server. Once the operator has discovered the configuration file, you should logs output similar to:

09:33:24.797 [atcher-worker-1] INFO  eu.op.sh.co.ShinyProxyController     - [default-localhost/3500196eb4d8294a5bccf475e7b4884f8a653b6e/0] [Step 0/4: Ok] ReconcileSingleShinyProxy
09:33:24.827 [atcher-worker-1] INFO  eu.op.sh.im.do.RedisConfig           - [Redis] Pulling image
09:33:25.857 [atcher-worker-1] INFO  eu.op.sh.im.do.RedisConfig           - [Redis] Creating new container
09:33:26.212 [atcher-worker-1] INFO  eu.op.sh.im.do.DockerOrchestrator    - [default-localhost/3500196eb4d8294a5bccf475e7b4884f8a653b6e/0] [Docker] Pulling image
09:33:26.752 [atcher-worker-3] INFO  eu.op.sh.im.do.DockerOrchestrator    - [default-localhost/3500196eb4d8294a5bccf475e7b4884f8a653b6e/0] [Docker] Creating new container
09:33:27.080 [atcher-worker-3] INFO  eu.op.sh.co.ShinyProxyController     - [default-localhost/3500196eb4d8294a5bccf475e7b4884f8a653b6e/0] [Step 1/4: Reconciling] [Container]
09:33:27.372 [atcher-worker-1] INFO  u.op.sh.im.do.ShinyProxyReadyChecker - [default-localhost/3500196eb4d8294a5bccf475e7b4884f8a653b6e/0] [Container: 601d0fa70223a] not ready yet (0/24)
09:33:32.407 [atcher-worker-1] INFO  u.op.sh.im.do.ShinyProxyReadyChecker - [default-localhost/3500196eb4d8294a5bccf475e7b4884f8a653b6e/0] [Container: 601d0fa70223a] not ready yet (1/24)
09:33:37.436 [atcher-worker-1] INFO  u.op.sh.im.do.ShinyProxyReadyChecker - [default-localhost/3500196eb4d8294a5bccf475e7b4884f8a653b6e/0] [Container: 601d0fa70223a] not ready yet (2/24)
09:33:42.845 [atcher-worker-1] INFO  u.op.sh.im.do.ShinyProxyReadyChecker - [default-localhost/3500196eb4d8294a5bccf475e7b4884f8a653b6e/0] [Container: 601d0fa70223a] ready
09:33:42.852 [atcher-worker-3] INFO  eu.op.sh.co.ShinyProxyController     - [default-localhost/3500196eb4d8294a5bccf475e7b4884f8a653b6e/0] [Step 0/4: Ok] ReconcileSingleShinyProxy
09:33:42.910 [atcher-worker-3] INFO  eu.op.sh.co.ShinyProxyController     - [default-localhost/3500196eb4d8294a5bccf475e7b4884f8a653b6e/0] [Step 1/4: Ok] [Container]
09:33:42.920 [atcher-worker-3] INFO  eu.op.sh.co.ShinyProxyController     - [default-localhost/3500196eb4d8294a5bccf475e7b4884f8a653b6e/0] [Step 2/4: Ok] [LatestMarker] Instance became latest
09:33:42.921 [atcher-worker-3] INFO  eu.op.sh.co.ShinyProxyController     - [default-localhost/3500196eb4d8294a5bccf475e7b4884f8a653b6e/0] [Step 3/4: Reconciling] [Ingress]
09:33:42.947 [atcher-worker-1] INFO  eu.op.sh.im.do.CaddyConfig           - [Caddy] Pulling image
09:33:43.875 [atcher-worker-1] INFO  eu.op.sh.im.do.CaddyConfig           - [Caddy] Creating new container
09:33:44.162 [atcher-worker-1] INFO  eu.op.sh.im.do.CaddyConfig           - [Caddy] Not ready yet (0/24)
09:33:44.689 [atcher-worker-1] INFO  eu.op.sh.im.do.CaddyConfig           - [Caddy] Ready (1/24)

The ShinyProxy server is now ready to use and is accessible by going to the configured domain name (e.g. http://localhost/). You can login by using the username jack and the password password. Click on Hello Application to start the first demo app.

See the troubleshooting section if your servers fails to start.

Updating a ShinyProxy server

Updating the configuration of a ShinyProxy server (e.g. to add a new app) is as simple as modifying the configuration file and waiting for the operator to create a new instance. There is no need to restart the ShinyProxy Operator (or its container). The operator checks the input file every minute for changes. So after changing the config file, the operator automatically detects the changed and re-tries deploying the ShinyProxy server.

Enabling TLS

Using Let’s Encrypt

The ShinyProxy Operator makes use of Caddy as a reverse proxy. A unique feature of Caddy is that it’s able to fully automatically configure TLS for your domain, typically using the free certificates provided by Let’s Encrypt.

  1. Before enabling TLS, make sure to meet the following requirements:

    • ShinyProxy is configured to use a public domain name (e.g. shinyproxy.example.com)
    • DNS is configured, such that this domain name points to your server
    • the ShinyProxy server is accessible over the internet

    Note: Caddy automatically renews the certificate when needed, therefore, the server must be accessible from the internet at all times.

  2. Add the SPO_CADDY_ENABLE_TLS: "true" environment variable to the docker-compose.yml file:

    services:
      shinyproxy-operator:
        image: openanalytics/shinyproxy-operator:2.2.0
        # ...
        environment:
          SPO_ORCHESTRATOR: docker
          SPO_DOCKER_GID: 1234 # replace by the id of step 6
          SPO_CADDY_ENABLE_TLS: "true"
        # ...
    
  3. Restart the ShinyProxy Operator (this is only needed once, because we added the SPO_CADDY_ENABLE_TLS environment variable):

    sudo docker compose -f /home/shinyproxy/shinyproxy/docker-compose.yml down
    sudo docker compose -f /home/shinyproxy/shinyproxy/docker-compose.yml up -d
    

If you aren’t sure whether all requirements are met, you can simply try enabling TLS and observe whether it works. If not, the Caddy logs contain more information:

sudo docker logs -f sp-caddy

Using custom certificates

The operator allows to use a certificate you already own. This is useful for deployments in organisations with a custom PKI.

  1. Add the SPO_CADDY_ENABLE_TLS: "true" environment variable to the docker-compose.yml file:

    services:
      shinyproxy-operator:
        image: openanalytics/shinyproxy-operator:2.2.0
        # ...
        environment:
          SPO_ORCHESTRATOR: docker
          SPO_DOCKER_GID: 1234 # replace by the id of step 6
          SPO_CADDY_ENABLE_TLS: "true"
        # ...
    
  2. Put your certificates somewhere in the input directory. In this example we put the cert and key at:

    • /home/shinyproxy/shinyproxy/input/mycert.crt
    • /home/shinyproxy/shinyproxy/input/mycert.key
  3. Change the ShinyProxy configuration to reference the cert and key. Use the absolute path inside the operator container. In our example, we’re using the input directory to store the certs, therefore we can use the following config:

    proxy:
      # ....
    caddyTlsCertFile: /opt/shinyproxy-docker-operator/input/mycert.crt
    caddyTlsKeyFile: /opt/shinyproxy-docker-operator/input/mycert.key
    
  4. Restart the ShinyProxy Operator (this is only needed once, because we added the SPO_CADDY_ENABLE_TLS environment variable):

    sudo docker compose -f /home/shinyproxy/shinyproxy/docker-compose.yml down
    sudo docker compose -f /home/shinyproxy/shinyproxy/docker-compose.yml up -d
    

Enabling monitoring

The operator includes a complete monitoring stack for ShinyProxy. This collects logs, metrics, and usage statistics. The following open source components are used:

Grafana acts as the UI for all these components. It’s automatically embedded in Grafana, meaning you can re-use the authentication of ShinyProxy to access it. Only admin users can access it.

To enable monitoring:

  1. Install the Loki Docker driver. The operator includes a script to do this:

    sudo docker run --group-add $(getent group docker | cut -d: -f3)  -v /var/run/docker.sock:/var/run/docker.sock:ro openanalytics/shinyproxy-operator:2.2.0 /install_plugins.sh
    
  2. Add the SPO_ENABLE_MONITORING: "true" environment variable to the docker-compose.yml file:

    services:
      shinyproxy-operator:
        image: openanalytics/shinyproxy-operator:2.2.0
        # ...
        environment:
          SPO_ORCHESTRATOR: docker
          SPO_DOCKER_GID: 1234 # replace by the id of step 6
          SPO_ENABLE_MONITORING: "true"
        # ...
    
  3. Add the log configuration to the docker-compose.yml file. This is required to collect the logs of the operator itself:

    services:
      shinyproxy-operator:
        image: openanalytics/shinyproxy-operator:2.2.0
        # ...
      logging:
        driver: loki
        options:
          loki-url: "http://localhost:3100/loki/api/v1/push"
          mode: non-blocking
          loki-external-labels: app=shinyproxy-operator,namespace=default
    
  4. Restart the ShinyProxy Operator (this is only needed once, because we modified the docker-compose.yml file):

    sudo docker compose -f /home/shinyproxy/shinyproxy/docker-compose.yml down
    sudo docker compose -f /home/shinyproxy/shinyproxy/docker-compose.yml up -d
    
  5. Add a user (e.g. jack) as an admin (in the ShinyProxy configuration):

    proxy:
      # ...
      admin-users:
       - jack
    

After a few minutes all components should be running. Grafana is now accessible at the /grafana sub-path on your ShinyProxy server. For example, if your fqdn is localhost, Grafana is accessible at http://localhost/grafana.

Adding templates

The look and feel of ShinyProxy can be customized by editing the templates. When using the operator you can put custom templates in the input/templates/<realm-id>/ directory. Where input/ is the directory where the ShinyProxy configuration files are located and <realm-id> is the value of the proxy.realm-id property.

If the operator has discovered the templates it logs a line similar too:

13:36:39.723 [atcher-worker-1] INFO  eu.op.sh.im.do.DockerOrchestrator    - [default-localhost/global] [Docker] Templates copied

If this line doesn’t appear in the logs, the templates are probably placed in the wrong directory.

Configuration reference

Operator configuration

In most situations, the operator itself needs very little configuration. Nevertheless, for some specific cases some configuration options are available. These options are specified using environment variables. All variables start with the SPO prefix, meaning ShinyProxyOperator.

  • SPO_ORCHESTRATOR: (required) can either be kubernetes (default) or docker.
  • SPO_DOCKER_GID: (required)
  • SPO_LOG_LEVEL: configures the log level of the operator, may be one of the following:
    • OFF: disables logging
    • ERROR
    • WARN
    • INFO
    • DEBUG: default (may change)
    • TRACE
    • ALL: enables all logging
  • SPO_CADDY_ENABLE_TLS: (optional) boolean flag enabling TLS, disabled by default.
  • SPO_ENABLE_MONITORING: (optional) boolean flag enabling monitoring, disabled by default.
  • SPO_GRAFANA_ROLE: (optional) the role used by Grafana for new users. Valid options are Admin, Editor and Viewer (default).
  • SPO_IMAGE_PULL_POLICY: (optional) pull policy for images used by the operator (e.g. Redis and Caddy). Doesn’t apply to the image of ShinyProxy itself and doesn’t change the behavior of ShinyProxy. Valid options are Never, IfNotPresent and Always (default).

The following options are more advanced and may cause problems if not used correctly:

  • SPO_DISABLE_ICC: (optional) boolean flag enabling inter-container connectivity, enabled by default. Disabling this requires additional setup and configuration.
  • SPO_FILE_POLL_INTERVAL: (optional) time in seconds that ShinyProxy waits before checking for changes in configuration
  • SPO_DOCKER_SOCKET: (optional) the location of the Docker socket on the host, default is /var/run/docker.sock.
  • SPO_DOCKER_DATA_DIR: the directory where ShinyProxy stores its data, default is /opt/shinyproxy-docker-operator/data/
  • SPO_INPUT_DIR: the directory containing the input (configuration) files, default is /opt/shinyproxy-docker-operator/input
  • SPO_CADDY_IMAGE: the Caddy image to use, default is docker.io/library/caddy:2.8
  • SPO_CADVISOR_IMAGE: the cAdvisor image to use, default is gcr.io/cadvisor/cadvisor:v0.49.1
  • SPO_GRAFANA_IMAGE: the Grafana image to use, default is docker.io/grafana/grafana-oss:11.6.1
  • SPO_GRAFANA_LOKI_IMAGE: the Grafana Loki image to use, default is docker.io/grafana/loki:3.2.2
  • SPO_PROMETHEUS_IMAGE: the Prometheus image to use, default is docker.io/prom/prometheus:v3.0.1
  • SPO_REDIS_IMAGE: the Redis image to use, default is docker.io/library/redis:7.2.4

ShinyProxy configuration

Configuration (of the operator) that’s specific to a single ShinyProxy server, must be configured in the configuration file of that ShinyProxy Server. In other words, both the operator and ShinyProxy itself read this configuration file. The following configuration options can be used:

  • image: (required) the Docker image to use for ShinyProxy (e.g. openanalytics/shinyproxy:3.2.0)
  • image-pull-policy: (optional) pull policy for the ShinyProxy image (doesn’t change the behavior of ShinyProxy). Valid options are Never, IfNotPresent and Always (default).
  • fqdn: (required) the fully qualified domain name, used to access ShinyProxy
  • proxy.realm-id: (required) identifier of the ShinyProxy server. Used in logs, the monitoring stack and Redis. Maximum length is 63 characters, only alphanumeric characters and - allowed, but may not start or end with -.
  • additionalFqdns: (optional) a list of additional FQDNs that can be used to access ShinyProxy.
  • replicas: (optional) the number of ShinyProxy replicas to run.
  • labels: (optional) map of labels to add to the ShinyProxy container.
  • memory-request: (optional) the minimum amount of memory available to a single ShinyProxy instance. Uses the same format as for apps. For example 1G.
  • memory-limit: (optional) the maximum amount of memory available to a single ShinyProxy instance. Uses the same format as for apps. For example 1G.
  • cpu-limit: (optional) the maximum amount of CPU time available to a single ShinyProxy instance. Uses the same format as for apps. For example 1 (= 1 CPU core).
  • dns: (optional) list of DNS servers to be used by the ShinyProxy container.
  • caddyTlsCertFile: (optional) path to a TLS certificate file (see Enabling TLS).
  • caddyTlsKeyFile: (optional) path to a TLS key file(see Enabling TLS).

Mandatory configuration

In order for the operator to work correctly, the following configuration must always be included in every input file. In addition, don’t change the values.

spring:
  session:
    store-type: redis
proxy:
  store-mode: Redis
  docker:
    internal-networking: true
  stop-proxies-on-shutdown: false
  authentication: simple

Forbidden configuration

To make things easy, the operator automatically adds a few configuration properties to the ShinyProxy configuration. These configuration properties shouldn’t be used in the input files. The full list of forbidden properties is:

  • logging.file.name
  • management.prometheus.metrics.export.enabled
  • management.server.port
  • proxy.docker.loki-url
  • proxy.log-as-json
  • proxy.monitoring.grafana-url
  • proxy.port
  • proxy.template-path
  • proxy.usage-stats-url
  • spring.config.import
  • spring.data.redis.host
  • spring.data.redis.password

Troubleshooting

Issue with the data directory

The operator requires a data directory, in order to share files between the multiple containers it creates. This data directory exists on the Docker host and is mounted in the container. The directory must exist before the operator is started, and must be owned by a non-root user. Finally, the id of the owner of this directory must be set inside the docker-compose.yml file.

If one of these pre-requisites isn’t met, the operator may fail with one these errors:

  • Exception: The data directory doesn't exist: '/opt/shinyproxy-docker-operator/data'!
  • Exception: Missing read permission for the data directory: '/opt/shinyproxy-docker-operator/data'!
  • Exception: Missing write permission for the data directory: '/opt/shinyproxy-docker-operator/data'!

To fix this, follow these steps:

  1. Re-create the directory:

    sudo mkdir -p /opt/shinyproxy-docker-operator/data
    
  2. Change the owner of the directory to the non-root user, e.g. shinyproxy:

    sudo chown shinyproxy:shinyproxy /opt/shinyproxy-docker-operator
    sudo chown shinyproxy:shinyproxy /opt/shinyproxy-docker-operator/data
    
  3. Change the permissions of the directory:

    sudo chmod 755 /opt/shinyproxy-docker-operator
    sudo chmod 755 /opt/shinyproxy-docker-operator/data
    
  4. Check that the docker-compose.yml file contains a volume mapping for the data directory:

    1
    2
    3
    4
    5
    6
    7
    8
    
    services:
      shinyproxy-operator:
        # ...
        volumes:
          - ./input:/opt/shinyproxy-docker-operator/input
          - /var/run/docker.sock:/var/run/docker.sock:ro
          - /opt/shinyproxy-docker-operator/data:/opt/shinyproxy-docker-operator/data
        # ...
    
  5. Check that the container runs as the non-root user:

    • Get the id of the user:

      sudo id -u shinyproxy
      
    • Then make sure it’s configured in the docker-compose.yml file:

      1
      2
      3
      4
      
      services:
        shinyproxy-operator:
          # ...
          user: "1234" # replace by the id of the previous step (must be a sting)
      
  6. Re-create the container:

    sudo docker compose -f /home/shinyproxy/shinyproxy/docker-compose.yml down
    sudo docker compose -f /home/shinyproxy/shinyproxy/docker-compose.yml up -d
    

Issue with the input directory

The operator reads the configuration files (for ShinyProxy) from an input directory. Similarly, to the data directory, this directory must be mounted in the container and also accessible the container.

If this isn’t the case, the operator may fail with the error:

Exception: Missing read permission for the input '/opt/shinyproxy-docker-operator/input' directory!

To fix this, follow these steps:

  1. Re-create the directory (the input directory must be created in the same directory as the docker-compose.yml file):

    sudo mkdir -p /home/shinyproxy/shinyproxy/input
    
  2. Change the owner of the directory to the non-root user, e.g. shinyproxy:

    sudo chown shinyproxy:shinyproxy /home/shinyproxy/shinyproxy/input
    
  3. Change the permissions of the directory:

    sudo chmod 755 /home/shinyproxy/shinyproxy/input
    
  4. Check that the docker-compose.yml file contains a volume mapping for the data directory:

    1
    2
    3
    4
    5
    6
    7
    8
    
    services:
      shinyproxy-operator:
        # ...
        volumes:
          - ./input:/opt/shinyproxy-docker-operator/input
          - /var/run/docker.sock:/var/run/docker.sock:ro
          - /opt/shinyproxy-docker-operator/data:/opt/shinyproxy-docker-operator/data
        # ...
    
  5. Re-create the container:

    sudo docker compose -f /home/shinyproxy/shinyproxy/docker-compose.yml down
    sudo docker compose -f /home/shinyproxy/shinyproxy/docker-compose.yml up -d
    

Issue with the Docker socket

The ShinyProxy Operator (just like ShinyProxy itself) needs access to the Docker daemon. This is archived by mounting the Docker socket into the container. The socket is owned by the docker group. To ensure that the operator can use the socket, it must be part of the docker group. Therefore, the id of the group must be configured in the docker-compose.yml file.

If one of these pre-requisites isn’t met, the operator may fail with the error:

Exception: No permission to access Docker daemon, check the mount of the socket and the 'SPO_DOCKER_GID' environment variable.

To fix this, follow these steps:

  1. Fix the permissions of the Docker socket:

    sudo chown -R root:docker /var/run/docker.sock
    
  2. Get the id of the docker group:

    sudo getent group docker | cut -d: -f3
    
  3. Check that the docker-compose.yml file contains this id at two places: in the SPO_DOCKER_GID environment variable and in the group_add parameter:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    
    services:
      shinyproxy-operator:
        # ...
        environment:
          SPO_ORCHESTRATOR: docker
          SPO_DOCKER_GID: 1234 # replace by the id of step 2
        group_add:
          - 1234 # replace by the id of step 2
        # ...
    
  4. Check that the docker-compose.yml file contains a volume mapping for the Docker socket:

    1
    2
    3
    4
    5
    6
    7
    8
    
    services:
      shinyproxy-operator:
        # ...
        volumes:
          - ./input:/opt/shinyproxy-docker-operator/input
          - /var/run/docker.sock:/var/run/docker.sock:ro
          - /opt/shinyproxy-docker-operator/data:/opt/shinyproxy-docker-operator/data
        # ...
    
  5. Check that the docker-compose.yml file doesn’t contain a value for the SPO_DOCKER_SOCKET environment variable

  6. Re-create the container:

    sudo docker compose -f /home/shinyproxy/shinyproxy/docker-compose.yml down
    sudo docker compose -f /home/shinyproxy/shinyproxy/docker-compose.yml up -d
    

ShinyProxy fails to start

There can be many reasons why your ShinyProxy servers fails to start, therefore start by looking at the logs of the operator using:

sudo docker compose -f /home/shinyproxy/shinyproxy/docker-compose.yml logs -f

In many cases the logs of the operator already explains the issue and a potential solution. For example, if you specify an incorrect image, you’ll receive an error similar to:

org.mandas.docker.client.exceptions.ImageNotFoundException: Image not found: my-example-image

The solution is then to modify the input file (e.g. /home/shinyproxy/shinyproxy/input/localhost.shinyproxy.yaml) and change the image property.

Another common issue is that the operator is able to create the ShinyProxy container, but the container fails to startup. This is usually caused by some invalid properties in the configuration file. In most cases, the operator already logs the error reported by ShinyProxy:

09:55:35.175 [atcher-worker-2] INFO  u.op.sh.im.do.ShinyProxyReadyChecker - [default-localhost/24a8189e821d0edaa7997848cfea33b6917fec17/0] [Container: b328fb7bd6875] not ready yet (2/24)
09:55:40.183 [atcher-worker-2] INFO  u.op.sh.im.do.ShinyProxyReadyChecker - [default-localhost/24a8189e821d0edaa7997848cfea33b6917fec17/0] [Container: b328fb7bd6875] failed (container has been restarted) (3/24)
09:55:40.205 [atcher-worker-2] INFO  eu.op.sh.co.ShinyProxyController     - [default-localhost/24a8189e821d0edaa7997848cfea33b6917fec17/0] Instance failed to start up, output: Full log file available at '/opt/shinyproxy-docker-operator/data/logs/sp-default-localhost-24a8189e821d0edaa7997848cfea33b6917fec17-0-LPIOHqcFin/shinyproxy.log', last output: ShinyProxy crashed! Exception: 'java.lang.RuntimeException', message: 'Unknown authentication type:simpl'

In this example, we used the following invalid config:

proxy:
  authentication: simpl

And as expected, the error indicates the incorrect property: Unknown authentication type:simpl. Changing this to the correct value, will fix the issue and allow ShinyProxy to start:

proxy:
  authentication: simple

If the issues doesn’t become clear from the operator logs, the next step is to look at the full logs of ShinyProxy itself. The operator automatically stores these logs on disk in the /opt/shinyproxy-docker-operator/data/logs/ directory. As can be seen in the example logs, the operator also reports the exact location of the logs. You can easily view these logs on the Docker host using:

less /opt/shinyproxy-docker-operator/data/logs/sp-default-localhost-24a8189e821d0edaa7997848cfea33b6917fec17-0-LPIOHqcFin/shinyproxy.log

In some cases these logs can be empty, especially when an error occurs before ShinyProxy can write it logs. In this case you can find the error using the Docker CLI:

  1. List all containers:

    sudo docker ps -a
    
  2. Find the ShinyProxy container in the list, and copy its name

  3. View the logs of the container:

    sudo docker logs -f sp-default-localhost-24a8189e821d0edaa7997848cfea33b6917fec17-0-LPIOHqcFin
    
  4. If you suspect an issue with the configuration of the container, you can inspect the container to view all its configuration:

    sudo docker inspect sp-default-localhost-24a8189e821d0edaa7997848cfea33b6917fec17-0-LPIOHqcFin
    

Finally, make sure to check that you have set all mandatory config and aren’t using any forbidden config.