tinyshinyserver

R Package License: MIT Platform

A lightweight, WebSocket-enabled proxy server for hosting multiple Shiny applications with automatic health monitoring, session management, and resource cleanup.

🎯 Perfect for: - Hosting multiple Shiny apps behind a single server - Development environments with multiple projects - Small-scale production deployments - R Markdown and Quarto dashboard hosting

Installation

From GitHub

# Install from GitHub
remotes::install_github("lab1702/tinyshinyserver")

From Source

# Clone and install locally
git clone https://github.com/lab1702/tinyshinyserver.git
cd tinyshinyserver
Rscript -e "devtools::install('.')"

Prerequisites

The package automatically installs required R dependencies:

Core: shiny, callr, jsonlite, later, httr, digest, httpuv, websocket, openssl Async: future Docs: rmarkdown, quarto Utils: logger

Optional (for examples): DT, plotly, dplyr, flexdashboard

πŸš€ Quick Start

1. Load

# Load the package
library(tinyshinyserver)

2. Get Example Apps

# Copy included example apps to your directory
examples_path <- system.file("examples", package = "tinyshinyserver")
file.copy(examples_path, ".", recursive = TRUE)

3. Start the Server

# Start with the example configuration
start_tss(config = "examples/config.json")

4. Access Your Server

🌐 Main Interface: http://localhost:3838
βš™οΈ Management Dashboard: http://localhost:3839
πŸ“± Individual Apps: http://localhost:3838/proxy/{app_name}/

5. Get Help

# Package overview and getting started
?tinyshinyserver

# Main function help
?start_tss

# Configuration format reference
?config-format

Features

πŸ“‹ Configuration

The server uses a JSON configuration file. Here’s a minimal example:

{
  "apps": [
    {
      "name": "sales",
      "path": "./examples/sales",
      "resident": true
    }
  ],
  "starting_port": 3001,
  "proxy_port": 3838,
  "proxy_host": "127.0.0.1",
  "management_port": 3839,
  "log_dir": "./logs"
}

πŸ“– See ?config-format for complete configuration reference

πŸ›‘ Stopping the Server

Recommended: Use the management interface at http://localhost:3839 and click β€œShutdown Server”.

Alternative methods: - Press Ctrl-C in the R console - API call: curl -X POST http://localhost:3839/api/shutdown

βœ… Graceful shutdown closes all connections and cleans up resources.

πŸ“¦ Included Examples

The package includes four example applications:

App Type Description
sales Single-file Shiny Simple dashboard with sample data
inventory Multi-file Shiny Interactive tables (ui.R + server.R)
reports R Markdown Flexdashboard with runtime: shiny
dashboard Quarto Modern dashboard with server: shiny

Example configuration (from examples/config.json):

{
  "apps": [
    {
      "name": "sales",
      "path": "./examples/sales",
      "resident": true
    },
    {
      "name": "inventory", 
      "path": "./examples/inventory"
    },
    {
      "name": "reports",
      "path": "./examples/reports",
      "resident": false
    },
    {
      "name": "dashboard",
      "path": "./examples/dashboard",
      "resident": true
    }
  ],
  "starting_port": 3001,
  "proxy_port": 3838,
  "management_port": 3839,
  "log_dir": "./logs"
}

⚑ Auto Port Assignment

Apps are automatically assigned ports starting from starting_port: - sales β†’ port 3001
- inventory β†’ port 3002
- reports β†’ port 3003
- dashboard β†’ port 3004

The system skips reserved ports (proxy_port, management_port) automatically.

πŸ”„ Resident vs On-Demand Apps

The server supports two application life cycle modes controlled by the resident configuration option:

Resident Apps ("resident": true)

On-Demand Apps ("resident": false, default)

Status Indicators

Example Configuration:

{
  "apps": [
    {
      "name": "critical-dashboard",
      "path": "./apps/dashboard",
      "resident": true  // Always running for immediate access
    },
    {
      "name": "occasional-report",
      "path": "./apps/reports",
      "resident": false  // Starts only when needed
    },
    {
      "name": "dev-prototype",
      "path": "./apps/prototype"
      // "resident" defaults to false
    }
  ]
}

Configuration Options

