From agent-almanac
Deploys ShinyProxy to host multiple containerized Shiny apps with per-app authentication, access control, usage tracking, and scaling via Docker. For multi-app Shiny hosting beyond single deployments.
npx claudepluginhub pjt222/agent-almanacThis skill uses the workspace's default tool permissions.
---
Dockerizes full-stack apps with multi-stage builds, configures docker-compose, CI/CD pipelines via GitHub Actions, nginx/Traefik reverse proxy, SSL/TLS with certbot, and multi-environment deploys with rollback strategies.
Provides production-ready Docker Compose templates with security hardening, resource limits, health checks, logging, monitoring, and high-availability for scalable deployments.
Share bugs, ideas, or general feedback.
Deploy ShinyProxy to host multiple containerized Shiny applications with authentication and usage tracking.
Each Shiny app needs its own Docker image. Example Dockerfile for a Shiny app:
FROM rocker/shiny:4.5.0
RUN apt-get update && apt-get install -y \
libcurl4-openssl-dev \
libssl-dev \
&& rm -rf /var/lib/apt/lists/*
RUN R -e "install.packages(c('shiny', 'bslib', 'DT', 'dplyr'), \
repos='https://cloud.r-project.org/')"
COPY app/ /srv/shiny-server/app/
RUN chown -R shiny:shiny /srv/shiny-server/app
USER shiny
EXPOSE 3838
CMD ["R", "-e", "shiny::runApp('/srv/shiny-server/app', host='0.0.0.0', port=3838)"]
Build and test each app:
docker build -t myorg/dashboard:latest ./apps/dashboard/
docker run --rm -p 3838:3838 myorg/dashboard:latest
Expected: Each Shiny app runs independently in its own container.
application.yml:
proxy:
title: "Shiny Applications"
port: 8080
container-backend: docker
docker:
internal-networking: true
authentication: simple
admin-groups: admins
users:
- name: admin
password: admin_password
groups: admins
- name: analyst
password: analyst_password
groups: users
specs:
- id: dashboard
display-name: "Analytics Dashboard"
description: "Interactive data analysis dashboard"
container-image: myorg/dashboard:latest
container-cmd: ["R", "-e", "shiny::runApp('/srv/shiny-server/app', host='0.0.0.0', port=3838)"]
container-network: shinyproxy-net
port: 3838
access-groups: [admins, users]
- id: report-builder
display-name: "Report Builder"
description: "Generate custom reports"
container-image: myorg/report-builder:latest
container-cmd: ["R", "-e", "shiny::runApp('/srv/shiny-server/app', host='0.0.0.0', port=3838)"]
container-network: shinyproxy-net
port: 3838
access-groups: [admins]
logging:
file:
name: /opt/shinyproxy/log/shinyproxy.log
server:
forward-headers-strategy: native
docker-compose.yml:
services:
shinyproxy:
image: openanalytics/shinyproxy:3.1.1
container_name: shinyproxy
ports:
- "8080:8080"
volumes:
- ./application.yml:/opt/shinyproxy/application.yml:ro
- /var/run/docker.sock:/var/run/docker.sock
- shinyproxy-logs:/opt/shinyproxy/log
networks:
- shinyproxy-net
restart: unless-stopped
networks:
shinyproxy-net:
name: shinyproxy-net
driver: bridge
volumes:
shinyproxy-logs:
# Create the network first (ShinyProxy spawns containers on this network)
docker network create shinyproxy-net
# Start ShinyProxy
docker compose up -d
# Check logs
docker compose logs -f shinyproxy
Expected: ShinyProxy starts on port 8080, shows login page, and lists configured apps.
On failure: Check docker compose logs shinyproxy. Verify app images are available locally (docker images).
As shown in Step 2 with authentication: simple and inline users.
proxy:
authentication: ldap
ldap:
url: ldap://ldap.example.com:389/dc=example,dc=com
manager-dn: cn=admin,dc=example,dc=com
manager-password: ldap_admin_password
user-search-base: ou=users
user-search-filter: (uid={0})
group-search-base: ou=groups
group-search-filter: (member={0})
proxy:
authentication: openid
openid:
auth-url: https://auth.example.com/realms/myrealm/protocol/openid-connect/auth
token-url: https://auth.example.com/realms/myrealm/protocol/openid-connect/token
jwks-url: https://auth.example.com/realms/myrealm/protocol/openid-connect/certs
client-id: shinyproxy
client-secret: your_client_secret
roles-claim: realm_access.roles
For production, place Nginx in front of ShinyProxy:
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
server {
listen 443 ssl;
server_name shiny.example.com;
ssl_certificate /etc/letsencrypt/live/shiny.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/shiny.example.com/privkey.pem;
location / {
proxy_pass http://shinyproxy:8080;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
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_read_timeout 600s;
proxy_buffering off;
}
}
WebSocket support is critical — ShinyProxy and Shiny use WebSockets heavily.
ShinyProxy logs usage events to its log file. For structured tracking, configure InfluxDB:
proxy:
usage-stats-url: http://influxdb:8086/write?db=shinyproxy
usage-stats-username: shinyproxy
usage-stats-password: stats_password
Add InfluxDB to the compose stack:
services:
influxdb:
image: influxdb:1.8
environment:
INFLUXDB_DB: shinyproxy
INFLUXDB_ADMIN_USER: admin
INFLUXDB_ADMIN_PASSWORD: admin_password
volumes:
- influxdata:/var/lib/influxdb
networks:
- shinyproxy-net
volumes:
influxdata:
specs:
- id: dashboard
container-image: myorg/dashboard:latest
container-memory-limit: 1g
container-cpu-limit: 1.0
max-instances: 5
container-env:
R_MAX_MEM_SIZE: 768m
# Check ShinyProxy health
curl -s http://localhost:8080/actuator/health
# Test login
curl -s -c cookies.txt -d "username=admin&password=admin_password" \
http://localhost:8080/login
# List apps via API
curl -s -b cookies.txt http://localhost:8080/api/proxyspec
Expected: Health endpoint returns UP. Login succeeds. Apps launch in isolated containers.
docker group or mount the socket.container-network in specs must match).docker ps to check and clean up.container-memory-limit to prevent a single app from starving others.deploy-shiny-app - single-app deployment to shinyapps.io, Posit Connect, or Dockerconfigure-reverse-proxy - reverse proxy patterns including WebSocket proxyingcreate-dockerfile - general Dockerfile creation for app imagescreate-r-dockerfile - R-specific Dockerfiles with rocker images