Provision · Deploy · Manage
⬤ No VM
☁️

CloudLaunch

An end-to-end cloud infrastructure automation platform. Provision a real Azure VM, deploy a containerised web application, and observe every operation streamed live — all from a single interface, with no manual cloud console interaction.

Python · FastAPI Azure SDK WebSocket Streaming Docker · Nginx Auto-Destroy
Workflow — four steps
1
🚀
Provision Infrastructure
Click Provision VM in the Operations tab. The platform creates a complete Azure stack — Virtual Network, NSG, Public IP, NIC, and Ubuntu VM — in approximately 90 seconds. Every step streams to the terminal in real time.
2
📦
Deploy the Application
Click Deploy App. The platform connects via SSH, installs Docker, uploads the application files over SFTP, builds the container image, and starts the Nginx server — fully automated, with live log output throughout.
3
🌐
Access the Application
Once deployed, a live IP link appears. Open it to reach the application served from your provisioned Azure VM, running inside a Docker container, over the public internet.
4
�️
Tear Down
Click Destroy to delete every Azure resource with a single API call. If you don't, the platform automatically tears everything down after 20 minutes — a server-side timer that cannot be overridden from the browser.
Platform capabilities
🖥️
Real Azure Infrastructure
Creates live Azure resources — VMs, Virtual Networks, Network Security Groups, Public IPs, and NICs — via the official Azure SDK. No mocks, no simulators.
📡
Live Log Streaming
Every log line from background operations is pushed to the dashboard in real time over a persistent WebSocket connection. No polling. No page refreshes.
🐳
Automated Deployment Pipeline
SSH connection, Docker installation, SFTP file transfer, image build, and container start are all orchestrated programmatically — no shell scripts, no Ansible.
🛡️
Multi-Layer Abuse Protection
Per-IP rate limiting, a global concurrency cap, an active VM budget, and a mandatory server-side auto-destroy timer operate independently to prevent runaway spend.
⌨️
Three Interfaces, One Backend
The same operations are available via a Typer CLI, a FastAPI REST API, and this vanilla JS dashboard — all backed by a single provider abstraction layer.
🔄
Full Lifecycle Management
Provision → Deploy → Status → Redeploy → Destroy. The complete infrastructure lifecycle is handled end-to-end, with persistent state across server restarts.
Live demo note: This runs against a real Azure subscription. Provisioning takes ~90 seconds; deployment ~2 minutes (Docker setup on a fresh VM). All VM resources are automatically deleted after 20 minutes regardless of user action. All log output is streamed live — nothing is pre-recorded.
Resource preview
Resources that will be created
Resource Name Type Detail
Loading plan…
Hourly
$0.010
Standard_B1s
Monthly est.
$7.49
730 hrs / month
VM Size
Standard_B1s
1 vCPU · 1 GB RAM
Region
southeastasia
Southeast Asia
This provisions a real Azure VM (~$0.01/hr, Standard_B1s). Please click Destroy when you're finished. All resources are automatically deleted after 20 minutes.
⚙ Configuration
Idle — select an operation above
Live VM status
Power State
Public IP
VM Size
Location
OS Disk
VM Name
Provision a VM first, then refresh.
All operations
No jobs yet. Run an operation first.
Python 3.8 FastAPI + Uvicorn Azure SDK WebSocket Docker

CloudLaunch — Engineering Overview

A cloud infrastructure automation backend built without infrastructure-as-code frameworks. Azure resources are managed via direct SDK calls, SSH automation is handled via Paramiko, and real-time log streaming is implemented over native WebSocket — no third-party abstractions.

~900
Lines of Python
6
Azure resources per VM
<200ms
API response time
~90s
End-to-end provision
3
Runtime services
Runtime services: Python process, Azure API, provisioned VM. No database, no cache, no message queue.

System Architecture — Request Flow

