ShinyProxy: Enterprise Container Orchestration for Shiny Applications

Complete Guide to Multi-Tenant, Scalable Shiny Deployment

Master ShinyProxy deployment for enterprise Shiny applications. Learn container orchestration, multi-tenant architecture, authentication integration, and security configuration for scalable, production-ready Shiny deployments.

Tools
Author
Affiliation
Published

May 23, 2025

Modified

June 12, 2025

Keywords

ShinyProxy deployment, enterprise shiny container orchestration, ShinyProxy tutorial, multi-tenant shiny deployment, container orchestration shiny, enterprise shiny architecture

Key Takeaways

Tip
  • Enterprise-Grade Architecture: ShinyProxy provides multi-tenant container orchestration that scales from departmental tools to organization-wide platforms
  • Security and Authentication: Built-in integration with enterprise authentication systems (LDAP, OAuth, SAML) ensures secure access control
  • Resource Isolation: Each Shiny application runs in its own Docker container, providing complete isolation and resource management
  • Production-Ready Features: Load balancing, health monitoring, and automatic container lifecycle management for reliable production deployments
  • Cost-Effective Scaling: Dynamic container allocation optimizes resource usage while supporting hundreds of concurrent users

Introduction

ShinyProxy represents the evolution of enterprise Shiny deployment, bridging the gap between basic Shiny Server and complex cloud orchestration platforms. As organizations increasingly need sophisticated analytical applications that serve multiple users securely and reliably, ShinyProxy has emerged as the preferred solution for enterprise container orchestration of Shiny applications.



Unlike traditional deployment approaches that struggle with multi-tenancy and resource isolation, ShinyProxy leverages Docker containers to provide complete application isolation while maintaining the simplicity that makes Shiny development accessible. This tutorial guides you through implementing a production-ready ShinyProxy deployment that meets enterprise requirements for security, scalability, and reliability.

Whether you’re deploying analytical applications for internal teams, client-facing dashboards for external stakeholders, or building a comprehensive analytics platform for your organization, ShinyProxy provides the enterprise-grade foundation that transforms prototype applications into production-ready analytical solutions.

Understanding ShinyProxy Architecture

ShinyProxy’s container-first architecture fundamentally changes how Shiny applications are deployed and managed in enterprise environments:

flowchart TD
    A[User Request] --> B[ShinyProxy Server]
    B --> C{Authentication}
    C -->|Authenticated| D[Container Manager]
    C -->|Failed| E[Login Page]
    D --> F[Docker Engine]
    F --> G[Shiny App Container 1]
    F --> H[Shiny App Container 2]
    F --> I[Shiny App Container N]
    
    J[Load Balancer] --> B
    K[Authentication Provider] --> C
    L[Container Registry] --> F
    
    style A fill:#e1f5fe
    style B fill:#f3e5f5
    style D fill:#e8f5e8
    style F fill:#fff3e0

Core Architecture Components

ShinyProxy Server

Acts as the orchestration layer that manages container lifecycle, user authentication, and request routing. Unlike traditional web servers, ShinyProxy dynamically creates and destroys containers based on user demand and session management policies.

Container Manager

Interfaces with Docker Engine to create, monitor, and destroy application containers. Each user session gets its own dedicated container, ensuring complete resource isolation and eliminating the cross-user contamination issues common in shared server environments.

Authentication Integration

Native support for enterprise authentication systems including LDAP, Active Directory, OAuth providers, and SAML. This integration ensures that Shiny applications inherit organizational access control policies without requiring custom authentication implementation.

Resource Management

Dynamic resource allocation with configurable memory limits, CPU constraints, and automatic scaling policies. Containers are created on-demand and destroyed when sessions end, optimizing resource utilization while maintaining performance.

Prerequisites and Environment Setup

System Requirements

Server Infrastructure:

  • Operating System: Linux (Ubuntu 20.04+ or RHEL 8+ recommended)
  • Memory: Minimum 8GB RAM (16GB+ recommended for production)
  • CPU: Minimum 4 cores (8+ cores recommended for concurrent users)
  • Storage: 50GB+ available disk space for containers and logs
  • Network: Stable internet connection for Docker image downloads

Software Dependencies:

  • Docker Engine: Version 20.10+
  • Java Runtime: OpenJDK 11 or higher
  • Reverse Proxy: Nginx or Apache (recommended for production)
  • SSL Certificate: For HTTPS termination (required for production)

Docker Environment Configuration

Install and configure Docker with appropriate permissions and resource limits:

# Install Docker Engine (Ubuntu/Debian)
curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh

# Add system user to docker group
sudo usermod -aG docker $USER

# Configure Docker daemon for production
sudo tee /etc/docker/daemon.json <<EOF
{
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "10m",
    "max-file": "3"
  },
  "storage-driver": "overlay2",
  "storage-opts": [
    "overlay2.override_kernel_check=true"
  ]
}
EOF

# Restart Docker service
sudo systemctl restart docker
sudo systemctl enable docker

Java Runtime Installation

ShinyProxy requires Java 11 or higher for optimal performance:

# Install OpenJDK 11 (Ubuntu/Debian)
sudo apt update
sudo apt install openjdk-11-jdk

# Verify Java installation
java -version
javac -version

# Set JAVA_HOME environment variable
echo 'export JAVA_HOME=/usr/lib/jvm/java-11-openjdk-amd64' >> ~/.bashrc
source ~/.bashrc

ShinyProxy Installation and Basic Configuration

Download and Initial Setup

# Create ShinyProxy directory structure
sudo mkdir -p /opt/shinyproxy
sudo mkdir -p /opt/shinyproxy/logs
sudo mkdir -p /opt/shinyproxy/config

# Download latest ShinyProxy release
cd /opt/shinyproxy
sudo wget https://www.shinyproxy.io/downloads/shinyproxy-3.0.2.jar

# Create system user for ShinyProxy
sudo useradd -r -s /bin/false shinyproxy
sudo chown -R shinyproxy:shinyproxy /opt/shinyproxy

Basic Configuration File

Create the foundational configuration file that defines application settings and container specifications:

