<p><div><div><div><div data-width="100" data-show-faces="false" data-send="true" data-layout="button_count" data-height="21" data-href="https://www.r-bloggers.com/setup-encrypted-rstudio-and-shiny-dashboard-solution-in-3-minutes/"></div></div><div></div></div><div></div></div>
<div>
(This article was first published on <strong><a href="http://www.56n.dk/setup-encrypted-rstudio-and-shiny-dashboard-solution-in-3-minutes/"> Renglish – 56north | Skræddersyet dataanalyse</a></strong>, and kindly contributed to <a rel="nofollow" href="https://www.r-bloggers.com/">R-bloggers)</a> </div>
<p>I have created a repository (https://github.com/56north/encrypted_dashboard) with code that automatically sets up Rstudio Server and Shiny Server behind and Nginx proxy with SSL certificates. The two servers share apps and packages so you can build cool stuff in Rstudio and deploy it immediately to Shiny. Woow!!! <img alt="😀" class="wp-smiley" src="https://i2.wp.com/s.w.org/images/core/emoji/2/72x72/1f600.png?w=456&ssl=1" data-recalc-dims="1"></p>
<p>Below is the readme from the repo. I do need help fixing some issues, but I am quite certain you guys can help with that. If we collaborate on this then we will all have a pretty awesome way to quickly setup an encrypted and easy to use dashboard environment.</p>
<h1>Docker + Nginx + Let’s Encrypt + Rstudio + Shiny</h1>
<hr>
<h2><a target="_blank" rel="nofollow" href="https://github.com/56north/encrypted_dashboard/blob/master/README.md#need-to-have-fixed"></a>NEED TO HAVE FIXED</h2>
<p><strong>SSL for all</strong></p>
<p>It seems that only one of the containers aquire the SSL certificate. Maybey someone with more Nginx skills than me can have a look.</p>
<p><strong>Upload limit</strong></p>
<p>There seems to be an upload-limit when we’re running behind Nginx. This can be fixed in the config file. If any knows how, please do. Here is a link I found regarding the issue: <a target="_blank" rel="nofollow" href="https://support.rstudio.com/hc/en-us/community/posts/200769376--Unexpected-response-from-server-error-with-file-upload">https://support.rstudio.com/hc/en-us/community/posts/200769376–Unexpected-response-from-server-error-with-file-upload</a></p>
<h2><a target="_blank" rel="nofollow" href="https://github.com/56north/encrypted_dashboard/blob/master/README.md#nice-to-have-fixed"></a>NICE TO HAVE FIXED</h2>
<p><strong>Multiple users in Rstudio Server</strong></p>
<p>Would be nice to be able to create multiple users in Rstudio when firing up the docker container. Maybe based on some of the information here: <a target="_blank" rel="nofollow" href="https://itsalocke.com/r-training-environment/">https://itsalocke.com/r-training-environment/</a></p>
<hr>
<p>This code originated at <a target="_blank" rel="nofollow" href="https://github.com/gilyes/docker-nginx-letsencrypt-sample">https://github.com/gilyes/docker-nginx-letsencrypt-sample</a>.</p>
<p>This simple example shows how to set up Rstudio Server and Shiny Server running behind a dockerized Nginx reverse proxy and served via HTTPS using free <a target="_blank" rel="nofollow" href="https://letsencrypt.org/">Let’s Encrypt</a> certificates. New sites can be added on the fly by just modifying <code>docker-compose.yml</code> and then running <code>docker-compose up</code> as the main Nginx config is automatically updated and certificates (if needed) are automatically acquired.</p>
<p>Some of the configuration from the original repo is derived from <a target="_blank" rel="nofollow" href="https://github.com/fatk/docker-letsencrypt-nginx-proxy-companion-examples">https://github.com/fatk/docker-letsencrypt-nginx-proxy-companion-examples</a> with some simplifications and updates to work with current <code>nginx.tmpl</code> from <a target="_blank" rel="nofollow" href="https://github.com/jwilder/nginx-proxy">nginx-proxy</a> and docker-compose v2 files.</p>
<h2><a target="_blank" rel="nofollow" href="https://github.com/56north/encrypted_dashboard/blob/master/README.md#running-the-example"></a>Running the example</h2>
<h3><a target="_blank" rel="nofollow" href="https://github.com/56north/encrypted_dashboard/blob/master/README.md#prerequisites"></a>Prerequisites</h3>
<ul>
<li><a target="_blank" rel="nofollow" href="https://docs.docker.com/engine/installation/">docker</a> (>= 1.10)</li>
<li><a target="_blank" rel="nofollow" href="https://github.com/docker/compose/releases">docker-compose</a> (>= 1.8.1)</li>
<li>access to (sub)domain(s) pointing to a publicly accessible server (required for TLS)</li>
</ul>
<h3><a target="_blank" rel="nofollow" href="https://github.com/56north/encrypted_dashboard/blob/master/README.md#preparation"></a>Preparation</h3>
<ul>
<li>Clone the <a target="_blank" rel="nofollow" href="https://github.com/56north/encrypted_dashboard">repository</a> on the server pointed to by your domain.</li>
<li>In <code>docker-compose.yml</code>:
<ul>
<li>Change the <strong>VIRTUAL_HOST</strong> and <strong>LETSENCRYPT_HOST</strong> entries from <em>rstudio.mydomain.com</em> and <em>shiny.mydomain.com</em> to your domains.</li>
<li>Change <strong>LETSENCRYPT_EMAIL</strong> entries to the email address you want to be associated with the certificates.</li>
<li>Change <strong>USER</strong> and <strong>PASSWORD</strong> entries to the user and password you want for Rstudio.</li>
</ul>
</li>
</ul>
<h3><a target="_blank" rel="nofollow" href="https://github.com/56north/encrypted_dashboard/blob/master/README.md#running"></a>Running</h3>
<p>In the main directory run:</p>
<div>
<pre>docker-compose up</pre>
</div>
<p>This will perform the following steps:</p>
<ul>
<li>Download the required images from Docker Hub (<a target="_blank" rel="nofollow" href="https://hub.docker.com/_/nginx/">nginx</a>, <a target="_blank" rel="nofollow" href="https://hub.docker.com/r/jwilder/docker-gen/">docker-gen</a>, <a target="_blank" rel="nofollow" href="https://hub.docker.com/r/jrcs/letsencrypt-nginx-proxy-companion/">docker-letsencrypt-nginx-proxy-companion</a>).</li>
<li>Create containers from them.</li>
<li>Build and create containers for Rstudio Server and Shiny Server</li>
<li>Start up the containers.
<ul>
<li><em>docker-letsencrypt-nginx-proxy-companion</em> inspects containers’ metadata and tries to acquire certificates as needed (if successful then saving them in a volume shared with the host and the Nginx container).</li>
<li><em>docker-gen</em> also inspects containers’ metadata and generates the configuration file for the main Nginx reverse proxy</li>
</ul>
</li>
</ul>
<p>If everything went well then you should now be able to access Rstudio and Shiny and the given addresses.</p>
<h3><a target="_blank" rel="nofollow" href="https://github.com/56north/encrypted_dashboard/blob/master/README.md#troubleshooting"></a>Troubleshooting</h3>
<ul>
<li>To view logs run <code>docker-compose logs</code>.</li>
<li>To view the generated Nginx configuration run <code>docker exec -ti nginx cat /etc/nginx/conf.d/default.conf</code></li>
</ul>
<h2><a target="_blank" rel="nofollow" href="https://github.com/56north/encrypted_dashboard/blob/master/README.md#how-does-it-work"></a>How does it work</h2>
<p>The system consists of 4 main parts:</p>
<ul>
<li>Main Nginx reverse proxy container.</li>
<li>Container that generates the main Nginx config based on container metadata.</li>
<li>Container that automatically handles the acquisition and renewal of Let’s Encrypt TLS certificates.</li>
<li>The actual servers living in their own containers. In this example Rstudio and Shiny.</li>
</ul>
<h3><a target="_blank" rel="nofollow" href="https://github.com/56north/encrypted_dashboard/blob/master/README.md#the-main-nginx-reverse-proxy-container"></a>The main Nginx reverse proxy container</h3>
<p>This is the only publicly exposed container, routes traffic to the backend servers and provides TLS termination.</p>
<p>Uses the official <a target="_blank" rel="nofollow" href="https://hub.docker.com/_/nginx/">nginx</a> Docker image.</p>
<p>It is defined in <code>docker-compose.yml</code> under the <strong>nginx</strong> service block:</p>
<pre><code>services:
  nginx:
    restart: always
    image: nginx
    container_name: nginx
    ports:
      - &quot;80:80&quot;
      - &quot;443:443&quot;
    volumes:
      - &quot;/etc/nginx/conf.d&quot;
      - &quot;/etc/nginx/vhost.d&quot;
      - &quot;/usr/share/nginx/html&quot;
      - &quot;./volumes/proxy/certs:/etc/nginx/certs:ro&quot;
</code></pre>
<p>As you can see it shares a few volumes:</p>
<ul>
<li>Configuration folder: used by the container that generates the configuration file.</li>
<li>Default Nginx root folder: used by the Let’s Encrypt container for challenges from the CA.</li>
<li>Certificates folder: written to by the Let’s Encrypt container, this is where the TLS certificates are maintained.</li>
</ul>
<h3><a target="_blank" rel="nofollow" href="https://github.com/56north/encrypted_dashboard/blob/master/README.md#the-configuration-generator-container"></a>The configuration generator container</h3>
<p>This container inspects the other running containers and based on their metadata (like <strong>VIRTUAL_HOST</strong> environment variable) and a template file it generates the Nginx configuration file for the main Nginx container. When a new container is spinning up this container detects that, generates the appropriate configuration entries and restarts Nginx.</p>
<p>Uses the <a target="_blank" rel="nofollow" href="https://hub.docker.com/r/jwilder/docker-gen/">jwilder/docker-gen</a> Docker image.</p>
<p>It is defined in <code>docker-compose.yml</code> under the <strong>nginx-gen</strong> service block:</p>
<pre><code>services:
  ...

  nginx-gen:
    restart: always
    image: jwilder/docker-gen
    container_name: nginx-gen
    volumes:
      - &quot;/var/run/docker.sock:/tmp/docker.sock:ro&quot;
      - &quot;./volumes/proxy/templates/nginx.tmpl:/etc/docker-gen/templates/nginx.tmpl:ro&quot;
    volumes_from:
      - nginx
    entrypoint: /usr/local/bin/docker-gen -notify-sighup nginx -watch -wait 5s:30s /etc/docker-gen/templates/nginx.tmpl /etc/nginx/conf.d/default.conf
</code></pre>
<p>The container reads the <code>nginx.tmpl</code> template file (source: <a target="_blank" rel="nofollow" href="https://github.com/jwilder/nginx-proxy">jwilder/nginx-proxy</a>) via a volume shared with the host.</p>
<p>It also mounts the Docker socket into the container in order to be able to inspect the other containers (the <code>&quot;/var/run/docker.sock:/tmp/docker.sock:ro&quot;</code> line). <strong>Security warning</strong>: mounting the Docker socket is usually discouraged because the container getting (even read-only) access to it can get root access to the host. In our case, this container is not exposed to the world so if you trust the code running inside it the risks are probably fairly low. But definitely something to take into account. See e.g. <a target="_blank" rel="nofollow" href="https://raesene.github.io/blog/2016/03/06/The-Dangers-Of-Docker.sock/">The Dangers of Docker.sock</a> for further details.</p>
<p>NOTE: it would be preferrable to have docker-gen only handle containers with exposed ports (via <code>-only-exposed</code> flag in the <code>entrypoint</code> script above) but currently that does not work, see e.g. <a target="_blank" rel="nofollow" href="https://github.com/jwilder/nginx-proxy/issues/438">https://github.com/jwilder/nginx-proxy/issues/438</a>.</p>
<h3><a target="_blank" rel="nofollow" href="https://github.com/56north/encrypted_dashboard/blob/master/README.md#the-lets-encrypt-container"></a>The Let’s Encrypt container</h3>
<p>This container also inspects the other containers and acquires Let’s Encrypt TLS certificates based on the <strong>LETSENCRYPT_HOST</strong> and <strong>LETSENCRYPT_EMAIL</strong> environment variables. At regular intervals it checks and renews certificates as needed.</p>
<p>Uses the <a target="_blank" rel="nofollow" href="https://hub.docker.com/r/jrcs/letsencrypt-nginx-proxy-companion/">jrcs/letsencrypt-nginx-proxy-companion</a> Docker image.</p>
<p>It is defined in <code>docker-compose.yml</code> under the <strong>letsencrypt-nginx-proxy-companion</strong> service block:</p>
<pre><code>services:
  ...

  letsencrypt-nginx-proxy-companion:
    restart: always
    image: jrcs/letsencrypt-nginx-proxy-companion
    container_name: letsencrypt-nginx-proxy-companion
    volumes_from:
      - nginx
    volumes:
      - &quot;/var/run/docker.sock:/var/run/docker.sock:ro&quot;
      - &quot;./volumes/proxy/certs:/etc/nginx/certs:rw&quot;
    environment:
      - NGINX_DOCKER_GEN_CONTAINER=nginx-gen
</code></pre>
<p>The container uses a volume shared with the host and the Nginx container to maintain the certificates.</p>
<p>It also mounts the Docker socket in order to inspect the other containers. See the security warning above in the docker-gen section about the risks of that.</p>
<h3><a target="_blank" rel="nofollow" href="https://github.com/56north/encrypted_dashboard/blob/master/README.md#the-rstudio-server-and-shiny-server"></a>The Rstudio Server and Shiny Server</h3>
<p>These two servers are running in their own respective containers. They are defined in <code>docker-compose.yml</code> under the <strong>tidyverse</strong> and <strong>shiny</strong> service blocks:</p>
<pre><code>services:
  ...

  tidyverse:
    restart: always
    image: rocker/tidyverse
    container_name: rstudio
    expose:
      - &quot;8787&quot;
    environment:
      - VIRTUAL_HOST=rstudio.mydomain.com
      - VIRTUAL_NETWORK=nginx-proxy
      - VIRTUAL_PORT=80
      - LETSENCRYPT_HOST=rstudio.mydomain.com
      - LETSENCRYPT_EMAIL=me@myemail.com
      - USER=test
      - PASSWORD=test
    volumes:
      - shiny-apps:/home/mikkel/apps
      - r-packages:/usr/local/lib/R/site-library

  shiny:
    restart: always
    image: rocker/shiny
    container_name: shiny
    expose:
      - &quot;3838&quot;
    environment:
      - VIRTUAL_HOST=shiny.mydomain.com
      - VIRTUAL_NETWORK=nginx-proxy
      - VIRTUAL_PORT=80
      - LETSENCRYPT_HOST=shiny.mydomain.com
      - LETSENCRYPT_EMAIL=me@myemail.com
    volumes:
      - shiny-apps:/srv/shiny-server/
      - ./volumes/shiny/logs:/var/log/
      - r-packages:/usr/local/lib/R/site-library
</code></pre>
<p>The important part here are the environment variables and the volumes. The environment variables are used by the config generator and certificate maintainer containers to set up the system.</p>
<h3><a target="_blank" rel="nofollow" href="https://github.com/56north/encrypted_dashboard/blob/master/README.md#the-data-volumes"></a>The data volumes</h3>
<p>The volumes are used to ensure that Rstudio and Shiny share apps and packages in order for you to build apps in Rstudio and have them deployed on the Shiny server without too big a hassle.</p>
<h2><a target="_blank" rel="nofollow" href="https://github.com/56north/encrypted_dashboard/blob/master/README.md#conclusion"></a>Conclusion</h2>
<p>This can be a fairly simple way to have easy, reproducible deploys for a secure R-based dashboard solution with auto-renewing TLS certificates.</p>
<p> </p>
<p> </p>
<p> </p>
<p>
<div>
<div>To <strong>leave a comment</strong> for the author, please follow the link and comment on their blog: <strong><a href="http://www.56n.dk/setup-encrypted-rstudio-and-shiny-dashboard-solution-in-3-minutes/"> Renglish – 56north | Skræddersyet dataanalyse</a></strong>.</div>
<hr>
<a rel="nofollow" href="https://www.r-bloggers.com/">R-bloggers.com</a> offers <strong><a rel="nofollow" href="https://feedburner.google.com/fb/a/mailverify?uri=RBloggers">daily e-mail updates</a></strong> about <a title="The R Project for Statistical Computing" rel="nofollow" href="https://www.r-project.org/">R</a> news and <a title="R tutorials" rel="nofollow" href="https://www.r-bloggers.com/search/tutorial">tutorials</a> on topics such as: <a title="Data science" rel="nofollow" href="https://www.r-bloggers.com/search/data%20science">Data science</a>, <a title="Big Data" rel="nofollow" href="https://www.r-bloggers.com/search/Big%20Data">Big Data, <a title="R jobs" rel="nofollow" href="https://www.r-users.com/">R jobs</a>, visualization (<a title="ggplot and ggplot2 tutorials" rel="nofollow" href="https://www.r-bloggers.com/search/ggplot2">ggplot2</a>, <a title="Boxplots using lattice and ggplot2 tutorials" rel="nofollow" href="https://www.r-bloggers.com/search/boxplot">Boxplots</a>, <a title="Maps and gis" rel="nofollow" href="https://www.r-bloggers.com/search/map">maps</a>, <a title="Animation in R" rel="nofollow" href="https://www.r-bloggers.com/search/animation">animation</a>), programming (<a title="RStudio IDE for R" rel="nofollow" href="https://www.r-bloggers.com/search/RStudio">RStudio</a>, <a title="Sweave and literate programming" rel="nofollow" href="https://www.r-bloggers.com/search/sweave">Sweave</a>, <a title="LaTeX in R" rel="nofollow" href="https://www.r-bloggers.com/search/LaTeX">LaTeX</a>, <a title="SQL and databases" rel="nofollow" href="https://www.r-bloggers.com/search/SQL">SQL</a>, <a title="Eclipse IDE for R" rel="nofollow" href="https://www.r-bloggers.com/search/eclipse">Eclipse</a>, <a title="git and github, Version Control System" rel="nofollow" href="https://www.r-bloggers.com/search/git">git</a>, <a title="Large data in R using Hadoop" rel="nofollow" href="https://www.r-bloggers.com/search/hadoop">hadoop</a>, <a title="Web Scraping of google, facebook, yahoo, twitter and more using R" rel="nofollow" href="https://www.r-bloggers.com/search/Web+Scraping">Web Scraping</a>) statistics (<a title="Regressions and ANOVA analysis tutorials" rel="nofollow" href="https://www.r-bloggers.com/search/regression">regression</a>, <a title="principal component analysis tutorial" rel="nofollow" href="https://www.r-bloggers.com/search/PCA">PCA</a>, <a title="Time series" rel="nofollow" href="https://www.r-bloggers.com/search/time+series">time series</a>, <a title="finance trading" rel="nofollow" href="https://www.r-bloggers.com/search/trading">trading</a>) and more...
<img height="1" alt="" width="1" src="http://feeds.feedburner.com/~r/RBloggers/~4/Zn2Hr229-lY"></a></div>