THON - The Hackathon Organizer Node
Run multiple VS Code sandbox instances with nginx SSL, groups-based user management, and optional local LLM inference
THON
Run multiple VS Code sandbox instances concurrently with nginx SSL reverse proxy, groups-based user management, persistent workspaces, and optional local LLM inference via Lemonade Server.
Features
- Unified CLI:
thon install,thon init,thon setup,thon run,thon launch— one config file (thon.yaml) for everything - Multi-Instance: Multiple concurrent VS Code sandboxes from a single command
- Groups-Based: Define users and groups in YAML or manage via dashboard
- Web Dashboard: Streamlit dashboard with 7 pages for instance, group, user, workspace, Lemonade, gateway, and settings management
- SSL/TLS: Automatic nginx reverse proxy with 4 SSL providers (auto, certbot, mkcert, openssl)
- Domain Support: Let's Encrypt certificates and domain-based URLs for production
- Persistent Workspaces: PVC Docker volumes or host bind mounts for workspace persistence
- Local LLM: Optional Lemonade Server integration for local inference with dynamic rescaling
- Semantic Indexing: Embedding model for Kilo Code's semantic code search
- AI Gateway: Optional APISIX gateway with per-user or per-group rate limiting, per-model concurrency, and API keys
- Authentication: Local password for dashboard; OIDC/OAuth2 (GitHub, GitLab, LinkedIn) for REST API
- Config Files: Store and manage groups YAML, kilo.jsonc, and VS Code settings in the database
- Kilo Code Ready: Auto-generated config with skeleton merging, experimental flags, and indexing
- LLM Observability: Optional Langfuse integration for tracing LLM calls
Quick Start
1. Prerequisites
# One-time host setup
bash ./scripts/setup.shInstalls: python3, nginx, docker.io, mkcert, openssl
2. Build Docker Image
docker build -t waterpistol/thon:latest ./3. Initialize Configuration
# Interactive setup wizard (recommended)
python -m thon init
# Or non-interactive (CI-friendly)
python -m thon init --non-interactiveThis creates a thon.yaml config file with all settings.
4. Setup and Run
# Install prerequisites and configure all components
python -m thon setup
# Start the API server (FastAPI on :8100)
python -m thon run
# Launch VS Code instances (batch mode from thon.yaml)
python -m thon launchAlternatively, use main.py directly:
python ./scripts/main.py --groups groups.yaml --external-ip 1.2.3.4Each user gets their own VS Code sandbox at https://<ip>/<endpoint_path>/.
Architecture
┌─────────────────────────────────────────────────────────────┐
│ Host Machine │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ nginx (443) │ │
│ │ SSL termination + WebSocket proxy │ │
│ └──────────────────────┬──────────────────────────────┘ │
│ │ │
│ ┌──────────────────────┼──────────────────────────────┐ │
│ │ Docker Network │ │
│ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │
│ │ │ Sandbox 1 │ │ Sandbox 2 │ │ Sandbox 3 │ │ │
│ │ │ code-server │ │ code-server │ │ code-server │ │ │
│ │ │ :8443 │ │ :8444 │ │ :8445 │ │ │
│ │ └─────────────┘ └─────────────┘ └─────────────┘ │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Lemonade Server (Optional) │ │
│ │ Chat model + Embedding model (semantic search) │ │
│ │ :13305 │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ APISIX AI Gateway (Optional) │ │
│ │ Rate limiting + per-user/group API keys │ │
│ │ Chat route + Embedding route │ │
│ │ :9080 │ │
│ └─────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘Components
| Component | Role |
|---|---|
| thon CLI | Unified entry point: thon install, thon init, thon setup, thon run, thon launch, thon config, thon nginx, thon gateway, thon cleanup |
| main.py | Orchestrates sandbox creation, nginx configs, workspace setup |
| Streamlit Dashboard | Web UI with 7 pages for instance, group, user, workspace, Lemonade, gateway, and settings management (:8501) |
| FastAPI REST API | Programmatic API for instances, groups, users, Lemonade, gateway, auth, nginx, config files (:8100) |
| nginx | SSL termination + WebSocket proxy (per-port or combined config) |
| code-server | VS Code in the browser, runs HTTP inside each sandbox |
| Lemonade Server | Optional local LLM inference (chat + embedding models) with dynamic rescaling |
| APISIX Gateway | Optional rate limiting with per-user or per-group API keys and per-model concurrency |
| SQLite | Persistent storage for sandbox records, groups, users, events, and settings |
Network Modes
Network mode is auto-detected from the server-returned endpoint format:
| Mode | Endpoint Format | Detection |
|---|---|---|
| Host | 127.0.0.1:8443 | No / after port |
| Bridge | 127.0.0.1:52322/proxy/8443 | /proxy/ in endpoint |
Workspace Persistence
| Mode | Storage | Lifecycle |
|---|---|---|
| PVC Volume | Docker named volume (thon-workspace-*) | Persists across instance recreations |
| Bind Mount | Host directory (--workspace-dir) | Persists on host filesystem |
| Ephemeral | Inside container | Lost when container is removed |
PVC volumes are created automatically when users are imported via the dashboard
or thon.yaml. When a sandbox is recreated, the same PVC volume is reattached.
SSL/TLS
| Provider | Description | Best For |
|---|---|---|
| auto (default) | Tries mkcert → certbot → openssl in order | Most setups |
| certbot | Let's Encrypt certificates | Production with domain |
| mkcert | CA-trusted certs, filename includes IP hash | Development |
| openssl | Self-signed certs with IP/domain in SAN | Fallback |
When a domain is configured (nginx.domain in thon.yaml), nginx uses it as
server_name and Let's Encrypt is preferred for CA-trusted certificates.
CA cert served at https://<ip>/ca.crt for remote clients.
URL Display
| URL Type | Format | Priority |
|---|---|---|
| Domain URL | https://{domain}/{endpoint_path}/ | Highest (when domain configured) |
| Public URL | https://{ip}/{endpoint_path}/ | Medium (via external IP) |
| Local URL | http://127.0.0.1:{port}/ | Lowest (local access) |
InstanceInfo.url computed property: domain_url > public_url > local_url.
Next Steps
- Installation Guide - Detailed setup instructions
- Dashboard - Streamlit web dashboard with 7 pages
- Lemonade Server - Local LLM inference with dynamic rescaling
- AI Gateway - APISIX rate limiting, per-model concurrency, and API key management
- Configuration - Full configuration reference
- CLI Reference - Command-line options