Search code examples
rdockershinyshinyproxy

How to fix '404 (Not Found)' errors when sourcing CSS and Javascript files in ShinyProxy


I am trying to launch a shiny app using ShinyProxy - something I have done many times before. However, this app is not correctly using any of the CSS or JS files that is required to make it run.

When I run the app manually with docker run -p 3838:3838 my_app everything works perfectly fine. However, when pointing ShinyProxy to the my_app image, the resulting app fails to load any CSS or JS files.

Dockerfile

FROM openanalytics/r-base

MAINTAINER Daniel Beachnau "[email protected]"

# Dependencies outside of R
RUN apt-get update && apt-get install -y \
    sudo \
    gdebi-core \
    pandoc \
    pandoc-citeproc \
    libcurl4-gnutls-dev \
    libcairo2-dev \
    libxt-dev \
    xtail \
    wget \
    libpq-dev \
    libmariadb-client-lgpl-dev \
    # Might be needed for the archivist R-Library
    dbus \
    systemd \
    # needed for odbc
    unixodbc-dev

RUN apt-get install apt-transport-https curl -y
RUN curl http://packages.microsoft.com/keys/microsoft.asc | apt-key add -
RUN curl https://packages.microsoft.com/config/ubuntu/16.04/prod.list > /etc/apt/sources.list.d/mssql-release.list
RUN apt-get update
RUN ACCEPT_EULA=Y apt-get install msodbcsql17 -y

# Download R-Packages
# tidyverse
RUN R -e "install.packages('tidyr')"
RUN R -e "install.packages('dplyr')"
RUN R -e "install.packages('readr')"
# Shiny Packages
RUN R -e "install.packages('shiny')"
RUN R -e "install.packages('shinycssloaders')"
RUN R -e "install.packages('shinydashboard')"
RUN R -e "install.packages('shinyWidgets')"
RUN R -e "install.packages('DT')"
RUN R -e "install.packages('shinyjs')"
RUN R -e "install.packages('flexdashboard')"
# Database Packages
RUN R -e "install.packages('odbc')"
RUN R -e "install.packages('RMySQL')"
# Other
RUN R -e "install.packages('devtools')"
RUN R -e "install.packages('lubridate')"
RUN R -e "install.packages('reshape2')"
RUN R -e "install.packages('grid')"
RUN R -e "install.packages('lemon')"
RUN R -e "install.packages('scales')"
RUN R -e "install.packages('ggthemes')"
RUN R -e "install.packages('ggplot2')"

RUN R -e "devtools::install_bitbucket(repo = 'my_repo/my_package',  auth_user = 'my_username', password = 'my_password')"

# copy the app to the image
COPY . /root

# run the script to update the app data
WORKDIR /root
RUN Rscript app_data_update.R

WORKDIR /root/app
COPY Rprofile.site /usr/lib/R/etc/
EXPOSE 3838
CMD ["R", "-e", "shiny::runApp('/root/app', host='0.0.0.0', port=3838)"]

application.yml

shiny:
  proxy:
    title: ShinyProxy Server
    logo-url: /images/logo-image.png
    landing-page: /
    heartbeat-rate: 10000
    heartbeat-timeout: 60000
    container-wait-time: 60000
    port: 8080
    authentication: ldap

    # Docker configuration
    docker:
      cert-path: /home/none
      url: http://localhost:2375
      port-range-start: 20000
    support:
      container-log-path: ./container-logs
      mail-to-address: [email protected],

  - name: my_apps_name
    display-name: Shiny App
    docker-image: dbeachnau/my_app
    groups: [Shiny Users Management]
    logo-url: /images/logo-image.png
    container-volumes: ["/path/to/app:/root/app"]


logging:
  file:
    shinyproxy.log

Here is how app looks in shiny proxy.

problem

Here is hoe my app looks when running manually.

desired

The console in chrome's inspect tool is replete with errors such as

GET https://myshinyserver.com/container_name/font-awesome-5.3.1/css/all.min.css net::ERR_ABORTED 404 (Not Found)

I do have other apps running on ShinyProxy which display properly, but I cannot solve the difference between how those apps are configured to how this app is configured. Let me know if additional details are required for diagnosing the issue. All feedback is appreciated - thank you.


Solution

  • You're probably seeing this with Shiny v1.3.0, and not with earlier versions. If so, it's probably because of a misconfiguration in your NGINX proxy directives. I've written up the details here, but I'll also post the salient details here.

    proxy_set_header Connection "upgrade";
    

    This directive causes NGINX to add a Connection: upgrade header to every HTTP request, when it's only supposed to be used for WebSockets.

    This line is recommended by NGINX Inc. themselves, however, those recommendations are intended for proxying of traffic that is exclusively WebSockets, whereas Shiny traffic is a combination of normal HTTP requests and WebSockets. Older versions of shiny/httpuv didn't mind this situation, but the new versions are stricter.

    A correct configuration looks something like this:

    http {
    
      map $http_upgrade $connection_upgrade {
          default upgrade;
          ''      close;
        }
    
      server {
        listen 80;
    
    
        location / {
          proxy_pass http://localhost:3838;
          proxy_redirect / $scheme://$http_host/;
          proxy_http_version 1.1;
          proxy_set_header Upgrade $http_upgrade;
          proxy_set_header Connection $connection_upgrade;
          proxy_read_timeout 20d;
          proxy_buffering off;
        }
      }
    }
    

    See the articles linked in the RStudio Community post for other examples.