Option Description Default
apps Array of Shiny applications to host Required
apps[].name Application identifier for URLs Required
apps[].path Relative path to app directory Required
apps[].resident Keep app running continuously (true) or start on-demand (false) false
starting_port Starting port for auto-assignment Required
log_dir Directory for log files Required
proxy_port Port for the proxy server 3838
proxy_host Host interface for proxy server (localhost, 127.0.0.1, 0.0.0.0, ::1, ::) β€œ127.0.0.1”
management_port Port for the management interface 3839
restart_delay Seconds to wait before restarting failed apps 5
health_check_interval Seconds between health checks 10

Network Configuration

The proxy_host option controls which network interface the proxy server binds to:

⚠️ Security Note: Using "0.0.0.0" makes the server accessible from external networks. Only use this if you understand the security implications and have proper firewall rules in place.

SSL and Authentication with Caddy

For production deployments requiring SSL/TLS and authentication, Caddy Server provides a simple solution:

# Caddyfile
myapp.example.com {
    reverse_proxy localhost:3838
    basicauth {
        username password_hash
    }
}

manage.myapp.example.com {
    reverse_proxy localhost:3839
    basicauth {
        admin admin_password_hash
    }
}

This configuration automatically handles SSL certificates via Let’s Encrypt and adds HTTP basic authentication.

Important: When using Caddy, keep proxy_host set to "localhost" or "127.0.0.1" in your config.json to ensure the server only accepts connections from Caddy, not directly from external clients.

Landing Page

The landing page at http://localhost:3838 provides an overview of all hosted applications with real-time status information.

Features

Real-time Status Display

Application Access

Server Information

The landing page uses the same status API as the management interface, ensuring consistency between all monitoring views.

Management Interface

The management interface provides a professional web-based dashboard for monitoring and controlling your Shiny server.

Accessing the Management Interface

Visit http://localhost:3839 to access the management dashboard.

πŸ”’ Security: The management interface is restricted to localhost only for security.

Features

System Overview

Application Management

Connection Tracking

Server Controls

Management API

The management interface exposes a REST API for programmatic access:

Endpoint Method Description
/api/status GET System overview (apps, connections)
/api/apps GET Detailed application status
/api/connections GET Active connection details
/api/apps/{name}/restart POST Restart specific application
/api/shutdown POST Graceful server shutdown

Example usage:

# Get system status
curl http://localhost:3839/api/status

# Restart the sales app
curl -X POST http://localhost:3839/api/apps/sales/restart

# Shutdown server
curl -X POST http://localhost:3839/api/shutdown

Dark Mode Support

The management interface automatically adapts to your system’s theme preference: - Light Mode: Clean, professional appearance for daytime use - Dark Mode: Comfortable viewing for low-light environments - Automatic Detection: Uses CSS prefers-color-scheme media query

Application Structure

Standard Shiny App

apps/myapp/
β”œβ”€β”€ app.R          # Single-file Shiny app
└── [other files]

Multi-file Shiny App

apps/myapp/
β”œβ”€β”€ ui.R           # UI definition
β”œβ”€β”€ server.R       # Server logic
└── [other files]

R Markdown App

apps/myapp/
β”œβ”€β”€ report.Rmd     # R Markdown with runtime: shiny
└── [other files]

Quarto App

apps/myapp/
β”œβ”€β”€ dashboard.qmd  # Quarto document with server: shiny
└── [other files]

Example Applications

The project includes four example applications demonstrating different application types:

1. Sales Dashboard (examples/sales/)

2. Inventory Management (examples/inventory/)

3. Business Reports (examples/reports/)

4. Interactive Dashboard (examples/dashboard/)

Memory Management

The server includes automatic memory management features:

Cleanup runs automatically every 5 minutes and logs activity for monitoring.

Logging

Log Files

Log Levels

Development

Running Individual Apps

For development, you can run apps directly:

# Standard Shiny app
R -e "shiny::runApp('apps/sales', port = 3001)"

# R Markdown app
R -e "rmarkdown::run('apps/reports/report.Rmd', shiny_args = list(port = 3003, host = '127.0.0.1'))"

# Quarto app
R -e "quarto::quarto_serve('apps/dashboard/dashboard.qmd', port = 3004, host = '127.0.0.1')"

Adding New Applications

  1. Create your app in apps/{app_name}/
  2. Add configuration entry to config.json (only name and path required)
  3. Restart the server

The server will automatically assign the next available port to your new application.

Health Endpoints

Proxy Server: - Health check: GET /health - Returns {"status": "healthy"} - Apps status: GET /api/apps - Returns detailed application status (used by landing page)

