# Install required packages
install.packages("shiny")
install.packages("quarto")
# Serve the dasboard
quarto::quarto_serve("index.qmd")Quarto Dashboard with Shiny Server and Docker
Quarto dashboards provide a seamless way to create interactive web applications using Python, R, Julia, and Observable. While there are convenient hosting solutions such as shinyapps.io, Hugging Face, and Posit Connect, sometimes you need more control over resources—particularly RAM. Hosting on a cloud platform like Google Cloud Run (GCR) allows for more flexibility and cost efficiency. The method outlined in this post should be applicable to other cloud providers as well, so please share your experience in the comments if you deploy it elsewhere!
In this blog post, I’ll show you how to deploy a Quarto dashboard with an R Shiny backend inside a Docker container, served using Shiny Server. You can find the complete setup in this GitHub repo. If you’re interested in a Python-based dashboard deployment, feel free to reach out!
Setting Up the Dashboard
The foundation of our dashboard is an index.qmd file. In this example, we use a demonstration from the Shiny Gallery that illustrates the k-Means clustering algorithm.
It is just a simple app without any additional depdencies. You can check out the code in the repo, I’m not going into details here.
To preview the dashboard locally, install Quarto, the necessary packages, and use the following command in your R console:
This launches a local server where you can interact with your dashboard. However, this step isn’t required for deployment, as the Docker container will handle rendering automatically.
Writing the Dockerfile
Our Docker container needs to: (i) install Quarto and its dependencies, (ii) install Shiny Server to serve the dashboard, and (iii) render the .qmd file to an HTML format for deployment.
We start with the rocker/shiny base image, which includes R, Shiny Server, and its dependencies. For production applications, you might want to specify the version here.
FROM rocker/shiny
Then, we install additional dependencies required for Quarto:
RUN apt-get update && apt-get install -y --no-install-recommends \
pandoc \
curl \
gdebi-core \
&& rm -rf /var/lib/apt/lists/*
Next, we install Quarto (you may want to also specify a fixed version for production stability):
RUN curl -LO https://quarto.org/download/latest/quarto-linux-amd64.deb
RUN gdebi --non-interactive quarto-linux-amd64.deb
We install the required R packages:
RUN R -e "install.packages(c('shiny', 'quarto'))"
We copy our custom configuration (see below) for the shiny server into the container.
RUN mkdir -p /srv/shiny-server/dashboard && \
chown -R shiny:shiny /srv/shiny-server
COPY shiny-server.conf /etc/shiny-server/shiny-server.conf
We also set additional permissions for server log files:
RUN mkdir -p /var/log/shiny-server && \
chown -R shiny:shiny /var/log/shiny-server
Since Shiny Server does not natively support .qmd files, we need to render the dashboard inside the container. If you are interested in why Shiny Server cannot handle the .qmd files directly, check out this pull request.
COPY index.qmd /srv/shiny-server/dashboard/index.qmd
WORKDIR /srv/shiny-server/dashboard/
RUN quarto render index.qmd
Finally, we switch to the shiny user for enhanced security and start the shiny Server process upon execution.
USER shiny
CMD ["/usr/bin/shiny-server"]
Shiny Server Configuration
Shiny Server requires a configuration file (shiny-server.conf) to specify how the dashboard is served. Below is a minimal setup:
run_as shiny;
server {
listen 8080;
location / {
site_dir /srv/shiny-server/dashboard;
log_dir /var/log/shiny-server;
}
}
This configuration ensures that:
- The server runs as the
shinyuser. - It listens on port
8080(which is compatible with GCR). - It serves the dashboard from
/srv/shiny-server/dashboard(as specified in theDockerfile).
Deploying to a Cloud Platform
Deploying this setup to a cloud provider like GCR is straightforward. If you want automatic deployment from a GitHub repository, you can follow Google’s Cloud Build setup. Once the repository is updated, GCR automatically builds and deploys the container.
Conclusion
With this setup, you can deploy a Quarto dashboard backed by an R Shiny application in a Docker container, making it easy to run both locally and on cloud platforms like GCR. This approach provides greater flexibility and control over resource allocation compared to managed services.
I’d love to hear your feedback! If you deploy this setup on other platforms, let me know how it works for you in the comments.