## Context Currently, tool instances run as Docker containers on the internal Docker network. The backend stores their URL as `http://localhost:{port}`, which is only accessible from inside the API container. Users clicking "Open" in the frontend get a 404 because their browser can't reach the internal container. The API and containers share a Docker network, so the API can reach containers by their container name or IP. ## Goals / Non-Goals **Goals:** - Users can access running tool instances through the API via HTTPS - Proxy enforces ownership (only instance owner can access) - Support both HTTP and WebSocket traffic - Minimal latency overhead - Works with existing Docker setup **Non-Goals:** - Public URLs / custom domains for instances (that's Option 2/3) - Load balancing across multiple instances - Advanced path rewriting (just pass-through) ## Decisions ### Proxy via FastAPI route (not separate service) **Decision:** Implement proxying as a FastAPI endpoint using `httpx` for async forwarding. **Rationale:** - Keeps everything in one deployable unit - Easy access to existing auth dependencies (`get_current_user_id`) - Can reuse existing session cookie auth - No extra infrastructure needed **Alternative considered:** Separate nginx/traefik proxy service - Rejected: adds operational complexity for a single feature ### Use container name for internal routing **Decision:** Store container name in ToolInstance model and route to `http://{container_name}:{port}` **Rationale:** - Container names are stable and DNS-resolvable within Docker network - More reliable than IPs which can change - Already using container names in docker.py ### Path: `/instances/{id}/proxy/{path:path}` **Decision:** All proxied traffic goes through `/instances/{id}/proxy/*` **Rationale:** - Clear URL structure - Easy to apply auth middleware - `path:path` captures everything after `/proxy/` ### WebSocket upgrade handling **Decision:** Support WebSocket upgrade by inspecting the `Upgrade: websocket` header and establishing a bidirectional pipe. **Rationale:** - code-server and jupyter use WebSockets for real-time features - FastAPI doesn't natively support proxying WebSockets, but we can use `starlette.websockets` to handle the upgrade ## Risks / Trade-offs **[Risk]** API becomes bandwidth bottleneck for all instance traffic → **Mitigation:** Document this limitation. Future migration to Option 2 (Traefik labels) possible. **[Risk]** Container name collision → **Mitigation:** Instance names already include UUID suffix, collision probability is negligible. **[Risk]** Large file uploads/downloads through proxy → **Mitigation:** Use streaming response in httpx. Monitor memory usage. ## Migration Plan 1. Deploy backend changes (proxy endpoint + model updates) 2. Update frontend links to use proxy URL 3. Test with code-server instance 4. Monitor API performance ## Open Questions - Should we add rate limiting to the proxy endpoint? - Do we need to rewrite response headers (Location, Set-Cookie)?