Management Interface: - System status: GET /api/status - Returns overall system health - Apps status: GET /api/apps - Returns detailed application status - Connections: GET /api/connections - Returns active connection details

πŸ“ Package Structure

tinyshinyserver/
β”œβ”€β”€ R/                    # R source code
β”‚   β”œβ”€β”€ start_tss.R       # Main exported function
β”‚   β”œβ”€β”€ config.R          # Configuration management
β”‚   β”œβ”€β”€ handlers.R        # HTTP request routing
β”‚   β”œβ”€β”€ process_manager.R # Application lifecycle
β”‚   └── ...              # Other core modules
β”œβ”€β”€ inst/
β”‚   β”œβ”€β”€ examples/         # Example apps & config
β”‚   β”‚   β”œβ”€β”€ sales/        # Simple Shiny app
β”‚   β”‚   β”œβ”€β”€ inventory/    # Multi-file Shiny app
β”‚   β”‚   β”œβ”€β”€ reports/      # R Markdown dashboard
β”‚   β”‚   β”œβ”€β”€ dashboard/    # Quarto dashboard
β”‚   β”‚   └── config.json   # Example configuration
β”‚   └── templates/        # HTML templates & CSS
β”œβ”€β”€ man/                  # Documentation (.Rd files)
β”œβ”€β”€ DESCRIPTION           # Package metadata
└── NAMESPACE            # Exported functions

Architecture

The server uses a multi-process architecture:

                    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                    β”‚  Management Server  β”‚
                    β”‚    (Port 3839)      β”‚
                    β”‚                     β”‚
                    β”‚  β€’ System Status    β”‚
                    β”‚  β€’ App Control      β”‚
                    β”‚  β€’ Connection Info  β”‚
                    β”‚  β€’ Graceful Shutdownβ”‚
                    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                    
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚   Proxy Server      β”‚
β”‚   (Port 3838)       β”‚
β”‚                     β”‚
β”‚  β”Œβ”€WebSocket─────────
β”‚  β”‚  Handler         β”‚
β”‚  β”‚                  β”‚
β”‚  β”‚  β”Œβ”€HTTP───────────
β”‚  β”‚  β”‚  Handler      β”‚
β””β”€β”€β”Όβ”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
   β”‚  β”‚
   β”‚  └── HTTP Requests ──┐
   β”‚                      β”‚
   └── WebSocket ─────────┼───┐
       Messages           β”‚   β”‚
                          β–Ό   β–Ό
              β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
              β”‚ Sales    β”‚ β”‚Inventory β”‚ β”‚ Reports  β”‚ β”‚Dashboard β”‚
              β”‚(Port     β”‚ β”‚(Port     β”‚ β”‚(Port     β”‚ β”‚(Port     β”‚
              β”‚ 3001)    β”‚ β”‚ 3002)    β”‚ β”‚ 3003)    β”‚ β”‚ 3004)    β”‚
              β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Key Components

πŸ”§ Troubleshooting

Common Issues

Apps won’t start
WebSocket connection failures
Management interface not accessible

πŸ” Debug Mode

# Check server logs (created after starting)
list.files("logs", pattern = "\\.(log|txt)$")

# Monitor main server log
tail -f logs/server.log  # Linux/macOS
Get-Content logs/server.log -Wait  # PowerShell

πŸ”’ Security Considerations

⚠️ Important: This server is designed for development and internal use.

For production deployment, consider: - Adding authentication (see Caddy reverse proxy example) - SSL/TLS encryption for external access - Firewall rules and network segmentation - Regular security updates - Rate limiting on management endpoints

Built-in security features: - Management interface restricted to localhost only - Input validation for configuration files - Process isolation between applications

🀝 Contributing

Contributions are welcome! Please see our contribution guidelines:

  1. Fork the repository
  2. Create a feature branch: git checkout -b feature/amazing-feature
  3. Make your changes and add tests
  4. Test thoroughly: devtools::check()
  5. Submit a pull request

Development Setup

# Clone and setup for development
git clone https://github.com/lab1702/tinyshinyserver.git
cd tinyshinyserver

# Install with dependencies
devtools::install_deps()
devtools::load_all()

# Run checks
devtools::check()

πŸ“„ License

This project is licensed under the MIT License - see the LICENSE file for details.

πŸ†˜ Support


Built with ❀️ for the R and Shiny community