🚀 “The toy wombat website needs a CDN!”
“Other teams don’t need it.”
Me: “No problem – I’ll make it optional.”
🎯 The Mission
We're launching a website for the new toy wombat — and to handle traffic spikes, we’ll add a Content Delivery Network (CDN).
But... only if needed. Other teams can skip it.
So let’s build this smart and reusable:
- 📦 Use modules for the App Service and CDN
- ✅ Make the CDN optional
- 🌍 Output the right hostname depending on what’s deployed
🧱 Step 1: Create the App Module
In VS Code:
- Create a folder called
modules
- Inside it, create a file:
app.bicep
Paste in this logic:
@description('The Azure region into which the resources should be deployed.')
param location string
@description('The name of the App Service app.')
param appServiceAppName string
@description('The name of the App Service plan.')
param appServicePlanName string
@description('The name of the App Service plan SKU.')
param appServicePlanSkuName string
resource appServicePlan 'Microsoft.Web/serverfarms@2024-04-01' = {
name: appServicePlanName
location: location
sku: {
name: appServicePlanSkuName
}
}
resource appServiceApp 'Microsoft.Web/sites@2024-04-01' = {
name: appServiceAppName
location: location
properties: {
serverFarmId: appServicePlan.id
httpsOnly: true
}
}
@description('The default host name of the App Service app.')
output appServiceAppHostName string = appServiceApp.properties.defaultHostName
✅ What this does:
It spins up a basic App Service Plan + App. Outputs the app’s host name.
💻 Step 2: Set Up Your Main Template
Create a file called main.bicep
.
Add these parameters:
param location string = 'westus3'
param appServiceAppName string = 'toy-${uniqueString(resourceGroup().id)}'
param appServicePlanSkuName string = 'F1'
param deployCdn bool = true
Add a variable:
var appServicePlanName = 'toy-product-launch-plan'
🧩 Step 3: Use the App Module
Still in main.bicep
, insert this module:
module app 'modules/app.bicep' = {
name: 'toy-launch-app'
params: {
appServiceAppName: appServiceAppName
appServicePlanName: appServicePlanName
appServicePlanSkuName: appServicePlanSkuName
location: location
}
}
🌐 Step 4: Create the CDN Module
Create a new file inside modules
called cdn.bicep
.
Paste this code:
param originHostName string
param profileName string = 'cdn-${uniqueString(resourceGroup().id)}'
param endpointName string = 'endpoint-${uniqueString(resourceGroup().id)}'
param httpsOnly bool
var originName = 'my-origin'
resource cdnProfile 'Microsoft.Cdn/profiles@2024-09-01' = {
name: profileName
location: 'global'
sku: {
name: 'Standard_Microsoft'
}
}
resource endpoint 'Microsoft.Cdn/profiles/endpoints@2024-09-01' = {
parent: cdnProfile
name: endpointName
location: 'global'
properties: {
originHostHeader: originHostName
isHttpAllowed: !httpsOnly
isHttpsAllowed: true
queryStringCachingBehavior: 'IgnoreQueryString'
contentTypesToCompress: [
'text/plain'
'text/html'
'text/css'
'application/x-javascript'
'text/javascript'
]
isCompressionEnabled: true
origins: [
{
name: originName
properties: {
hostName: originHostName
}
}
]
}
}
output endpointHostName string = endpoint.properties.hostName
✅ What this does:
It creates a CDN profile + endpoint, pointing to your app. Outputs the CDN host name.
🧩 Step 5: Use the CDN Module (With a Condition)
Back in main.bicep
, add the CDN module:
module cdn 'modules/cdn.bicep' = if (deployCdn) {
name: 'toy-launch-cdn'
params: {
httpsOnly: true
originHostName: app.outputs.appServiceAppHostName
}
}
💡 This only runs if deployCdn
is true.
📦 Step 6: Output the Right Hostname
Now, let’s give the user the correct URL based on whether CDN is on:
output websiteHostName string = deployCdn ? cdn.outputs.endpointHostName : app.outputs.appServiceAppHostName
✅ Final main.bicep
Snapshot
param location string = 'westus3'
param appServiceAppName string = 'toy-${uniqueString(resourceGroup().id)}'
param appServicePlanSkuName string = 'F1'
param deployCdn bool = true
var appServicePlanName = 'toy-product-launch-plan'
module app 'modules/app.bicep' = {
name: 'toy-launch-app'
params: {
appServiceAppName: appServiceAppName
appServicePlanName: appServicePlanName
appServicePlanSkuName: appServicePlanSkuName
location: location
}
}
module cdn 'modules/cdn.bicep' = if (deployCdn) {
name: 'toy-launch-cdn'
params: {
httpsOnly: true
originHostName: app.outputs.appServiceAppHostName
}
}
output websiteHostName string = deployCdn ? cdn.outputs.endpointHostName : app.outputs.appServiceAppHostName
🚀 Deploy It!
Make sure you're ready:
az bicep install && az bicep upgrade
az login
az group create --name BicepRG --location westus3
Then deploy:
az deployment group create \
--resource-group BicepRG \
--name main \
--template-file main.bicep
🔎 Check the Deployment
In the Azure Portal:
- Go to Resource Groups > BicepRG
- Go to Deployments > main
- Expand it to see both modules:
toy-launch-app
and (if enabled)toy-launch-cdn
- Check Outputs:
- If CDN is enabled, you’ll get the CDN host name
- Otherwise, you get the App Service host name
Try both in the browser (add https://
in front)!
📌 CDN might take a minute to activate — if it doesn't load instantly, just wait and retry.
🧠 In Short
Feature | What We Did |
---|---|
App Module | Reusable App Service plan + app deployment |
CDN Module | Created a globally distributed cache layer |
Conditional Module | Made CDN deploy only when needed |
Smart Output | Automatically return the correct public URL |
Wanna follow my Azure learning journey?
Stick around — I’m sharing it all, wins and stumbles included 😄
You can find me on LinkedIn — drop me a message and just say hi 👋
Would love to hear what you're working on or learning!