# /opt/shinyproxy/config/application.yml
proxy:
  title: Enterprise Analytics Platform
  logo-url: file:///opt/shinyproxy/config/logo.png
  landingpage: /
  heartbeat-rate: 10000
  heartbeat-timeout: 60000
  port: 8080
  bind-address: 0.0.0.0
  
  authentication: simple
  admin-groups: [admin]
  users:
    - name: admin
      password: changeThisPassword123!
      groups: [admin]
    - name: analyst
      password: analystPassword456!
      groups: [analyst]
  
  # Container runtime configuration
  container-backend: docker
  docker:
    url: http://localhost:2375
    port-range-start: 20000
    port-range-max: 25000
    
  specs:
    - id: data-explorer
      display-name: Interactive Data Explorer
      description: Advanced data exploration and visualization tool
      container-cmd: ["R", "-e", "shiny::runApp('/srv/shiny-server/data-explorer', host='0.0.0.0', port=3838)"]
      container-image: your-registry/shiny-data-explorer:latest
      container-memory: "2GB"
      container-cpu-limit: 2
      container-privileged: false
      access-groups: [analyst, admin]
      
    - id: financial-dashboard
      display-name: Financial Analytics Dashboard
      description: Real-time financial performance monitoring
      container-cmd: ["R", "-e", "shiny::runApp('/srv/shiny-server/financial-dashboard', host='0.0.0.0', port=3838)"]
      container-image: your-registry/shiny-financial:latest
      container-memory: "4GB"
      container-cpu-limit: 2
      container-privileged: false
      access-groups: [admin]

logging:
  level:
    root: INFO
    eu.openanalytics: DEBUG
  file:
    name: /opt/shinyproxy/logs/shinyproxy.log

Systemd Service Configuration

Create a systemd service for production deployment management:

# /etc/systemd/system/shinyproxy.service
[Unit]
Description=ShinyProxy
After=docker.service
Requires=docker.service

[Service]
Type=simple
User=shinyproxy
ExecStart=/usr/bin/java -jar /opt/shinyproxy/shinyproxy-3.0.2.jar
WorkingDirectory=/opt/shinyproxy/config
Restart=always
RestartSec=10

# Resource limits
LimitNOFILE=65536
Environment=JAVA_OPTS=-Xmx2g

# Security settings
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ReadWritePaths=/opt/shinyproxy/logs

[Install]
WantedBy=multi-user.target

Enable and start the ShinyProxy service:

# Reload systemd configuration
sudo systemctl daemon-reload

# Enable ShinyProxy service
sudo systemctl enable shinyproxy

# Start ShinyProxy service
sudo systemctl start shinyproxy

# Check service status
sudo systemctl status shinyproxy

# Monitor logs
sudo journalctl -u shinyproxy -f

Container Image Preparation

Creating Optimized Shiny Container Images

Effective ShinyProxy deployment requires well-designed container images that balance functionality with security and performance:

# Dockerfile for Shiny Data Explorer Application
FROM rocker/shiny:4.3.2

