Introduction
Azure Portal is Microsoft Azure's unified web interface for managing all your cloud resources, from virtual machines to serverless apps. In 2026, with the rise of AI and hybrid workloads, mastering the Portal is essential for intermediate developers. Why this tutorial? Unlike pure CLI approaches, the Portal provides intuitive visualizations of costs, monitoring, and topologies, while integrating seamlessly with scripts for automation.
We'll deploy a Web App on App Service: a scalable PaaS service that handles SSL, scaling, and CI/CD automatically. You'll learn to create a Resource Group, an App Service Plan, deploy Node.js code via ZIP, configure a custom domain, and monitor. Each step combines Portal (for discovery) and code (CLI/PowerShell/ARM) for a professional hybrid approach.
Key benefits: 50% faster setup than pure CLI, visual error detection, reusable template exports. By the end, you'll have a live, scalable app ready for 100 instances with real-time logs. Ready to scale your apps to production? (128 words)
Prerequisites
- Active Azure account (create a free one at portal.azure.com)
- Azure CLI 2.65+ installed (
az --versionto check) - PowerShell 7+ with Az module (
Install-Module -Name Az) - Node.js 20+ and a simple project (e.g., Express 'Hello World')
- Editor like VS Code with Azure extension
- Test budget: ~$1 for 1 hour of runtime
Connect to Azure CLI
# az login opens the browser for authentication
az login
# Check subscriptions
az account list --output table
# Set default subscription (replace with your ID)
SUBSCRIPTION_ID="your-subscription-id-here"
az account set --subscription $SUBSCRIPTION_ID
# Check available regions (e.g., francecentral)
az account list-locations --query "[].{Name:name, DisplayName:displayName}" --output table | grep -i franceThis script starts an Azure CLI session via OAuth browser-based auth, lists subscriptions, and selects one. Run it before any operations to avoid 'authentication required' errors. Pitfall: With multiple accounts, always set the subscription to target resources correctly.
Step 1: Create a Resource Group via Portal and CLI
In Azure Portal, go to Resource groups > Create. Choose a unique name like 'rg-webapp-demo', region 'France Central' for low EU latency, and tags {'Environment':'Prod', 'Project':'Demo'}. Click Review + Create.
Analogy: A Resource Group is like a project folder: it scopes costs, RBAC, and lifecycle. The Portal lets you visualize the resource map instantly.
Replicate it in CLI for CI/CD automation. After Portal creation, verify: az group list --output table.
Create Resource Group in CLI
#!/bin/bash
RG_NAME="rg-webapp-demo"
LOCATION="francecentral"
# Create RG with tags
az group create \
--name $RG_NAME \
--location $LOCATION \
--tags Environment=Prod Project=Demo Owner=your-email@domain.com
# Verify
az group show --name $RG_NAME --query "{name:name, location:location, tags:tags}" --output tableThis bash script creates an RG with tags for governance (costs, audits). Tags are mandatory in production for compliance. Pitfall: Names must be globally unique (no reuse), and location affects latency/pricing – francecentral optimizes for EU.
PowerShell Equivalent for Resource Group
# Connect in PowerShell
Connect-AzAccount
$rgName = "rg-webapp-demo"
$location = "francecentral"
# Create RG
New-AzResourceGroup -Name $rgName -Location $location -Tag @{Environment="Prod"; Project="Demo"; Owner="your-email@domain.com"}
# Verify
Get-AzResourceGroup -Name $rgName | Format-List Name,Location,TagsPowerShell offers fine-grained control for Windows admins. Connect-AzAccount is interactive like az login. Advantage: Native Azure DevOps pipelines. Avoid: Forgetting Update-AzConfig -DefaultSubscriptionForLogin your-sub-id for persistent sessions.
Step 2: Provision App Service Plan
App Service Plan defines the SKU (pricing/size). In Portal: Create a resource > Web App > Basics > App Service Plan > Create new (S1 Standard for auto-scaling). Analogy: It's the 'engine' under your app, billed by the hour.
Enable Always On for zero cold starts. Portal shows real-time cost estimator – crucial for budgets.
Automate next.
Create App Service Plan in CLI
#!/bin/bash
RG_NAME="rg-webapp-demo"
PLAN_NAME="asp-webapp-demo"
LOCATION="francecentral"
# Create Standard S1 plan (2 CPU, 3.5GB, horizontal scaling)
az appservice plan create \
--name $PLAN_NAME \
--resource-group $RG_NAME \
--location $LOCATION \
--sku S1 \
--is-linux
# Verify
az appservice plan list --resource-group $RG_NAME --query "[?name=='$PLAN_NAME'].{name:name, sku:sku, workerSize:workerSize}" --output tableS1 SKU supports deployment slots and auto-scale. --is-linux for Node.js/PHP/Python. Pitfall: Free/Shared don't scale – upgrade early. Check az appservice plan show for provisioning status (5-10 min).
Create Web App in CLI
#!/bin/bash
RG_NAME="rg-webapp-demo"
PLAN_NAME="asp-webapp-demo"
WEBAPP_NAME="webapp-demo-$(date +%s)" # Unique name
RUNTIME="NODE|20-lts"
# Create Web App
az webapp create \
--resource-group $RG_NAME \
--plan $PLAN_NAME \
--name $WEBAPP_NAME \
--runtime "$RUNTIME" \
--deployment-local-git
# Enable HTTPS only
az webapp update --resource-group $RG_NAME --name $WEBAPP_NAME --https-only true
# Test URL
az webapp show --resource-group $RG_NAME --name $WEBAPP_NAME --query defaultHostName --output tsvCreates the app linked to the plan, with Node 20 runtime. deployment-local-git enables Git deploy. HTTPS-only secures production. Pitfall: Web App names must be globally unique – add timestamp. Test the generated URL in a browser.
Step 3: Deploy Code and Configure
Prepare a simple Node project: npm init -y; npm i express; echo 'app.get("/",(req,res)=>res.send("Hello Azure!")); app.listen(8080);' > app.js; node app.js.
In Portal: Deployment Center > Source: Local Git or ZIP Deploy. For production, integrate GitHub Actions.
Scaling: Portal > Scale out (up to 100 instances). Enable Application Insights for traces.
Automate the deploy.
Deploy via ZIP in CLI
#!/bin/bash
RG_NAME="rg-webapp-demo"
WEBAPP_NAME="webapp-demo-your-unique-name"
ZIP_FILE="./dist.zip" # Create it: zip -r dist.zip . -x "node_modules/*"
# Deploy ZIP (full override)
az webapp deployment source config-zip \
--resource-group $RG_NAME \
--name $WEBAPP_NAME \
--src $ZIP_FILE
# Restart and logs
az webapp restart --resource-group $RG_NAME --name $WEBAPP_NAME
az webapp log tail --resource-group $RG_NAME --name $WEBAPP_NAMEZIP deploy is ideal for CI/CD (GitHub Actions/Azure Pipelines). Tail logs in real-time for debugging. Pitfall: Forget process.env.PORT in Node (Azure enforces 80/443). Restart triggers hot-reload.
ARM JSON Template Exported from Portal
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"webAppName": {
"type": "string",
"defaultValue": "webapp-demo"
}
},
"resources": [
{
"type": "Microsoft.Web/serverfarms",
"apiVersion": "2022-03-01",
"name": "asp-webapp-demo",
"location": "francecentral",
"sku": {
"name": "S1",
"tier": "Standard"
}
},
{
"type": "Microsoft.Web/sites",
"apiVersion": "2022-03-01",
"name": "[parameters('webAppName')]
"location": "francecentral",
"properties": {
"serverFarmId": "[resourceId('Microsoft.Web/serverfarms', 'asp-webapp-demo')]",
"siteConfig": {
"appSettings": [
{
"name": "WEBSITE_NODE_DEFAULT_VERSION",
"value": "~20"
}
]
}
}
}
]
}Export from Portal (Resource > Export template) for IaC. Deploy with az deployment group create --resource-group rg-webapp-demo --template-file webapp-arm.json. Parameters enable reusability. Pitfall: Outdated apiVersion causes failures – use 2022+.
Best Practices
- Systematic tags: Tag all resources (Env, CostCenter, Owner) for Azure Cost Management billing.
- Minimal RBAC: Assign Contributor to RG, not global Owner (Portal > Access control IAM).
- Enabled monitoring: Application Insights + Alerts for CPU>80%, 5xx failures.
- Staging slots: Create 'staging' slot for zero-downtime deploys (Portal > Deployment slots).
- Advanced diagnostics: Enable Failed Request Tracing and Detailed Error for production.
Common Errors to Avoid
- Non-unique name: Web App names are global – add UUID or timestamp, or get 'NameUnavailable'.
- Region mismatch: RG and resources must match location, or deployment fails.
- Cold starts: Forget Always On on Free/Basic SKU – app sleeps after 20min idle.
- No log tail: Debug without
log tailor Portal Logs – don't assume early success.
Next Steps
Dive deeper with Azure Bicep (ARM successor) or Terraform. Integrate Azure Front Door for CDN/global routing.
Resources:
Check out our Learni Azure DevOps training for advanced CI/CD and AZ-204 certification.