{"id":34599251,"url":"https://github.com/niradler/streamlit-fastapi-proxy","last_synced_at":"2026-05-26T08:03:22.897Z","repository":{"id":307272210,"uuid":"1028938888","full_name":"niradler/streamlit-fastapi-proxy","owner":"niradler","description":null,"archived":false,"fork":false,"pushed_at":"2025-07-30T10:26:52.000Z","size":395,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-07-30T11:57:13.452Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/niradler.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-07-30T09:30:19.000Z","updated_at":"2025-07-30T10:26:55.000Z","dependencies_parsed_at":"2025-07-30T11:57:17.394Z","dependency_job_id":"ad64eee6-4c49-4420-a013-22d9990accef","html_url":"https://github.com/niradler/streamlit-fastapi-proxy","commit_stats":null,"previous_names":["niradler/streamlit-fastapi-proxy"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/niradler/streamlit-fastapi-proxy","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/niradler%2Fstreamlit-fastapi-proxy","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/niradler%2Fstreamlit-fastapi-proxy/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/niradler%2Fstreamlit-fastapi-proxy/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/niradler%2Fstreamlit-fastapi-proxy/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/niradler","download_url":"https://codeload.github.com/niradler/streamlit-fastapi-proxy/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/niradler%2Fstreamlit-fastapi-proxy/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28002250,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-12-24T02:00:07.193Z","response_time":83,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-12-24T12:07:54.071Z","updated_at":"2025-12-24T12:08:11.700Z","avatar_url":"https://github.com/niradler.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Streamlit FastAPI Proxy\n\nA FastAPI-based proxy server for managing and serving multiple Streamlit applications with full WebSocket support. Can be used as a standalone proxy server or integrated into existing FastAPI applications.\n\n## Features\n\n- 🚀 **Multiple Streamlit Apps**: Run and manage multiple Streamlit applications simultaneously\n- 🔌 **WebSocket Support**: Full WebSocket proxying for real-time Streamlit features\n- 📡 **HTTP Proxy**: Complete HTTP request/response proxying\n- 🎛️ **App Management**: RESTful API for starting, stopping, and managing apps\n- 📊 **App Registry**: Persistent storage of registered applications\n- 🔄 **Auto Port Management**: Automatic port allocation and management\n- 📝 **Access Tracking**: Track last access times for apps\n- 🧩 **Easy Integration**: Simple integration into existing FastAPI applications\n- 🏁 **Default Apps**: Auto-start apps marked with `run_by_default=True`\n\n![Demo](st-proxy.gif)\n\n## Installation\n\n### From PyPI (Recommended)\n\n```bash\npip install streamlit-fastapi-proxy\n\n# Run the standalone server\nstreamlit-proxy\n```\n\n### From Source\n\n```bash\n# Clone the repository\ngit clone https://github.com/niradler/streamlit-fastapi-proxy.git\ncd streamlit-fastapi-proxy\n\n# Install dependencies with uv\nuv sync\n\n# Or install manually\npip install -e .\n\n# Run the standalone server\nstreamlit-proxy\n# Or run directly without installing\npython -m streamlit_proxy.cli\n```\n\n### Using Docker\n\n```bash\n# Clone the repository\ngit clone https://github.com/niradler/streamlit-fastapi-proxy.git\ncd streamlit-fastapi-proxy\n\n# Build and run with Docker Compose\ndocker-compose up -d\n\n# Or build and run manually\ndocker build -t streamlit-fastapi-proxy .\ndocker run -d -p 8000:8000 \\\n  -v $(pwd)/app_registry.json:/app/app_registry.json \\\n  -v $(pwd)/apps:/app/apps \\\n  streamlit-fastapi-proxy\n```\n\n## Quick Start\n\n### Option 1: Standalone Server\n\n1. **Install the package:**\n   ```bash\n   pip install streamlit-fastapi-proxy\n   ```\n\n2. **Start the proxy server:**\n   ```bash\n   streamlit-proxy\n   # Or run directly from source\n   python -m streamlit_proxy.cli\n   ```\n\n3. **Register a Streamlit app:**\n   ```bash\n   curl -X POST \"http://localhost:8000/_apps/register\" \\\n        -H \"Content-Type: application/json\" \\\n        -d '{\n          \"name\": \"Test App\",\n          \"slug\": \"test-app\", \n          \"path\": \"/path/to/your/app.py\",\n          \"run_by_default\": false\n        }'\n   ```\n\n4. **Start the app:**\n   ```bash\n   curl -X POST \"http://localhost:8000/_apps/test-app/start\"\n   ```\n\n5. **Access your app:**\n   Open `http://localhost:8000/apps/test-app/` in your browser\n\n### Option 2: Integration with Existing FastAPI App\n\n```python\nfrom fastapi import FastAPI\nfrom streamlit_proxy import integrate_streamlit_proxy\n\n# Create your FastAPI app\napp = FastAPI(title=\"My Dashboard\")\n\n# Add your existing routes\n@app.get(\"/\")\ndef read_root():\n    return {\"message\": \"Hello World\"}\n\n# Integrate Streamlit proxy\nintegrate_streamlit_proxy(app)\n\n# Run with: uvicorn main:app --reload\n```\n\nThis will add:\n- Management endpoints at `/_apps/*`\n- Proxy endpoints at `/apps/*`\n- CORS middleware (if not already present)\n\n### Option 3: Manual Integration\n\nFor more control over the integration:\n\n```python\nfrom fastapi import FastAPI\nfrom streamlit_proxy.main import (\n    setup_streamlit_proxy_routes,\n    add_streamlit_proxy_middleware,\n)\n\napp = FastAPI()\n\n# Add routes with custom prefix\nsetup_streamlit_proxy_routes(app)\n\n# Optionally add CORS middleware\nadd_streamlit_proxy_middleware(app)\n```\n\n## API Endpoints\n\n### App Management\n\n- **GET** `/_apps/` - List all registered apps with status\n- **POST** `/_apps/register` - Register a new Streamlit app\n- **POST** `/_apps/{slug}/start` - Start a specific app\n- **POST** `/_apps/{slug}/stop` - Stop a specific app  \n- **GET** `/_apps/{slug}/status` - Get detailed status of an app\n- **POST** `/_apps/cleanup` - Stop and cleanup all running apps\n\n### Proxy Endpoints\n\n- **GET** `/apps/` - Redirect to first default app (if configured)\n- **ALL** `/apps/{slug}/` - Proxy to app root\n- **ALL** `/apps/{slug}/{path:path}` - Proxy HTTP requests to the app\n- **WebSocket** `/apps/{slug}/stream` - Proxy WebSocket connections\n- **WebSocket** `/apps/{slug}/_stcore/stream` - Proxy Streamlit core WebSocket\n- **WebSocket** `/apps/{slug}/{ws_path:path}` - Generic WebSocket proxy\n\n## Configuration\n\nEnvironment variables:\n\n- `ROOT_PATH` - Root directory for resolving relative paths (default: current working directory)\n- `APP_REGISTRY_PATH` - Path to app registry JSON file (default: `app_registry.json`, relative to ROOT_PATH)\n- `STARTING_PORT` - Starting port for Streamlit apps (default: `8503`)\n- `MAX_PORT` - Maximum port for Streamlit apps (default: `8550`)\n\n### Path Resolution\n\nThe proxy supports both absolute and relative paths:\n\n- **Absolute paths**: Used as-is (e.g., `/home/user/apps/my_app.py`)\n- **Relative paths**: Resolved relative to `ROOT_PATH` (e.g., `apps/my_app.py` → `{ROOT_PATH}/apps/my_app.py`)\n\nThis makes it easy to deploy in different environments (local, Docker, production) without changing app configurations.\n\n## App Registration Format\n\n```json\n{\n  \"name\": \"My Streamlit App\",\n  \"slug\": \"my-app\",\n  \"path\": \"/absolute/path/to/app.py\",\n  \"desired_port\": 8503,\n  \"run_by_default\": false\n}\n```\n\n### Fields\n\n- **name** (required): Display name of the application\n- **slug** (required): Unique identifier used in URLs (e.g., `/apps/{slug}/`)\n- **path** (required): Path to the Streamlit app file (absolute or relative to ROOT_PATH)\n- **desired_port** (optional): Preferred port for the app (auto-assigned if not specified)\n- **run_by_default** (optional): If `true`, app will auto-start when proxy starts (default: `false`)\n\n### Default Apps\n\nApps with `run_by_default: true` will:\n1. Auto-start when the proxy server starts\n2. Be accessible at the root `/apps/` path (first default app gets priority)\n\nExample:\n```json\n{\n  \"name\": \"Main Dashboard\",\n  \"slug\": \"dashboard\",\n  \"path\": \"apps/dashboard.py\",\n  \"run_by_default\": true\n}\n```\n\nAccess at: `http://localhost:8000/apps/` → redirects to `http://localhost:8000/apps/dashboard/`\n\n## WebSocket Support\n\nThis proxy provides full WebSocket support for Streamlit's real-time features:\n\n- ✅ Real-time widget updates\n- ✅ Interactive plots and charts  \n- ✅ Live data streaming\n- ✅ Session state synchronization\n- ✅ Auto-rerun functionality\n\n## Example Usage\n\nSee the `apps/test_app.py` for a sample Streamlit application that demonstrates WebSocket functionality.\n\n## Development\n\n```bash\n# Install development dependencies\nuv sync\n\n# Run in development mode with auto-reload\nuvicorn main:app --reload --host 0.0.0.0 --port 8000\n\n# Or with uv\nuv run uvicorn main:app --reload\n\n# Format code\nuv run black .\nuv run isort .\n\n# Type checking\nuv run mypy streamlit_proxy\n\n# Linting\nuv run ruff check .\n\n# Build package\nuv build\n```\n\n## Architecture\n\n```\n┌─────────────────┐    HTTP/WS     ┌─────────────────┐\n│   Client        │ ◄─────────────► │  FastAPI Proxy  │\n│   Browser       │                │  (Port 8000)    │\n└─────────────────┘                └─────────────────┘\n                                           │\n                                           │ HTTP/WS Proxy\n                                           ▼\n                                   ┌─────────────────┐\n                                   │  Streamlit Apps │\n                                   │  (Ports 8503+)  │\n                                   │                 │\n                                   │  ┌──────────┐   │\n                                   │  │ App 1    │   │\n                                   │  │ App 2    │   │\n                                   │  │ App N... │   │\n                                   │  └──────────┘   │\n                                   └─────────────────┘\n```\n\n## Advanced Usage\n\n### Programmatic App Management\n\n```python\nfrom streamlit_proxy.manager_service import AppControllerService\nfrom streamlit_proxy.models import AppConfig\n\n# Create service instance\ncontroller = AppControllerService()\n\n# Register an app programmatically\napp_config = AppConfig(\n    name=\"Analytics Dashboard\",\n    slug=\"analytics\",\n    path=\"apps/analytics.py\",\n    run_by_default=True\n)\ncontroller.register_app(app_config)\n\n# Start the app\nawait controller.start_app(\"analytics\")\n\n# Check status\nstatus = controller.get_app_status(\"analytics\")\nprint(status)\n\n# Stop the app\nawait controller.stop_app(\"analytics\")\n```\n\n### Custom Streamlit Command\n\nBy default, the proxy uses `python -m streamlit` to run apps. You can customize this by subclassing `AppService`:\n\n```python\nfrom streamlit_proxy.services import AppService\n\nclass CustomAppService(AppService):\n    def _get_streamlit_command(self) -\u003e list[str]:\n        # Use a specific Python version or virtual environment\n        return [\"/path/to/venv/bin/python\", \"-m\", \"streamlit\"]\n```\n\n### Cleanup Handlers\n\nIf integrating into an existing FastAPI app, you may want to handle cleanup:\n\n```python\nfrom contextlib import asynccontextmanager\nfrom fastapi import FastAPI\nfrom streamlit_proxy import integrate_streamlit_proxy\nfrom streamlit_proxy.main import cleanup_running_apps\n\n@asynccontextmanager\nasync def lifespan(app: FastAPI):\n    # Startup\n    yield\n    # Shutdown - cleanup Streamlit apps\n    await cleanup_running_apps()\n\napp = FastAPI(lifespan=lifespan)\nintegrate_streamlit_proxy(app)\n```\n\n## Troubleshooting\n\n### Apps not starting\n\n1. Check that the path to your Streamlit app is correct\n2. Verify the port range is available (STARTING_PORT to MAX_PORT)\n3. Ensure Streamlit is installed: `pip install streamlit`\n4. Check logs for specific error messages\n\n### WebSocket connection issues\n\n1. Ensure your reverse proxy (if any) supports WebSocket connections\n2. Check that CORS middleware is properly configured\n3. Verify firewall rules allow WebSocket connections\n\n### Port conflicts\n\nIf you get port conflicts, adjust the port range:\n```bash\nexport STARTING_PORT=9000\nexport MAX_PORT=9100\nstreamlit-proxy\n```\n\n## License\n\nThis project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.\n\n## Contributing\n\nContributions are welcome! Please feel free to submit a Pull Request.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fniradler%2Fstreamlit-fastapi-proxy","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fniradler%2Fstreamlit-fastapi-proxy","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fniradler%2Fstreamlit-fastapi-proxy/lists"}