7 Docker Image Build Guide for Shiny Apps
7.1 Docker Build Guide for Shiny Apps
This guide explains how to containerize your Shiny app using Docker. The process varies slightly depending on whether your app is built with {golem}
, {rhino}
, or as a bare Shiny app script.
7.1.1 How to Build Docker Image of Your App for Further Deployment
7.1.1.1 Prerequisites
Before you begin, make sure:
- ✅ You have an up-to-date
renv.lock
file in your project directory.
This is very important! - ✅ Docker Engine is installed and running on your machine.
7.1.1.1.1 🧱 Example 1: If You Are Using {golem}
# Default base image with Shiny Server
FROM rocker/shiny:4.4.1
# Note:
# If you encounter issues with rocker/shiny, you can try:
# FROM rocker/r-ver:4.4.1
# Install system dependencies
RUN apt-get update && apt-get install -y \
\
dotnet-runtime-8.0 \
libcurl4-openssl-dev \
libssl-dev \
libxml2-dev \
libfontconfig1-dev \
libfreetype6-dev \
libpng-dev \
libtiff5-dev \
libjpeg-dev
gitRUN ln -s /usr/lib/x86_64-linux-gnu/libdl.so.2 /usr/lib/x86_64-linux-gnu/libdl.so
# Copy the app package
COPY . /app
WORKDIR /app
# Install renv and restore environment
RUN R -e "install.packages('renv'); \
options(renv.config.repos.override = 'https://packagemanager.posit.co/cran/latest'); \
renv::restore();"
# Install your golem package
RUN R -e "renv::install('.')"
# Expose Shiny port
EXPOSE 80
# Start {golem} app (replace <your_package_name> with actual name)
CMD ["R", "-e", "shiny::runApp(<your_package_name>::run_app(), host='0.0.0.0', port=80)"]
7.1.1.1.2 🦏 Example 2: If You Are Using {rhino}
FROM rocker/shiny:4.4.1
# Install system dependencies
RUN apt-get update && apt-get install -y \
\
dotnet-runtime-8.0 \
libcurl4-openssl-dev \
libssl-dev \
libxml2-dev \
libfontconfig1-dev \
libfreetype6-dev \
libpng-dev \
libtiff5-dev \
libjpeg-dev
git
RUN ln -s /usr/lib/x86_64-linux-gnu/libdl.so.2 /usr/lib/x86_64-linux-gnu/libdl.so
COPY . /app
WORKDIR /app
RUN R -e "install.packages('renv'); \
options(renv.config.repos.override = 'https://packagemanager.posit.co/cran/latest'); \
renv::restore();"
EXPOSE 80
# Start {rhino} app
CMD ["R","-e", "shiny::runApp('./app.R', host='0.0.0.0', port = 80)"]
7.1.1.1.3 🧩 Example 3: If You Are Using a Bare Shiny App (not a package)
FROM rocker/shiny:4.4.1
RUN apt-get update && apt-get install -y \
\
dotnet-runtime-8.0 \
libcurl4-openssl-dev \
libssl-dev \
libxml2-dev \
libfontconfig1-dev \
libfreetype6-dev \
libpng-dev \
libtiff5-dev \
libjpeg-dev
gitRUN ln -s /usr/lib/x86_64-linux-gnu/libdl.so.2 /usr/lib/x86_64-linux-gnu/libdl.so
COPY . /app
WORKDIR /app
RUN R -e "install.packages('renv'); \
options(renv.config.repos.override = 'https://packagemanager.posit.co/cran/latest'); \
renv::restore();"
EXPOSE 80
# Start bare Shiny app
CMD ["R", "-e", "shiny::runApp('./app.R', host='0.0.0.0', port=80)"]
7.1.1.1.4 🔐 Optional: Enable Access to Private GitHub Repositories
If your Shiny app depends on private R packages hosted on GitHub, you’ll need to pass a GitHub token to your Dockerfile.
Dockerfile Instructions
Add the following lines to your Dockerfile
after the WORKDIR /app
line:
# Pass GitHub token for private repos
ARG GITHUB_PAT
ENV GITHUB_PAT=${GITHUB_PAT}
This allows renv::restore()
or other commands like remotes::install_github()
to authenticate and install private packages during the Docker build process.
🚩 Important: Only include this section if your project uses private GitHub dependencies. Otherwise, it’s unnecessary and can be safely omitted.
📝 Note about base image and R version:
The image tag in theFROM
line (e.g.,rocker/shiny:4.4.1
orrocker/r-ver:4.4.1
) must match the R version in yourrenv.lock
file.
If you’re not sure, openrenv.lock
and check:{ "R": { "Version": "4.4.1" } }
If the tag and version don’t match, your build may fail or produce unexpected results. example:
FROM rocker/shiny:<R version from `renv.lock` file>
P.S. If you encounter issues with
rocker/shiny
base image, you can try:FROM rocker/r-ver:<R version from `renv.lock` file>
7.1.1.1.5 📁 Recommended: Use a .dockerignore File
To reduce image size and speed up the Docker build, you should add a .dockerignore
file to your project root. This file tells Docker which files and folders to exclude when sending context to the Docker daemon.
Example .dockerignore
:
Create a file named .dockerignore
with the following content:
renv/staging/
renv/library/
renv/python/
.git
.Rproj.user
.Rhistory
.RData
.Ruserdata
This setup will avoid sending unnecessary R internals, Git metadata, and temporary files to your Docker image.
7.1.1.2 🛠 Build and Run Instructions
To build the Docker image:
docker build -t your-app-name .
ℹ️
your-app-name
is a tag you choose. It can be any name.
To run the image locally:
docker run --rm -p 3838:80 your-app-name
🔁 You can replace
3838
with any local port,
but must keep80
inside the container.
Once running, open your browser and go to:
http://localhost:3838
If your app loads — 🎉 you’re ready for further deployment (e.g., to Azure App Service)!
7.2 How to Deploy a Docker Image of Your App to Azure
- Sign in to the Azure portal with your Microsoft Account and 2FA code.
- Search “App Services”.
- Select “Create”.
- Select “Web App”.
- Follow the configuration procedure:
- Select the Resource Group
Shiny
. - Type the Web App Name.
- Select
Publish in Container
. - Select
Operating System Linux
. - Select
Region Germany West Central
. - Click on
Next: Database
. - Click on
Next: Container
. - Select the correct Image Source (Azure Registry or Docker Registry).
- Enter the URL of the registry, Image name and Tags, and Optional Startup command if needed.
- Click on
Next: Networking
. - Select
Enable Public Access: On
. - Go to the tab `Review and Create’.
- Deploy your Web App.
- Select the Resource Group
7.2.1 Additional Azure Configration
If you need to add a Custom Domain URL follow steps below: 1. Login at IONOS.de with admin account. 2. Create a dedicated CNAME and TXT record (Values from the Azure Portal: Custom Domain
). 3. Validate your records in the Azure Portal by clicking on Validate Custom Domain
. 4. Utilize default Azure SSL Certificate
and SNI Binding
. 5. After a couple of minutes you can browse your Web App in your custom domain.
7.3 Automate Docker Build & Push to Azure with GitHub Actions
You can automate the Docker image build and push process to Azure Container Registry (ACR) using GitHub Actions. This is especially useful for continuous deployment pipelines when pushing to the main
branch.
7.3.1 Prerequisites
Before you use the workflow, make sure:
- Azure Container Registry (ACR) is set up and accessible.
- You have access/created the following secrets in your GitHub repository or organization:
ACR_ENDPOINT
: e.g.myregistry.azurecr.io
ACR_USERNAME
: the username for your ACRACR_PASSWORD
: the password for your ACRACTIONS_PAT
(optional): only needed if your project depends on private GitHub repositories (e.g., private R packages).
7.3.2 GitHub Actions Workflow Example
Save this in .github/workflows/docker-image.yml
:
name: Build and Push Docker Image to Azure
on:
push:
branches: [ main ]
env:
IMAGE_NAME: your-image-name # 🔧 You can change this to any name you like
jobs:
build-and-push:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to Azure Container Registry
uses: docker/login-action@v3
with:
registry: ${{ secrets.ACR_ENDPOINT }}
username: ${{ secrets.ACR_USERNAME }}
password: ${{ secrets.ACR_PASSWORD }}
- name: Build and Push Docker Image
uses: docker/build-push-action@v5
with:
context: .
file: Dockerfile
push: true
tags: ${{ secrets.ACR_ENDPOINT }}/${{ env.IMAGE_NAME }}:latest
# 🔒 Optional: only include build-args if you use private GitHub dependencies
build-args: |
GITHUB_PAT=${{ secrets.ACTIONS_PAT }}
🛠️ The IMAGE NAME is customizable — name your image however you like.
🔐 The
build-args
section is optional and should only be included if your build process accesses private GitHub repositories (e.g., installing a private R package viarenv::restore()
).
📦 This workflow builds and pushes the Docker image on every push to the
main
branch. Your Azure App Service can then pull this image from ACR for deployment.