# Install system dependencies
RUN apt-get update && apt-get install -y \
    libcurl4-gnutls-dev \
    libssl-dev \
    libxml2-dev \
    libcairo2-dev \
    libgit2-dev \
    default-libmysqlclient-dev \
    libpq-dev \
    libsasl2-dev \
    libldap2-dev \
    && rm -rf /var/lib/apt/lists/*

# Install R packages
RUN R -e "install.packages(c('shiny', 'shinydashboard', 'DT', 'plotly', 'dplyr', 'ggplot2', 'readr', 'RMySQL', 'RPostgreSQL'), repos='https://cran.rstudio.com/')"

# Copy application files
COPY shiny-apps/data-explorer/ /srv/shiny-server/data-explorer/
COPY config/Rprofile.site /usr/local/lib/R/etc/

# Set proper permissions
RUN chown -R shiny:shiny /srv/shiny-server/

# Configure security settings
USER shiny

# Health check
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
  CMD curl -f http://localhost:3838/ || exit 1

# Expose port
EXPOSE 3838

# Start command (will be overridden by ShinyProxy)
CMD ["R", "-e", "shiny::runApp('/srv/shiny-server/data-explorer', host='0.0.0.0', port=3838)"]

Multi-Stage Build Optimization

For production environments, implement multi-stage builds to reduce image size and security footprint:

# Multi-stage Dockerfile for optimized production images
FROM rocker/r-base:4.3.2 as builder

# Install build dependencies
RUN apt-get update && apt-get install -y \
    libcurl4-gnutls-dev \
    libssl-dev \
    libxml2-dev \
    build-essential \
    && rm -rf /var/lib/apt/lists/*

# Install R packages
RUN R -e "install.packages(c('shiny', 'shinydashboard', 'DT', 'plotly', 'dplyr', 'ggplot2'), repos='https://cran.rstudio.com/')"

# Production stage
FROM rocker/shiny:4.3.2

# Copy installed packages from builder
COPY --from=builder /usr/local/lib/R/site-library /usr/local/lib/R/site-library

# Install only runtime dependencies
RUN apt-get update && apt-get install -y \
    libcurl4-gnutls-dev \
    libssl-dev \
    libxml2-dev \
    && rm -rf /var/lib/apt/lists/*

# Copy application
COPY shiny-apps/data-explorer/ /srv/shiny-server/data-explorer/

# Security configuration
RUN chown -R shiny:shiny /srv/shiny-server/ && \
    chmod -R 755 /srv/shiny-server/

USER shiny
EXPOSE 3838

# Health check
HEALTHCHECK --interval=30s --timeout=3s \
  CMD curl -f http://localhost:3838/ || exit 1

Build and Registry Management

# Build optimized container image
docker build -t your-registry/shiny-data-explorer:latest .

# Tag for version management
docker tag your-registry/shiny-data-explorer:latest your-registry/shiny-data-explorer:v1.0.0

# Push to container registry
docker push your-registry/shiny-data-explorer:latest
docker push your-registry/shiny-data-explorer:v1.0.0

# Verify image
docker images | grep shiny-data-explorer

Advanced Authentication Integration

LDAP/Active Directory Integration

Enterprise environments typically require integration with existing directory services:

# LDAP Authentication Configuration
proxy:
  authentication: ldap
  ldap:
    url: ldap://ldap.company.com:389
    user-dn-pattern: uid={0},ou=users,dc=company,dc=com
    user-search-filter: (uid={0})
    user-search-base: ou=users,dc=company,dc=com
    group-search-base: ou=groups,dc=company,dc=com
    group-search-filter: (member={0})
    manager-dn: cn=admin,dc=company,dc=com
    manager-password: ${LDAP_MANAGER_PASSWORD}
    
  # Map LDAP groups to ShinyProxy groups
  authorization:
    expression: hasRole('ROLE_USER')
  
  admin-groups: [IT-ADMINS, DATA-SCIENCE-LEADS]
  
  specs:
    - id: executive-dashboard
      display-name: Executive Dashboard
      access-groups: [C-SUITE, VP-LEVEL]
      # ... container configuration
      
    - id: analyst-tools
      display-name: Analyst Toolkit
      access-groups: [ANALYSTS, DATA-SCIENTISTS]
      # ... container configuration

OAuth2 Integration

For modern authentication workflows, integrate with OAuth2 providers:

# OAuth2 Configuration (example with Google)
proxy:
  authentication: oauth2
  oauth2:
    client-id: ${OAUTH2_CLIENT_ID}
    client-secret: ${OAUTH2_CLIENT_SECRET}
    access-token-uri: https://oauth2.googleapis.com/token
    user-authorization-uri: https://accounts.google.com/o/oauth2/auth
    scope: openid email profile
    user-info-uri: https://www.googleapis.com/oauth2/v2/userinfo
    jwk-set-uri: https://www.googleapis.com/oauth2/v3/certs
    username-attribute: email
    
  # Additional OAuth2 settings
  logout-url: https://accounts.google.com/logout
  
  specs:
    - id: public-analytics
      display-name: Public Analytics Tool
      # No access-groups restriction for OAuth2 authenticated users

SAML Integration

For enterprise SSO environments requiring SAML:

# SAML Configuration
proxy:
  authentication: saml
  saml:
    app-entity-id: shinyproxy-analytics
    idp-entity-id: https://sso.company.com/entity-id
    idp-single-sign-on-service-url: https://sso.company.com/sso/saml
    idp-single-logout-service-url: https://sso.company.com/slo/saml
    idp-x509-certificate: |
      -----BEGIN CERTIFICATE-----
      [Certificate content]
      -----END CERTIFICATE-----
    
    # Attribute mapping
    username-attribute: NameID
    groups-attribute: memberOf
    
  logout-url: https://sso.company.com/logout

Production Security Configuration

SSL/TLS Implementation with Traefik

Configure HTTPS termination using Traefik reverse proxy (recommended for ShinyProxy):

# docker-compose.yml with Traefik integration
version: '3.8'

services:
  traefik:
    image: traefik:v3.0
    command:
      # API and dashboard
      - "--api.dashboard=true"
      - "--api.insecure=false"
      
      # Docker provider
      - "--providers.docker=true"
      - "--providers.docker.exposedbydefault=false"
      
      # Entry points
      - "--entrypoints.web.address=:80"
      - "--entrypoints.websecure.address=:443"
      
      # SSL/TLS configuration
      - "--certificatesresolvers.letsencrypt.acme.tlschallenge=true"
      - "--certificatesresolvers.letsencrypt.acme.email=admin@company.com"
      - "--certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json"
      
      # Security headers
      - "--entrypoints.websecure.http.middlewares=security-headers@docker"
      
      # Logging
      - "--log.level=INFO"
      - "--accesslog=true"
      
    ports:
      - "80:80"
      - "443:443"
      - "8080:8080"  # Dashboard (secure in production)
    volumes:
      - "/var/run/docker.sock:/var/run/docker.sock:ro"
      - "./letsencrypt:/letsencrypt"
    labels:
      # Dashboard access (secure with authentication in production)
      - "traefik.enable=true"
      - "traefik.http.routers.dashboard.rule=Host(`traefik.company.com`)"
      - "traefik.http.routers.dashboard.tls.certresolver=letsencrypt"
      - "traefik.http.routers.dashboard.service=api@internal"
      
      # Security headers middleware
      - "traefik.http.middlewares.security-headers.headers.stsSeconds=31536000"
      - "traefik.http.middlewares.security-headers.headers.stsIncludeSubdomains=true"
      - "traefik.http.middlewares.security-headers.headers.stsPreload=true"
      - "traefik.http.middlewares.security-headers.headers.forceSTSHeader=true"
      - "traefik.http.middlewares.security-headers.headers.frameDeny=true"
      - "traefik.http.middlewares.security-headers.headers.contentTypeNosniff=true"
      - "traefik.http.middlewares.security-headers.headers.browserXssFilter=true"
      - "traefik.http.middlewares.security-headers.headers.referrerPolicy=strict-origin-when-cross-origin"
    networks:
      - shinyproxy

  shinyproxy:
    image: openanalytics/shinyproxy:3.0.2
    volumes:
      - ./config:/opt/shinyproxy/config
      - ./logs:/opt/shinyproxy/logs
      - /var/run/docker.sock:/var/run/docker.sock
    environment:
      - SPRING_PROFILES_ACTIVE=prod
    labels:
      # Traefik configuration
      - "traefik.enable=true"
      
      # HTTP to HTTPS redirect
      - "traefik.http.routers.shinyproxy-http.rule=Host(`analytics.company.com`)"
      - "traefik.http.routers.shinyproxy-http.entrypoints=web"
      - "traefik.http.routers.shinyproxy-http.middlewares=redirect-to-https@docker"
      
      # HTTPS configuration
      - "traefik.http.routers.shinyproxy.rule=Host(`analytics.company.com`)"
      - "traefik.http.routers.shinyproxy.entrypoints=websecure"
      - "traefik.http.routers.shinyproxy.tls.certresolver=letsencrypt"
      - "traefik.http.routers.shinyproxy.middlewares=security-headers@docker"
      
      # Service configuration
      - "traefik.http.services.shinyproxy.loadbalancer.server.port=8080"
      
      # WebSocket support (automatic with Traefik)
      - "traefik.http.services.shinyproxy.loadbalancer.sticky.cookie=true"
      
      # Redirect middleware
      - "traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https"
      - "traefik.http.middlewares.redirect-to-https.redirectscheme.permanent=true"
      
    networks:
      - shinyproxy
    depends_on:
      - traefik

networks:
  shinyproxy:
    external: false

For traditional server deployment without Docker Compose, use Traefik configuration file:

# /etc/traefik/traefik.toml
[global]
  checkNewVersion = false
  sendAnonymousUsage = false

[api]
  dashboard = true
  insecure = false

[entryPoints]
  [entryPoints.web]
    address = ":80"
  [entryPoints.websecure]
    address = ":443"

[certificatesResolvers]
  [certificatesResolvers.letsencrypt]
    [certificatesResolvers.letsencrypt.acme]
      email = "admin@company.com"
      storage = "/etc/traefik/acme.json"
      [certificatesResolvers.letsencrypt.acme.tlsChallenge]

[http]
  [http.routers]
    [http.routers.shinyproxy]
      rule = "Host(`analytics.company.com`)"
      entryPoints = ["websecure"]
      service = "shinyproxy"
      [http.routers.shinyproxy.tls]
        certResolver = "letsencrypt"
        
    [http.routers.shinyproxy-http]
      rule = "Host(`analytics.company.com`)"
      entryPoints = ["web"]
      middlewares = ["redirect-to-https"]
      
  [http.services]
    [http.services.shinyproxy]
      [http.services.shinyproxy.loadBalancer]
        [[http.services.shinyproxy.loadBalancer.servers]]
          url = "http://localhost:8080"
          
  [http.middlewares]
    [http.middlewares.redirect-to-https]
      [http.middlewares.redirect-to-https.redirectScheme]
        scheme = "https"
        permanent = true
        
    [http.middlewares.security-headers]
      [http.middlewares.security-headers.headers]
        stsSeconds = 31536000
        stsIncludeSubdomains = true
        stsPreload = true
        forceSTSHeader = true
        frameDeny = true
        contentTypeNosniff = true
        browserXssFilter = true
        referrerPolicy = "strict-origin-when-cross-origin"

Container Security Hardening

Implement security best practices for container runtime:

# Enhanced security configuration in application.yml
proxy:
  docker:
    # Use Docker socket with TLS
    url: https://docker-daemon:2376
    cert-path: /opt/shinyproxy/docker-certs
    tls-verify: true
    
  specs:
    - id: secure-app
      # Security constraints
      container-privileged: false
      container-memory: "2GB"
      container-cpu-limit: 2
      
      # Network isolation
      container-network: shinyproxy-net
      
      # Security options
      container-security-opts:
        - no-new-privileges
        - apparmor:docker-default
        
      # Read-only root filesystem
      container-read-only: true
      
      # Temporary filesystem mounts
      container-tmpfs:
        - /tmp
        - /var/tmp
        
      # Resource limits
      container-ulimits:
        - name: nofile
          soft: 1024
          hard: 2048

Monitoring and Logging Configuration

Application Monitoring

Implement comprehensive monitoring for production ShinyProxy deployments:

# Enhanced logging and monitoring configuration
logging:
  level:
    root: INFO
    eu.openanalytics: DEBUG
    org.springframework.security: DEBUG
  pattern:
    console: "%d{yyyy-MM-dd HH:mm:ss} - %msg%n"
    file: "%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n"
  file:
    name: /opt/shinyproxy/logs/shinyproxy.log
    max-size: 10MB
    max-history: 30

management:
  endpoints:
    web:
      exposure:
        include: health,info,metrics,prometheus
      base-path: /actuator
  endpoint:
    health:
      show-details: when-authorized
  metrics:
    export:
      prometheus:
        enabled: true

# Custom metrics configuration
proxy:
  usage-stats-url: http://localhost:9090/metrics
  container-log-path: /opt/shinyproxy/logs/containers

External Monitoring Integration

Configure integration with monitoring systems like Prometheus and Grafana:

# docker-compose.yml for monitoring stack
version: '3.8'
services:
  shinyproxy:
    image: openanalytics/shinyproxy:latest
    ports:
      - "8080:8080"
    volumes:
      - ./config:/opt/shinyproxy/config
      - ./logs:/opt/shinyproxy/logs
      - /var/run/docker.sock:/var/run/docker.sock

  prometheus:
    image: prom/prometheus:latest
    ports:
      - "9090:9090"
    volumes:
      - ./monitoring/prometheus.yml:/etc/prometheus/prometheus.yml
    command:
      - '--config.file=/etc/prometheus/prometheus.yml'
      - '--storage.tsdb.path=/prometheus'
      - '--web.console.libraries=/etc/prometheus/console_libraries'
      - '--web.console.templates=/etc/prometheus/consoles'

  grafana:
    image: grafana/grafana:latest
    ports:
      - "3000:3000"
    environment:
      - GF_SECURITY_ADMIN_PASSWORD=admin
    volumes:
      - grafana-storage:/var/lib/grafana
      - ./monitoring/grafana/dashboards:/etc/grafana/provisioning/dashboards
      - ./monitoring/grafana/datasources:/etc/grafana/provisioning/datasources

volumes:
  grafana-storage:

Performance Optimization and Scaling

Resource Management Strategies

Optimize resource allocation for different application types and user loads:

# Advanced resource management configuration
proxy:
  container-backend: docker
  docker:
    # Connection pooling
    pool-size: 10
    max-total-connections: 100
    
    # Container lifecycle management
    port-range-start: 20000
    port-range-max: 25000
    container-wait-time: 60000
    container-idle-timeout: 300000
    
  specs:
    # High-performance analytics application
    - id: heavy-analytics
      display-name: Advanced Analytics Suite
      container-memory: "8GB"
      container-cpu-limit: 4
      container-cpu-reservation: 2
      container-memory-swap: "16GB"
      
      # JVM optimization for R applications
      container-env:
        R_MAX_VSIZE: "8GB"
        JAVA_OPTS: "-Xmx6g -XX:+UseG1GC"
        
    # Lightweight dashboard application
    - id: simple-dashboard
      display-name: Executive Dashboard
      container-memory: "1GB"
      container-cpu-limit: 1
      container-cpu-reservation: 0.5
      
      # Quick startup optimization
      container-env:
        R_MAX_VSIZE: "1GB"

Load Balancing and High Availability

Configure ShinyProxy for high availability with multiple instances using Traefik:

# High Availability ShinyProxy with Traefik Load Balancing
version: '3.8'

services:
  traefik:
    image: traefik:v3.0
    command:
      - "--api.dashboard=true"
      - "--providers.docker=true"
      - "--providers.docker.exposedbydefault=false"
      - "--entrypoints.web.address=:80"
      - "--entrypoints.websecure.address=:443"
      - "--certificatesresolvers.letsencrypt.acme.tlschallenge=true"
      - "--certificatesresolvers.letsencrypt.acme.email=admin@company.com"
      - "--certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json"
      # Health checking
      - "--ping=true"
      - "--metrics.prometheus=true"
    ports:
      - "80:80"
      - "443:443"
      - "8080:8080"
    volumes:
      - "/var/run/docker.sock:/var/run/docker.sock:ro"
      - "./letsencrypt:/letsencrypt"
    healthcheck:
      test: ["CMD", "traefik", "healthcheck", "--ping"]
      interval: 30s
      timeout: 3s
      retries: 3
    networks:
      - shinyproxy

  # Primary ShinyProxy instance
  shinyproxy-1:
    image: openanalytics/shinyproxy:3.0.2
    environment:
      - SPRING_PROFILES_ACTIVE=prod
      - SERVER_PORT=8080
    volumes:
      - ./config:/opt/shinyproxy/config
      - ./logs:/opt/shinyproxy/logs/instance-1
      - /var/run/docker.sock:/var/run/docker.sock
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.shinyproxy.rule=Host(`analytics.company.com`)"
      - "traefik.http.routers.shinyproxy.entrypoints=websecure"
      - "traefik.http.routers.shinyproxy.tls.certresolver=letsencrypt"
      - "traefik.http.services.shinyproxy.loadbalancer.server.port=8080"
      # Health check configuration
      - "traefik.http.services.shinyproxy.loadbalancer.healthcheck.path=/actuator/health"
      - "traefik.http.services.shinyproxy.loadbalancer.healthcheck.interval=30s"
      - "traefik.http.services.shinyproxy.loadbalancer.healthcheck.timeout=5s"
      # Session stickiness for WebSocket connections
      - "traefik.http.services.shinyproxy.loadbalancer.sticky.cookie=true"
      - "traefik.http.services.shinyproxy.loadbalancer.sticky.cookie.name=shinyproxy-server"
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8080/actuator/health"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 60s
    networks:
      - shinyproxy
    depends_on:
      - traefik

  # Secondary ShinyProxy instance
  shinyproxy-2:
    image: openanalytics/shinyproxy:3.0.2
    environment:
      - SPRING_PROFILES_ACTIVE=prod
      - SERVER_PORT=8080
    volumes:
      - ./config:/opt/shinyproxy/config
      - ./logs:/opt/shinyproxy/logs/instance-2
      - /var/run/docker.sock:/var/run/docker.sock
    labels:
      - "traefik.enable=true"
      - "traefik.http.services.shinyproxy.loadbalancer.server.port=8080"
      # Same service name for automatic load balancing
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8080/actuator/health"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 60s
    networks:
      - shinyproxy
    depends_on:
      - traefik

  # Optional: Third instance for additional capacity
  shinyproxy-3:
    image: openanalytics/shinyproxy:3.0.2
    environment:
      - SPRING_PROFILES_ACTIVE=prod
      - SERVER_PORT=8080
    volumes:
      - ./config:/opt/shinyproxy/config
      - ./logs:/opt/shinyproxy/logs/instance-3
      - /var/run/docker.sock:/var/run/docker.sock
    labels:
      - "traefik.enable=true"
      - "traefik.http.services.shinyproxy.loadbalancer.server.port=8080"
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8080/actuator/health"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 60s
    networks:
      - shinyproxy
    depends_on:
      - traefik

networks:
  shinyproxy:
    driver: bridge

For production environments, add monitoring and scaling configuration:

# docker-compose.override.yml for production scaling
version: '3.8'

services:
  # Prometheus for metrics collection
  prometheus:
    image: prom/prometheus:latest
    ports:
      - "9090:9090"
    volumes:
      - ./monitoring/prometheus.yml:/etc/prometheus/prometheus.yml
      - prometheus-data:/prometheus
    command:
      - '--config.file=/etc/prometheus/prometheus.yml'
      - '--storage.tsdb.path=/prometheus'
      - '--web.console.libraries=/etc/prometheus/console_libraries'
      - '--web.console.templates=/etc/prometheus/consoles'
      - '--storage.tsdb.retention.time=30d'
      - '--web.enable-lifecycle'
    networks:
      - shinyproxy

  # Grafana for visualization
  grafana:
    image: grafana/grafana:latest
    ports:
      - "3000:3000"
    environment:
      - GF_SECURITY_ADMIN_PASSWORD=${GRAFANA_PASSWORD:-admin}
      - GF_USERS_ALLOW_SIGN_UP=false
    volumes:
      - grafana-data:/var/lib/grafana
      - ./monitoring/grafana/dashboards:/etc/grafana/provisioning/dashboards:ro
      - ./monitoring/grafana/datasources:/etc/grafana/provisioning/datasources:ro
    networks:
      - shinyproxy
    depends_on:
      - prometheus

volumes:
  prometheus-data:
  grafana-data:

Common Issues and Troubleshooting

Container Startup Issues

Issue 1: Containers Fail to Start

Problem: Applications fail to launch with container creation errors.

Solution:

# Check Docker daemon status
sudo systemctl status docker

# Verify ShinyProxy can communicate with Docker
docker ps

# Check container image availability
docker images | grep your-app-name

# Test container manually
docker run --rm -p 3838:3838 your-registry/shiny-app:latest

# Review ShinyProxy logs
sudo journalctl -u shinyproxy -f --lines=100

Issue 2: Memory and Resource Constraints

Problem: Applications crash due to insufficient resources or memory limits.

Solution:

# Adjust resource allocations in application.yml
specs:
  - id: memory-intensive-app
    container-memory: "4GB"  # Increase from default
    container-memory-swap: "8GB"  # Allow swap usage
    container-cpu-limit: 4  # Increase CPU allocation
    
    # JVM and R memory settings
    container-env:
      R_MAX_VSIZE: "4GB"
      JAVA_OPTS: "-Xmx3g -XX:+UseG1GC -XX:MaxGCPauseMillis=200"

Authentication and Authorization Problems

Issue 3: LDAP Authentication Failures

Problem: Users cannot authenticate through LDAP/Active Directory.

Solution:

# Test LDAP connectivity
ldapsearch -H ldap://ldap.company.com:389 -x -D "cn=admin,dc=company,dc=com" -W -b "ou=users,dc=company,dc=com"

# Verify LDAP configuration in application.yml
# Enable debug logging for authentication
logging:
  level:
    org.springframework.security: DEBUG
    org.springframework.ldap: DEBUG

Issue 4: Group-Based Access Control Not Working

Problem: Users with correct group membership cannot access applications.

Solution:

# Verify group mapping configuration
proxy:
  ldap:
    group-search-base: ou=groups,dc=company,dc=com
    group-search-filter: (member={0})  # Adjust for your LDAP schema
    group-role-attribute: cn
    
  # Ensure groups match exactly
  specs:
    - id: restricted-app
      access-groups: [DATA-SCIENTISTS, ANALYSTS]  # Use exact LDAP group names

Performance and Scaling Issues

Issue 5: Slow Application Startup

Problem: Applications take too long to start, affecting user experience.

Solution:

# Optimize container startup
specs:
  - id: fast-startup-app
    # Pre-built, optimized container image
    container-image: your-registry/optimized-shiny:latest
    
    # Reduce startup overhead
    container-cmd: ["R", "--slave", "-e", "shiny::runApp('/srv/shiny-server/app', host='0.0.0.0', port=3838)"]
    
    # Resource reservation for faster allocation
    container-cpu-reservation: 1

    
    # Environment tuning for faster R startup
    container-env:
      R_COMPILE_PKGS: "0"  # Skip package compilation
      R_DISABLE_HTTPD: "1"  # Disable R help server

# Monitor container startup times
proxy:
  container-log-path: /opt/shinyproxy/logs/containers
  usage-stats-url: http://localhost:9090/metrics

Issue 6: High Memory Usage and OOM Kills

Problem: Containers are killed due to out-of-memory conditions.

Solution:

# Memory optimization strategies
specs:
  - id: memory-optimized-app
    # Appropriate memory allocation
    container-memory: "4GB"
    container-memory-swap: "6GB"
    
    # R memory management
    container-env:
      R_MAX_VSIZE: "3GB"  # Leave headroom for system
      GC_INITIAL_HEAP_SIZE: "100MB"
      R_GC_MEM_GROW: "3"
      
    # JVM tuning for R processes
    container-env:
      JAVA_OPTS: "-Xmx2g -XX:+UseG1GC -XX:MaxGCPauseMillis=200 -XX:+UseStringDeduplication"

# Monitor memory usage
docker stats --format "table {{.Container}}\t{{.CPUPerc}}\t{{.MemUsage}}\t{{.NetIO}}\t{{.BlockIO}}"

Common Questions About ShinyProxy Deployment

ShinyProxy offers unique advantages that position it between cloud platforms and traditional server deployments:

vs. shinyapps.io:

  • Control: Full control over infrastructure, security, and customization vs. managed service convenience
  • Cost: Potentially lower long-term costs for high-usage applications vs. predictable monthly fees
  • Scalability: Manual scaling configuration vs. automatic scaling
  • Maintenance: Requires infrastructure management vs. zero maintenance overhead

vs. Shiny Server (Open Source):

  • Isolation: Complete container isolation vs. shared R processes
  • Security: Enterprise authentication integration vs. basic access control
  • Resource Management: Dynamic container allocation vs. fixed resource sharing
  • Multi-tenancy: Built-in multi-tenant architecture vs. single-tenant limitations

vs. Shiny Server Pro/RStudio Connect:

  • Cost: Open source (free) vs. commercial licensing fees
  • Features: Container-first approach vs. traditional server management
  • Flexibility: Docker ecosystem integration vs. proprietary solutions

Best Use Cases for ShinyProxy:

  • Organizations requiring container-based deployment
  • Multi-tenant environments with strict user isolation
  • Integration with existing Docker/Kubernetes infrastructure
  • Custom authentication and enterprise security requirements
  • Cost-sensitive deployments with high usage volumes

Production ShinyProxy deployments require careful infrastructure planning to ensure reliability and performance:

Minimum Production Requirements:

  • CPU: 8+ cores (4 cores minimum for testing)
  • Memory: 16GB+ RAM (32GB+ recommended for heavy usage)
  • Storage: 100GB+ SSD storage for containers and logs
  • Network: Stable internet connection with adequate bandwidth

Scaling Considerations:

# Estimate resource needs based on concurrent users
# Rule of thumb: 2GB RAM + 1 CPU core per 10 concurrent users
concurrent_users = 50
estimated_memory = concurrent_users * 0.2  # GB per user
estimated_cores = concurrent_users / 10

echo "Estimated needs: ${estimated_memory}GB RAM, ${estimated_cores} CPU cores"

Infrastructure Architecture:

  • Load Balancer: Traefik, Nginx, or cloud load balancer for high availability
  • Container Storage: Fast SSD storage for Docker images and temporary files
  • Backup Strategy: Regular backups of configuration and user data
  • Monitoring: Prometheus, Grafana, or equivalent monitoring stack

Network and Security:

  • Firewall Configuration: Secure access to necessary ports only (80, 443, management ports)
  • SSL Certificates: Valid certificates for production domains
  • VPN Access: Consider VPN requirements for internal applications
  • DNS Configuration: Proper DNS setup for custom domains

High Availability Setup:

  • Multiple ShinyProxy instances behind load balancer
  • Shared configuration storage (NFS, cloud storage)
  • Database clustering for authentication backends
  • Geographic distribution for disaster recovery

Container issues are among the most common ShinyProxy problems, but systematic troubleshooting can resolve most issues:

Step 1: Check ShinyProxy Logs

# View ShinyProxy logs
sudo journalctl -u shinyproxy -f --lines=100

# Check for specific error patterns
sudo journalctl -u shinyproxy | grep -i "error\|failed\|exception"

Step 2: Test Container Images Directly

# Test the container image outside of ShinyProxy
docker run --rm -p 3838:3838 your-registry/shiny-app:latest

# Check if the application starts correctly
curl http://localhost:3838/

# Examine container logs
docker logs [container-id]

Step 3: Verify Resource Constraints

# Check if resource limits are too restrictive
specs:
  - id: problematic-app
    container-memory: "4GB"  # Increase if needed
    container-cpu-limit: 2   # Ensure adequate CPU
    
    # Add resource monitoring
    container-env:
      R_MAX_VSIZE: "3GB"

Step 4: Common Issues and Solutions

Memory Issues:

  • Increase container memory limits
  • Optimize R memory usage with gc() calls
  • Check for memory leaks in application code

Package/Dependency Problems:

  • Verify all required packages are in the container image
  • Check package version compatibility
  • Ensure system dependencies are installed

Permission Issues:

  • Verify container runs with appropriate user permissions
  • Check file system permissions for shared volumes
  • Ensure Docker daemon permissions are correct

Network/Port Conflicts:

  • Verify port ranges don’t conflict with other services
  • Check firewall rules and network policies
  • Ensure containers can communicate with required services

Step 5: Advanced Debugging

# Access container for debugging
docker exec -it [container-id] /bin/bash

# Check container resource usage
docker stats [container-id]

# Inspect container configuration
docker inspect [container-id]

Yes, ShinyProxy provides robust enterprise authentication integration capabilities:

LDAP/Active Directory Integration:

# Complete LDAP configuration example
proxy:
  authentication: ldap
  ldap:
    url: ldap://ad.company.com:389
    user-dn-pattern: cn={0},ou=users,dc=company,dc=com
    user-search-base: ou=users,dc=company,dc=com
    user-search-filter: (sAMAccountName={0})
    group-search-base: ou=groups,dc=company,dc=com
    group-search-filter: (member={0})
    group-role-attribute: cn
    manager-dn: cn=service-account,ou=service-accounts,dc=company,dc=com
    manager-password: ${LDAP_SERVICE_PASSWORD}

SAML Integration for SSO:

# SAML configuration for enterprise SSO
proxy:
  authentication: saml
  saml:
    app-entity-id: shinyproxy-analytics
    idp-entity-id: https://sso.company.com/adfs/services/trust
    idp-single-sign-on-service-url: https://sso.company.com/adfs/ls/
    idp-single-logout-service-url: https://sso.company.com/adfs/ls/
    idp-x509-certificate: |
      -----BEGIN CERTIFICATE-----
      [Your IdP certificate content]
      -----END CERTIFICATE-----
    username-attribute: http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name
    groups-attribute: http://schemas.microsoft.com/ws/2008/06/identity/claims/groups

OAuth2 Integration:

# OAuth2 with Azure AD example
proxy:
  authentication: oauth2
  oauth2:
    client-id: ${AZURE_CLIENT_ID}
    client-secret: ${AZURE_CLIENT_SECRET}
    access-token-uri: https://login.microsoftonline.com/[tenant-id]/oauth2/v2.0/token
    user-authorization-uri: https://login.microsoftonline.com/[tenant-id]/oauth2/v2.0/authorize
    scope: openid profile email
    user-info-uri: https://graph.microsoft.com/v1.0/me
    username-attribute: userPrincipalName

Advanced Group Mapping:

# Map enterprise groups to ShinyProxy roles
proxy:
  admin-groups: [IT-ADMINS, SHINY-ADMINISTRATORS]
  
  specs:
    - id: executive-dashboard
      access-groups: [C-SUITE, VP-LEVEL, EXECUTIVE-TEAM]
      
    - id: analyst-tools
      access-groups: [DATA-ANALYSTS, BUSINESS-ANALYSTS, DATA-SCIENTISTS]
      
    - id: public-reports
      # No access-groups = available to all authenticated users

Testing Authentication:

# Test LDAP connectivity
ldapsearch -H ldap://ad.company.com:389 \
  -D "cn=service-account,ou=service-accounts,dc=company,dc=com" \
  -W -b "ou=users,dc=company,dc=com" \
  "(sAMAccountName=testuser)"

# Verify group membership
ldapsearch -H ldap://ad.company.com:389 \
  -D "cn=service-account,ou=service-accounts,dc=company,dc=com" \
  -W -b "ou=groups,dc=company,dc=com" \
  "(member=cn=testuser,ou=users,dc=company,dc=com)"

Security Best Practices:

  • Use service accounts with minimal required permissions
  • Secure LDAP connections with TLS/SSL
  • Store sensitive credentials as environment variables
  • Implement proper group-based access control
  • Regular security audits of authentication configuration

Scaling ShinyProxy requires a multi-layered approach combining load balancing, redundancy, and resource optimization:

High Availability Architecture:

# docker-compose.yml for HA deployment
version: '3.8'
services:
  traefik:
    image: traefik:v3.0
    command:
      - "--providers.docker=true"
      - "--entrypoints.websecure.address=:443"
      - "--certificatesresolvers.letsencrypt.acme.tlschallenge=true"
    ports:
      - "443:443"
    volumes:
      - "/var/run/docker.sock:/var/run/docker.sock:ro"
    networks:
      - shinyproxy

  shinyproxy-1:
    image: openanalytics/shinyproxy:3.0.2
    environment:
      - SPRING_PROFILES_ACTIVE=prod
    volumes:
      - ./config:/opt/shinyproxy/config
      - /var/run/docker.sock:/var/run/docker.sock
    labels:
      - "traefik.enable=true"
      - "traefik.http.services.shinyproxy.loadbalancer.server.port=8080"
      - "traefik.http.services.shinyproxy.loadbalancer.healthcheck.path=/actuator/health"
    networks:
      - shinyproxy

  shinyproxy-2:
    image: openanalytics/shinyproxy:3.0.2
    environment:
      - SPRING_PROFILES_ACTIVE=prod
    volumes:
      - ./config:/opt/shinyproxy/config
      - /var/run/docker.sock:/var/run/docker.sock
    labels:
      - "traefik.enable=true"
      - "traefik.http.services.shinyproxy.loadbalancer.server.port=8080"
    networks:
      - shinyproxy

networks:
  shinyproxy:
    driver: bridge

Scaling Strategies:

Horizontal Scaling:

  • Deploy multiple ShinyProxy instances
  • Use load balancer for traffic distribution
  • Implement session stickiness for WebSocket connections
  • Share configuration through network storage

Vertical Scaling:

  • Increase server resources (CPU, memory)
  • Optimize container resource allocation
  • Tune JVM parameters for ShinyProxy
  • Implement resource monitoring and alerting

Container Optimization:

# Optimized container configuration
proxy:
  docker:
    # Connection pooling
    pool-size: 20
    max-total-connections: 200
    
    # Resource management
    port-range-start: 20000
    port-range-max: 25000
    
  specs:
    - id: optimized-app
      container-memory: "2GB"
      container-cpu-limit: 2
      container-cpu-reservation: 1
      
      # Quick startup optimization
      container-env:
        R_COMPILE_PKGS: "0"
        R_DISABLE_HTTPD: "1"

Monitoring and Auto-scaling:

# Monitor resource usage
docker stats --format "table {{.Container}}\t{{.CPUPerc}}\t{{.MemUsage}}"

# Implement auto-scaling triggers
# Scale up when CPU > 80% for 5 minutes
# Scale down when CPU < 30% for 15 minutes

Performance Optimization:

  • Pre-build and cache container images
  • Use fast SSD storage for Docker
  • Implement container image layering optimization
  • Regular cleanup of unused containers and images
  • Network optimization for container communication

Geographic Distribution:

  • Deploy in multiple regions for global users
  • Use CDN for static assets
  • Implement database replication for multi-region setups
  • Consider edge caching for improved performance

Test Your Understanding

What are the key advantages of ShinyProxy’s container-per-user architecture compared to traditional shared Shiny Server deployments?

  1. Containers use less memory than shared processes
  2. Each user gets complete resource isolation and security separation
  3. Container startup is faster than shared server connections
  4. Authentication is simpler with containers
  • Think about what happens when multiple users access the same server
  • Consider security implications of shared vs. isolated environments
  • Remember the resource management capabilities discussed

B) Each user gets complete resource isolation and security separation

ShinyProxy’s container-per-user architecture provides several critical advantages: - Complete isolation: Each user’s session runs in its own container, preventing memory leaks, crashes, or security issues from affecting other users - Resource control: Individual memory and CPU limits per container prevent one user from consuming all server resources - Security boundaries: Containers provide process-level isolation that protects sensitive data and prevents cross-user access - Scalability: Dynamic container creation allows for better resource utilization and scaling

While containers do have overhead compared to shared processes, the benefits of isolation, security, and resource management far outweigh the costs in enterprise environments.

Complete this LDAP authentication configuration for an enterprise environment:

proxy:
  authentication: ldap
  ldap:
    url: ldap://ldap.company.com:389
    user-dn-pattern: uid={0},ou=users,dc=company,dc=com
    group-search-base: ou=groups,dc=company,dc=com
    group-search-filter: ______
    manager-dn: cn=admin,dc=company,dc=com
    manager-password: ${LDAP_MANAGER_PASSWORD}

What should replace the blank for proper group membership checking?

  • Think about how LDAP stores group membership information
  • Consider the standard LDAP attribute for group members
  • The {0} placeholder represents the user’s distinguished name
group-search-filter: (member={0})

Explanation:

  • (member={0}) searches for groups where the user’s DN is listed as a member
  • The {0} placeholder is replaced with the user’s full distinguished name
  • This is the standard LDAP group membership pattern
  • Alternative patterns might include (memberUid={1}) for username-based membership or (uniqueMember={0}) for certain LDAP implementations

Additional considerations:

  • Verify your LDAP schema’s group membership attribute
  • Test with ldapsearch to confirm the correct filter
  • Some organizations use nested groups requiring recursive search filters

You’re deploying ShinyProxy for a financial services company that requires:

  • High availability with zero downtime
  • Automatic SSL certificate management
  • Load balancing across multiple instances
  • Health monitoring and failover

Which deployment approach would you recommend and why?

  1. Single ShinyProxy instance with Nginx reverse proxy
  2. Multiple ShinyProxy instances with Traefik orchestration
  3. ShinyProxy with manual load balancer configuration
  4. Cloud-managed container service without reverse proxy
  • Consider the specific requirements: HA, automatic SSL, load balancing, monitoring
  • Think about which solution provides the most automation
  • Remember the advantages of different reverse proxy solutions

B) Multiple ShinyProxy instances with Traefik orchestration

Why this is the best choice:

High Availability:

  • Multiple ShinyProxy instances provide redundancy
  • Automatic failover when instances become unhealthy
  • Zero-downtime deployments with rolling updates

Automatic SSL Management:

  • Traefik’s built-in Let’s Encrypt integration
  • Automatic certificate renewal
  • No manual certificate management overhead

Load Balancing:

  • Dynamic service discovery and load balancing
  • Session stickiness for WebSocket connections
  • Health check integration with automatic instance removal

Monitoring and Failover:

  • Built-in health checking and metrics
  • Prometheus integration for monitoring
  • Automatic traffic routing away from failed instances

Enterprise Benefits:

  • Container-native approach aligns with modern infrastructure
  • Reduced operational overhead compared to manual configurations
  • Better security with automatic updates and proper isolation

The Traefik + multiple ShinyProxy approach provides the automation, reliability, and scalability required for enterprise financial services environments.

Conclusion

ShinyProxy represents a significant evolution in enterprise Shiny deployment, providing the container orchestration, security, and scalability required for production analytical applications. By leveraging Docker containers for complete user isolation and integrating seamlessly with enterprise authentication systems, ShinyProxy bridges the gap between prototype applications and enterprise-grade analytical platforms.

The container-per-user architecture ensures that applications remain performant and secure even under heavy concurrent usage, while features like dynamic resource allocation and automatic container lifecycle management optimize infrastructure utilization. Combined with Traefik’s modern reverse proxy capabilities, ShinyProxy deployments can achieve enterprise-grade reliability with minimal operational overhead.

Whether you’re building internal analytical tools for your organization or deploying client-facing dashboards that require enterprise security and compliance, ShinyProxy provides the foundation for scalable, maintainable, and secure Shiny application deployment that grows with your needs.

Next Steps

Based on what you’ve learned in this tutorial, here are the recommended paths for continuing your ShinyProxy mastery:

Immediate Next Steps (Complete These First)

Building on Your Foundation (Choose Your Path)

For Enterprise Integration Focus:

For Cloud Deployment Focus:

For Production Operations:

Long-term Goals (2-4 Weeks)

  • Deploy a production ShinyProxy environment serving multiple applications
  • Implement automated CI/CD pipelines for container deployment
  • Integrate with organizational monitoring and alerting systems
  • Create standardized deployment templates for your organization
Back to top

Reuse

Citation

BibTeX citation:
@online{kassambara2025,
  author = {Kassambara, Alboukadel},
  title = {ShinyProxy: {Enterprise} {Container} {Orchestration} for
    {Shiny} {Applications}},
  date = {2025-05-23},
  url = {https://www.datanovia.com/learn/tools/shiny-apps/production-deployment/shinyproxy-deployment.html},
  langid = {en}
}
For attribution, please cite this work as:
Kassambara, Alboukadel. 2025. “ShinyProxy: Enterprise Container Orchestration for Shiny Applications.” May 23, 2025. https://www.datanovia.com/learn/tools/shiny-apps/production-deployment/shinyproxy-deployment.html.