feat(cloudflare-tunnel): integrate Cloudflare tunnels for instance access

Backend:
- Add cloudflare_tunnel.py service for creating/deleting tunnels via Cloudflare API
- Add public_url and tunnel_id fields to ToolInstance model
- Update start_instance to create Cloudflare tunnel after container starts
- Update stop_instance to delete tunnel before stopping container
- Update delete_instance to cleanup tunnel before deletion
- Update restart_instance to recreate tunnel on restart
- Create Alembic migration 0011 for tunnel fields
- Add Cloudflare config settings (API token, zone ID, account ID, base domain)

Infrastructure:
- Add cloudflared service to docker-compose.traefik.yml
- Mount shared cloudflared_config volume between API and cloudflared containers
- Add Cloudflare env vars to API service

Frontend:
- Update instance Open button to handle both full URLs and proxy paths

The instance URL is now set to the Cloudflare tunnel public URL when available,
falling back to the API proxy path if tunnel creation fails.
This commit is contained in:
Fusion
2026-05-20 14:25:06 +02:00
parent 98795e31dd
commit b40eb3e88c
12 changed files with 688 additions and 3 deletions
@@ -0,0 +1,50 @@
## ADDED Requirements
### Requirement: System creates Cloudflare tunnel on instance start
When a tool instance is started, the system SHALL create a Cloudflare tunnel and DNS record to expose it publicly.
#### Scenario: Start instance creates tunnel
- **WHEN** a user starts a tool instance
- **THEN** the system calls the Cloudflare API to create a tunnel
- **AND** creates a CNAME DNS record for `instance-{id}.{zone}`
- **AND** stores the tunnel ID and public URL in the database
#### Scenario: Tunnel points to correct container
- **WHEN** a tunnel is created for an instance
- **THEN** the tunnel ingress rule maps the subdomain to the container's internal DNS name and port
### Requirement: System deletes Cloudflare tunnel on instance stop
When a tool instance is stopped or deleted, the system SHALL clean up the associated Cloudflare tunnel and DNS record.
#### Scenario: Stop instance deletes tunnel
- **WHEN** a user stops a running instance
- **THEN** the system deletes the DNS record
- **AND** deletes the Cloudflare tunnel
#### Scenario: Delete instance cleans up tunnel
- **WHEN** a user deletes an instance
- **AND** the instance has an active tunnel
- **THEN** the system deletes both the DNS record and the tunnel
### Requirement: Frontend uses public URL for instance access
The frontend SHALL display and link to the public Cloudflare URL for running instances.
#### Scenario: Open button uses public URL
- **WHEN** a user views a running instance
- **THEN** the "Open" button links to the instance's public URL
- **AND** the URL opens in a new tab
#### Scenario: Session list shows public URL
- **WHEN** a user views their sessions
- **THEN** each running session displays its public URL
### Requirement: Only instance owner can start/stop/delete tunnels
The system SHALL verify that only the instance owner can trigger tunnel creation or deletion.
#### Scenario: Owner starts instance
- **WHEN** the instance owner clicks "Start"
- **THEN** the tunnel is created successfully
#### Scenario: Non-owner attempts to start
- **WHEN** a non-owner attempts to start an instance
- **THEN** the request returns 403 Forbidden