Deploying web applications in R with shiny
The Shiny Server Open source is the only application that is made free for the community (shinyapps.io has a free plan, but is limited in number of applications and in hours of usage, while RStudio connect is affordable to medium/large organizations), however its features are limited compared to the commercial products made by RStudio: for example the community edition lacks of the authentication features implemented in the other RStudio products, and this is a key feature I need in order to share some projects with a limited number of users.
Adding an authentication layer to Shiny Server Community Edition
I spent a lot of time in understanding how to implement an authentication layer in front of the Shiny Server community edition: the first attempt I made was adding a HTTP Basic Authentication on each shiny application I need to make private. This solution however was not ideal, since this type of authentication is not safe, and passwords are stored in the browser cache during usage. Closing and re-opening the browser requires to start everytime a new authentication and it’s impossible to logout and login again with another user without closing the browser. So I searched authentication alternatives made by the community (I wrote down a small list here), when I found this beautiful guide made by pawamoy on how to use Django as an Authentication layer for Shiny:
Django application as an authentication / authorization server for Shiny
As you may know, Shiny Server comes in two versions: open-source and professional. The professional adds security and…
This guide has inspired me to do something similar (I had a good experience with Django in another project) and I want to create a more structured project in which I could enhance the solution proposed in the pawamoy guide. So, instead of writing about how the Django authentication works with shiny (I think that pawamoy explains those details better than me, I suggest you to read his guide), I want to explain how I added more features in my Django-Shiny authentication project.
Enhancing the Shiny — Django authentication layer
In my mind, I want to structure the authentication layer in a better way. Ideally I want to:
- Structure the project with docker-compose
- Ensure authentication per application
- Direct access to the shiny application (without the django container but with authentication)
- Customize the layout
1. Structuring the project with docker-compose
Instead to install all required stuff on a local machine, I prefer to organize my project with docker compose. This is easier to maintain (for example, if I need to update the R version) and keeps images shorter (consider that the R based image needs a lot of packages to work properly in different situations). If I need to clean-up my shiny-server installation, I could easily remove a docker image instead of search-and-clean every single package I’ve installed.
By sharing volumes between container, I could set a NgINX container as the frontend application (which forwards request to the backend and can serve static content itself). Shiny and Django containers (with the database) are part of the backend and are linked to the NgINX container since they are not accessible from the outside. By defining an .env configuration file, I could define passwords and runtime specific variables required by the application (like the django SECRET_KEY) which can’t be tracked in GitHub. Image are pre-builded and loaded into Docker Hub in order to save time with CI tests and for a faster installation on production environment. Here is an extract of docker-compose.yml file:
2. Ensuring authentication per application
In my project, I want to be able to add a new shiny application without modifying configuration files. In order to do this, the shiny application need to be managed entirely by django: the shiny application location and ownership need to be managed in models in order to exploit the django Class-based Views. In the following example, the application ownership is determined using a ManyToMany relationship with the default django-auth User model, while the application location is a CharField in which we indicate the application location where we put shiny code inside the docker-compose project folder:
This allows to add a new application using the default django-admin application (however the shiny application code need to be placed manually in the project folder, for the moment. I plan to add a custom django FormView in order to upload code using the admin). The location field in this case will also be part of the final URL which will be served by the Shiny Server docker-compose application:
By customizing the django views.py, I could customize how applications could be displayed: a public application is available to everyone, even anonymous users; superuser can always display the applications while logged user can see applications only if they own them. In the following example, by inheriting the UserPassesTestMixin from django-auth modules, a generic View can be displayed only if a custom test_func(self) method returns True:
3. Direct access to the shiny application
Like the Shiny — Gallery, I want to be able to display the shiny application outside the django container application view: this allows to display an application alone in the browser page. The example below enhance the pawamoy solution and give to the authorization url the same behaviour described in the django view (which embeds the shiny application) described above:
The previous code works together with the following NgINX configuration block: every direct access to shiny application need to be tested using django. Moreover, anonymous users are redirected to login and then towards the requested application URL, while not authorized users got a 403 (access denied) page:
4. Customize the layout
The application layout is determined by using bootstrap with the django-templates files: in such way I can customize the application with a few lines of HTML code:
This guide tries to summarize how I customized a clever solution found on the web by describing the enhancements I implemented. This is not an attempt to substitute the commercial solutions provided by RStudio: this is considered as an exercise in which I can model an authentication layer in front of the Shiny Server Community Edition. There are others features that are available in the commercial editions and should be evaluated carefully: for example the multi threaded support and the better resource management which let you to scale your applications and support a very large community. Moreover the support that RStudio can provide to their customers will be better than the support given to a simple open-source project and should be carefully considered if you need to provide shiny applications to your partners or customers.
If you want to learn more, the full application is available in GitHub:
This is an attempt of managing shiny authentication with django starting from Django application as an authentication /…
While a more user-oriented guide on how to install the whole application and add a shiny application can be found in the GitHub — Wiki of the project:
Shiny Server @CNR-IBBA. Contribute to cnr-ibba/shiny-server development by creating an account on GitHub.
If you liked this article, feel free to make a comment or make a clap. See you for another amazing-super complicated guide!