A one-command Azure deployment of the LearningSteps API and a PostgreSQL database.
For the 5-day walkthrough built on top of this deployment, see handbook.md.
This deployment is intentionally minimal and unsecured. The VM is publicly reachable, the database accepts connections from any IP, credentials are stored in plaintext, and there is no traffic inspection or monitoring. It is a starting point — not a production setup.
- Ubuntu VM (Standard_D2s_v3) running the FastAPI application on port 8000
- Azure PostgreSQL Flexible Server (B1ms) as the database
- A virtual network with one subnet and a basic network security group
Install the following before running the script:
| Tool | Install |
|---|---|
| Python 3.8+ | python.org — on Windows use python, on macOS/Linux use python3 |
| Terraform ≥ 1.5 | developer.hashicorp.com/terraform/install |
| Azure CLI | learn.microsoft.com/en-us/cli/azure/install-azure-cli |
Azure CLI ssh extension |
az extension add --name ssh — required for the handbook's az ssh / az ssh config commands (Entra ID VM login) |
| Azure subscription | Your account needs Contributor or Owner role on the subscription |
python3 deploy.pyOn Windows:
python deploy.py
The script will:
- Log you in to Azure if needed (opens a browser)
- Generate an SSH key pair in the project folder
- Ask for a resource prefix and Azure region (IMPORTANT - Make sure your prefix is unique and includes your name, otherwise the deployment will fail due to naming conflicts)
- Ask for a PostgreSQL admin password
- Run
terraform apply— takes about 7–8 minutes - Run a smoke test against the deployed API
To skip the interactive prompts:
python3 deploy.py --password YourPassword1 --prefix learningstepsbob --location westeuropeOnce deployed, the script prints the API URL and SSH command.
When not in use, deallocate the VM to avoid compute charges:
az vm deallocate --resource-group rg-<prefix> --name vm-<prefix>Start it again:
az vm start --resource-group rg-<prefix> --name vm-<prefix>Stop the database:
az postgres flexible-server stop --resource-group rg-<prefix> --name psql-<prefix>Start it again:
az postgres flexible-server start --resource-group rg-<prefix> --name psql-<prefix>Note: Azure automatically restarts a stopped PostgreSQL Flexible Server after 7 days.
To destroy everything permanently:
terraform destroyterraform applyfails with a Sentinel-related resource "already exists" (seen onazurerm_sentinel_log_analytics_workspace_onboarding.main,azurerm_sentinel_alert_rule_scheduled.waf_attack, andazurerm_sentinel_automation_rule.block_attacker) — happens if youterraform destroyand then redeploy with the same prefix shortly after: these Sentinel objects use fixed names (not random IDs) and can take a few minutes to clear on Azure's side even though the Log Analytics workspace itself is gone.terraform applyfails on the first one it hits — expect to repeat this for each one in turn (apply, hit next conflict, import, re-apply) rather than all three appearing in one error. Fix each by importing it into the new state, then re-running apply:Avoiding it entirely: use a different prefix, or wait a few minutes after destroy before reusing the same one.az account show --query id -o tsv # get your subscription ID terraform import azurerm_sentinel_log_analytics_workspace_onboarding.main \ "/subscriptions/<subscription-id>/resourceGroups/rg-<prefix>/providers/Microsoft.OperationalInsights/workspaces/law-<prefix>/providers/Microsoft.SecurityInsights/onboardingStates/default" terraform import azurerm_sentinel_alert_rule_scheduled.waf_attack \ "/subscriptions/<subscription-id>/resourceGroups/rg-<prefix>/providers/Microsoft.OperationalInsights/workspaces/law-<prefix>/providers/Microsoft.SecurityInsights/alertRules/waf-attack-scheduled" terraform import azurerm_sentinel_automation_rule.block_attacker \ "/subscriptions/<subscription-id>/resourceGroups/rg-<prefix>/providers/Microsoft.OperationalInsights/workspaces/law-<prefix>/providers/Microsoft.SecurityInsights/automationRules/a1b2c3d4-0000-0000-0000-000000000001" terraform apply
The SSH key is generated in the project folder during deployment:
ssh azureuser@<vm-ip> -i .learningsteps_key