The hardware and bandwidth for this mirror is donated by dogado GmbH, the Webhosting and Full Service-Cloud Provider. Check out our Wordpress Tutorial.
If you wish to report a bug, or if you are interested in having us mirror your free-software or open-source project, please feel free to contact us at mirror[@]dogado.de.
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
# Install from GitHub
remotes::install_github("lab1702/tinyshinyserver")# Clone and install locally
git clone https://github.com/lab1702/tinyshinyserver.git
cd tinyshinyserver
Rscript -e "devtools::install('.')"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
# Load the package
library(tinyshinyserver)# Copy included example apps to your directory
examples_path <- system.file("examples", package = "tinyshinyserver")
file.copy(examples_path, ".", recursive = TRUE)# Start with the example configuration
start_tss(config = "examples/config.json")π Main Interface: http://localhost:3838
βοΈ Management Dashboard: http://localhost:3839
π± Individual Apps:
http://localhost:3838/proxy/{app_name}/
# Package overview and getting started
?tinyshinyserver
# Main function help
?start_tss
# Configuration format reference
?config-formatruntime: shinyserver: shinyThe 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
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.
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"
}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.
The server supports two application life cycle modes controlled by
the resident configuration option:
"resident": true)"resident": false, default)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
}
]
}| 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 |
The proxy_host option controls which network interface
the proxy server binds to:
"localhost" or "127.0.0.1" - Binds to
localhost only (default, most secure)"0.0.0.0" - Binds to all network interfaces (allows
external access)"::1" - IPv6 localhost"::" - All IPv6 interfacesβ οΈ 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.
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.
The landing page at http://localhost:3838 provides an overview of all hosted applications with real-time status information.
The landing page uses the same status API as the management interface, ensuring consistency between all monitoring views.
The management interface provides a professional web-based dashboard for monitoring and controlling your Shiny server.
Visit http://localhost:3839 to access the management dashboard.
π Security: The management interface is restricted to localhost only for security.
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/shutdownThe 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
apps/myapp/
βββ app.R # Single-file Shiny app
βββ [other files]
apps/myapp/
βββ ui.R # UI definition
βββ server.R # Server logic
βββ [other files]
apps/myapp/
βββ report.Rmd # R Markdown with runtime: shiny
βββ [other files]
apps/myapp/
βββ dashboard.qmd # Quarto document with server: shiny
βββ [other files]
The project includes four example applications demonstrating different application types:
examples/sales/)examples/inventory/)examples/reports/)runtime: shinyexamples/dashboard/)server: shinyformat: dashboardThe server includes automatic memory management features:
Cleanup runs automatically every 5 minutes and logs activity for monitoring.
logs/server.log - Main server logslogs/{app_name}_output.log - Per-app stdout logslogs/{app_name}_error.log - Per-app stderr logsINFO - Normal operationsWARN - Warning conditions (e.g., queue limits
reached)ERROR - Error conditions requiring attentionFor 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')"apps/{app_name}/config.json (only name and
path required)The server will automatically assign the next available port to your new application.
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
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
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) β
ββββββββββββ ββββββββββββ ββββββββββββ ββββββββββββ
netstat -an | findstr :3838logs/{app_name}_error.log?start_tss for configuration help# 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β οΈ 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
Contributions are welcome! Please see our contribution guidelines:
git checkout -b feature/amazing-featuredevtools::check()# 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()This project is licensed under the MIT License - see the LICENSE file for details.
?tinyshinyserver, ?start_tss,
?config-formatBuilt with β€οΈ for the R and Shiny community
These binaries (installable software) and packages are in development.
They may not be fully stable and should be used with caution. We make no claims about them.
Health stats visible at Monitor.