Browser
dashboard.html
HTTP / WS
CLI
Typer / Rich
Python calls
REST Client
curl / scripts
HTTP POST
FastAPI / Uvicorn
POST /provision · /deploy · /destroy  |  WS /ws/{job_id}
Rate limiter · Concurrency cap · Budget guard (ASGI middleware)
↓ launch_job() — spawns daemon thread
Background Thread
Sync provider code · queue.Queue
Blocking I/O (Azure SDK, SSH)
⟷ run_in_executor
WebSocket Handler
Async drain · heartbeat · log replay
Async event loop
↓ Azure SDK calls (blocking, inside thread)
Resource Groups
ResourceManagementClient
+
Virtual Network · NSG · IP
NetworkManagementClient
+
Virtual Machine
ComputeManagementClient
↓ VM ready — Paramiko SSH
Ubuntu 22.04 VM
Standard_B1s · Southeast Asia
→ Docker →
Nginx Container
port 80 · --restart always
+
state.json
IP · resource group · SSH key
Technology choices
API Framework
FastAPI
Async-native with first-class WebSocket support, Pydantic v2 request validation, and auto-generated OpenAPI docs. No bolt-on WebSocket library needed.
Python 3.8
Cloud SDK
Azure SDK for Python
Direct ARM API calls with no abstraction layer. Full control over resource creation order, error handling, polling, and retry logic.
azure-mgmt-*
SSH / SFTP
Paramiko 3.x
Pure-Python SSH2 implementation. Handles RSA key auth, remote exec, SFTP uploads, and exit-status checking without spawning subprocesses.
No subprocess
Concurrency Model
Threads + asyncio bridge
Blocking SDK calls run in daemon threads. run_in_executor() bridges the queue read back to the async event loop — keeps the event loop unblocked.
No Celery
State
Flat file (state.json)
Appropriate for the access pattern: one write on provision, one delete on destroy, no concurrent writers. Persists across server restarts with no migration overhead.
No DB needed
CLI
Typer + Rich
Type-annotated CLI commands with zero boilerplate. Rich provides coloured tables, panels, and progress spinners — consistent with the dashboard terminal output.
8 commands
Frontend
Vanilla JS
No build step, no dependencies. Served directly as a static file by FastAPI. WebSocket, Fetch API, and DOM manipulation cover everything needed.
Single HTML file
Azure Auth
Service Principal
Client credentials flow via DefaultAzureCredential. Credentials are loaded from environment variables only — not stored in code or state files.
12-factor
Design decisions
🧵
Why threads rather than async for the provider code?
The Azure SDK and Paramiko are synchronous and blocking — wrapping them in asyncio.to_thread would work mechanically but obscures the blocking nature of the calls. Explicit daemon threads make the concurrency model clear: one thread per job, tied to the operation lifetime. The WebSocket handler re-enters the async world only for the queue read, via run_in_executor().
📄
Why a flat file instead of SQLite or a database?
There is exactly one write (provision) and one delete (destroy) on state, with no concurrent writers. A database would add a service dependency, connection pooling, and migration scripts with no benefit. The file is written atomically and read fresh on each request. On server restart, the process reads the file and restores its in-memory state correctly.
📡
How does real-time log streaming work?
The provider pushes log lines into an in-process queue as it executes. The WebSocket handler drains that queue on the async event loop via run_in_executor(), which blocks a thread-pool thread rather than the event loop. A heartbeat ping is sent every 15 seconds to keep the connection alive. Clients that connect late receive the full log history replayed immediately on join.
🛡️
How is the public demo protected against abuse?
Four independent layers: a per-IP token-bucket rate limiter (4 writes/min, 60 reads/min) implemented as ASGI middleware; a global concurrency cap (1 active job at a time); an active VM budget (maximum 3 provisioned VMs, counter decrements on destroy); and a mandatory server-side auto-destroy timer that fires after 20 minutes and cannot be cancelled from the browser.
🔌
What is the provider abstraction and why does it exist?
An abstract BaseProvider interface defines provision(), deploy(), destroy(), and get_status(). AzureProvider implements it. The API layer calls a factory function and never imports cloud SDK modules directly. Adding a second cloud provider requires one new file — the API, CLI, and dashboard have no changes.
Security model
🪣
Token Bucket Rate Limiter
Per-IP sliding window. Write operations are capped separately from reads. Runs as ASGI middleware — evaluated before any route handler.
4 writes / min · 60 reads / min
🚦
Global Concurrency Cap
Only one mutating job runs at a time, globally. Tracked with a threading lock and counter. Released automatically when the background thread exits.
1 concurrent operation
💰
Active VM Budget
Provision is rejected if the active VM count reaches the limit. The counter decrements on destroy — it tracks live VMs, not a lifetime total.
3 active VMs maximum
Mandatory Auto-Destroy
A server-side timer starts after every successful provision. After 20 minutes it runs the full destroy sequence — identical to the manual path — regardless of browser state.
20-minute hard limit
📋
Audit Log
Every mutating operation is written to an append-only audit log with timestamp, source IP, operation type, and parameters. Never exposed via the API.
Append-only · server-side only
🔑
Credential Isolation
Azure service principal credentials are loaded from environment variables only. They are never written to state files, logs, or returned by any API endpoint.
DefaultAzureCredential · env vars
Scaling path — current prototype vs production
State
state.json
→ PostgreSQL
Job Queue
In-process queue
→ Celery + Redis
Workers
Daemon threads
→ Worker pool / K8s Jobs
Cloud
Azure only
→ AWS / GCP providers
Auth
Open (demo)
→ OAuth2 / JWT
View source on GitHub
github.com/unknown788/cloud-cli-tool
About this project
Built as a portfolio project demonstrating backend engineering, cloud infrastructure automation, real-time systems, and security design — typical scope of a backend or platform engineering role.