Running Shiny Server with a Proxy

Follow

Shiny Server: Running with a Proxy

Overview

If you are running Shiny Server behind a proxy server you need be sure to configure the proxy server so that it correctly handles all traffic to and from Shiny Server. Beyond the normal reverse proxy configuration you'd apply for any HTTP server application, you also need to ensure that websockets are forwarded correctly between the proxy server and Shiny Server so that Shiny applications will run properly. This article describes how to correctly configure a reverse proxy with Nginx and Apache.

Nginx Configuration

On Debian or Ubuntu a version of Nginx that supports reverse-proxying can be installed using the following command:

sudo apt-get install nginx

On CentOS or Red Hat you can install Nginx using the following command:

sudo yum install nginx

To enable an instance of Nginx running on the same server to act as a front-end proxy to Shiny Server you would add commands like the following to your nginx.conf file. Note that you must add code to proxy websockets in order to correctly display Shiny apps and R Markdown Shiny documents in Shiny Server.

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; } } }

If you want to serve Shiny Server from a custom path (e.g. /shiny) you would edit your nginx.conf file as shown below:

http {

  map $http_upgrade $connection_upgrade {
    default upgrade;
    ''      close;
  }

  server {
    listen 80;

    rewrite ^/shiny$ $scheme://$http_host/shiny/ permanent;
    
    location /shiny/ {
      rewrite ^/shiny/(.*)$ /$1 break;
      proxy_pass http://localhost:3838;
      proxy_redirect / $scheme://$http_host/shiny/;
      proxy_http_version 1.1;
      proxy_set_header Upgrade $http_upgrade;
      proxy_set_header Connection $connection_upgrade;
      proxy_read_timeout 20d;
      proxy_buffering off;
    }
  }
}

In addition, if you also want to proxy the admin dashboard, you'll need to add a separate directive for that port as well - for instance:

    location /shiny-admin/ {
      rewrite ^/shiny-admin/(.*)$ /$1 break;
      proxy_pass http://localhost:4151;
      proxy_redirect / $scheme://$http_host/shiny-admin/;
      proxy_http_version 1.1;
      proxy_set_header Upgrade $http_upgrade;
      proxy_set_header Connection $connection_upgrade;
      proxy_read_timeout 20d;
      proxy_buffering off;
    }

After adding these entries you'll then need to restart Nginx so that the proxy settings take effect:

sudo /etc/init.d/nginx restart

Nginx SSL Configuration

First, follow instructions in the previous section to install Nginx. 

Next, you will need to create or purchase a SSL certificate. This will work with a self-signed certificate, but you should use an officially signed certificate if you want to avoid browser error codes.

Next, you will need to create a new configuration file for your Shiny Server in the /etc/nginx/sites-available directory. Here is an example of what that content might look like:

map $http_upgrade $connection_upgrade {
  default upgrade;
  '' close;
}

server {
  listen 443;
  server_name <your_server_name>;

  ssl    on;
  ssl_session_timeout  5m;
  ssl_protocols  TLSv1.2;
  ssl_ciphers  HIGH:!aNULL:!MD5;
  ssl_prefer_server_ciphers   on;

  ssl_certificate        <path_ssl_cert_file>;
  ssl_certificate_key    <path_to_ssl_key_file>;

  access_log /var/log/nginx/<your-site>.log;
  error_log /var/log/nginx/<your-site>-error.log error;

  location / {

    proxy_set_header    Host $host;
    proxy_set_header    X-Real-IP $remote_addr;
    proxy_set_header    X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header    X-Forwarded-Proto $scheme;
    proxy_pass          http://localhost:3838;
    proxy_read_timeout  20d;
    proxy_buffering off;

    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection $connection_upgrade;
    proxy_http_version 1.1;

    proxy_redirect      / $scheme://$host/;
  }
}

Note that your particular SSL requirements may be different and you may need to change this setup accordingly.

After creating this file, create a symlink in the /etc/nginx/sites-enabled directory pointing to the above file as in the following:

ln -s /etc/nginx/sites-available/shiny-server /etc/nginx/sites-enabled/shiny-server

and then restart Nginx.

Apache Configuration

To enable an instance of Apache running on the same server to act as a front-end proxy to Shiny Server you need to use the mod_proxy and mod_proxy_wstunnel modules. The steps for enabling this module vary across operating systems so you should consult your distribution's Apache documentation for details.

On Debian and Ubuntu systems Apache can be installed with mod_proxy using the following commands:

sudo apt-get install apache2
sudo apt-get install libapache2-mod-proxy-html
sudo apt-get install libxml2-dev

Then, to update the Apache configuration files to activate mod_proxy you execute the following commands:

sudo a2enmod proxy
sudo a2enmod proxy_http
sudo a2enmod proxy_wstunnel

On CentOS and RedHat systems Apache can be installed with mod_proxy and mod_proxy_wstunnel by following the instructions here:

http://httpd.apache.org/docs/2.4/platform/rpm.html

By default with Apache 2.4, mod_proxy and mod_proxy_wstunnel should be enabled. You can check this by opening the file /etc/httpd/conf.modules.d/00-proxy.conf and making sure the following lines are included and not commented out:

LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_wstunnel_module modules/mod_proxy_wstunnel.so

Once you have enabled mod_proxy and mod_proxy_wstunnel in your Apache installation you need to add the required proxy commands to your VirtualHost definition. Note that you will also need to include code to correctly proxy websockets in order to correctly proxy Shiny apps and R Markdown documents within Shiny Server. For example:

<VirtualHost *:80>

  <Proxy *>
    Allow from localhost
  </Proxy>
 
 RewriteEngine on
RewriteCond %{HTTP:Upgrade} =websocket
RewriteRule /(.*) ws://localhost:3838/$1 [P,L]
RewriteCond %{HTTP:Upgrade} !=websocket
RewriteRule /(.*) http://localhost:3838/$1 [P,L]
ProxyPass / http://localhost:3838/
ProxyPassReverse / http://localhost:3838/
ProxyRequests Off </VirtualHost>

Note that if you want to serve Shiny from a custom path (e.g. /shiny) you would replace the directives described above to:

 RedirectMatch permanent ^/shiny$ /shiny/

RewriteEngine on
RewriteCond %{HTTP:Upgrade} =websocket
RewriteRule /shiny/(.*) ws://localhost:3838/$1 [P,L]
RewriteCond %{HTTP:Upgrade} !=websocket
RewriteRule /shiny/(.*) http://localhost:3838/$1 [P,L]
ProxyPass /shiny/ http://localhost:3838/
ProxyPassReverse /shiny/ http://localhost:3838/

Header edit Location ^/ /shiny/
ProxyRequests Off

Note that in some environments, if you have issues with the above configuration when using the proxy to redirect multiple locations, then the following may need to be commented out:

# Header edit Location ^/ /shiny/

In addition, if you also want to proxy the admin dashboard, you'll need to add a separate directive for that port as well - for instance:

ProxyPass /shiny-admin/ http://localhost:4151/
ProxyPassReverse /shiny-admin/ http://localhost:4151/

Finally, after you've completed all of the above steps you'll then need to restart Apache so that the proxy settings take effect:

sudo /etc/init.d/apache2 restart

 

 

Comments