The previous lesson ended with two loose ends, one facing inwards and one facing outwards. Inwards: the Barcelona and Palma offices are still outside the Azure network, the legacy check-in system lives on a server in the basement in Barcelona, and Marta Ríos cannot administer the platform from home without exposing something to the internet. Outwards: a customer buying a ticket from South America crosses the Atlantic on every request to West Europe, and they can tell.
Both problems are about connectivity, but in opposite directions. The first is solved with hybrid connectivity: encrypted tunnels or dedicated circuits that join the on-premises network with the Azure virtual network, so that 10.100.0.0/16 and 10.20.0.0/16 behave as a single network. The second is solved with global delivery: services that put the content and the connection termination close to the customer, wherever they are.
This lesson closes module 2 with both, and with a warning that appears on every Azure bill and that almost nobody anticipates: the cost of data transfer out.
Important cost warning: this is the module's most expensive lesson. A VPN gateway is billed by the hour from the moment it is created, even with not a single tunnel connected, and it takes between 20 and 45 minutes to deploy. ExpressRoute involves a contract with a carrier and is not something you test in a lab. Front Door and CDN cost money per data served. Deploy only what you are going to use and delete it the same day.
Contents
- Contoso Airlines' hybrid scenario
- Point-to-site VPN: administering from home
- Site-to-site VPN: connecting Barcelona and Palma
- Deploying the gateway with Azure CLI
- ExpressRoute: when it justifies its price
- Azure Virtual WAN, at a conceptual level
- Global delivery: the customer buying from South America
- Azure Front Door, Azure CDN and Traffic Manager compared
- Public DNS with Azure DNS
- The cost of data transfer out
- The module's final architecture and cleanup
- Common Mistakes and Tips
- Exercises
- Conclusion
- Contoso Airlines' hybrid scenario
What stays on premises after the migration, and why:
| System | Where it lives | Why it is still there | What it needs from Azure |
|---|---|---|---|
| Legacy check-in | A server in Barcelona | Integrated with the accounting system and with a certified card reader | Reading the sales from db-reservas every night |
| Ground staff workstations | Barcelona and Palma | They are physical workstations | Reaching the operations dashboard and the Azure Files share |
| On-premises directory | Barcelona | Identity synchronization still pending (module 4) | Employee authentication |
| Marta Ríos's administration | A laptop, from home or while travelling | She is a person, not a system | Reaching snet-gestion and Bastion without opening ports |
Remember the addressing plan settled in the previous lesson, because hybrid connectivity is where that plan proves its worth: Barcelona is 10.100.0.0/16, Palma 10.101.0.0/16, the Azure hub 10.10.0.0/16 and production 10.20.0.0/16. Nothing overlaps, so everything can be routed.
The three connectivity options, compared at a glance:
| Option | Where it travels | Bandwidth | Latency | Cost | Time to set up |
|---|---|---|---|---|---|
| Point-to-site VPN | The internet, encrypted | The client's | Variable | Very low | Minutes |
| Site-to-site VPN | The internet, encrypted (IPsec) | Up to ~1–10 Gbps depending on SKU | Variable, depends on the internet | Low | Hours |
| ExpressRoute | The carrier's private circuit | 50 Mbps – 100 Gbps | Predictable, with an SLA | High | Weeks or months |
- Point-to-site VPN: administering from home
A point-to-site VPN (P2S) connects one individual machine to the virtual network. Marta Ríos installs a client on her laptop, authenticates, and her laptop receives an address from a dedicated range, with access to the network's private resources.
Its components:
| Component | What it is |
|---|---|
| VPN gateway | The Azure resource that terminates the tunnels; it lives in GatewaySubnet |
| Client address pool | The range from which IPs are assigned to the laptops; it cannot overlap with anything |
| Authentication | Certificates, Microsoft Entra ID or RADIUS |
| Protocol | OpenVPN (recommended, cross-platform), IKEv2 or SSTP |
Contoso reserves 172.16.30.0/24 for the P2S clients: a range that collides neither with Azure (10.x) nor with the offices.
NET_GROUP="rg-contoso-red-pro"
GATEWAY="vgw-contoso-pro"
# Configure point-to-site on an already existing gateway,
# with Microsoft Entra ID authentication and the OpenVPN protocol.
az network vnet-gateway update \
--resource-group "${NET_GROUP}" \
--name "${GATEWAY}" \
--address-prefixes 172.16.30.0/24 \
--client-protocol OpenVPN \
--vpn-auth-type AAD \
--aad-tenant "https://login.microsoftonline.com/<tenant-id>" \
--aad-audience "<azure-vpn-client-application-id>" \
--aad-issuer "https://sts.windows.net/<tenant-id>/" \
--output none
# Download the configuration profile for the client.
az network vnet-gateway vpn-client generate \
--resource-group "${NET_GROUP}" \
--name "${GATEWAY}" \
--authentication-method EAPTLS \
--output tsvAuthentication with Microsoft Entra ID is preferable to certificates: it integrates with the multi-factor authentication you configured in lesson 01-03, it lets you revoke a person's access by disabling their account, and it does not force you to distribute and renew certificates one by one.
With P2S connected, Marta reaches snet-gestion and Bastion with no public IP exposed at all, which is exactly the promise we left pending in the previous lesson.
- Site-to-site VPN: connecting Barcelona and Palma
A site-to-site VPN (S2S) connects an entire network with the virtual network through an IPsec/IKE tunnel between the office's VPN device and the Azure gateway. Nothing is installed on the machines: every workstation in the office reaches Azure transparently.
graph LR
subgraph BCN["Barcelona office · 10.100.0.0/16"]
FW1["VPN device<br/>public IP 198.51.100.10"]
FAC["Legacy check-in"]
end
subgraph PMI["Palma office · 10.101.0.0/16"]
FW2["VPN device<br/>public IP 198.51.100.42"]
end
FW1 -->|"IPsec tunnel"| GW["vgw-contoso-pro<br/>GatewaySubnet 10.10.255.0/27"]
FW2 -->|"IPsec tunnel"| GW
MAR["Marta Ríos<br/>laptop · P2S 172.16.30.x"] -->|"OpenVPN"| GW
GW --> HUB["vnet-contoso-hub-pro<br/>10.10.0.0/16"]
HUB -->|peering with<br/>gateway transit| PRO["vnet-contoso-pro<br/>10.20.0.0/16"]
The four components that have to be created, and in this order:
| Component | Azure resource | What it represents |
|---|---|---|
| Gateway subnet | GatewaySubnet (/27 or larger) |
The space where the gateway lives |
| Public IP | ip-vgw-contoso-pro, Standard static |
The Azure end that the office points at |
| Virtual network gateway | vgw-contoso-pro |
The tunnel terminator on the Azure side |
| Local network gateway | lng-oficina-barcelona |
The representation in Azure of the office's network: its public IP and its ranges |
The fourth is the one whose name confuses people most: a local network gateway is not a device, but an Azure object that describes the other end. If the office changes its public IP or adds a subnet, this object has to be updated.
Gateway SKUs
| SKU | Aggregate bandwidth | S2S tunnels | P2S connections | Zone redundancy | Use |
|---|---|---|---|---|---|
Basic |
100 Mbps | 10 | 128 | No | Legacy, avoid |
VpnGw1 |
650 Mbps | 30 | 250 | No | Small production |
VpnGw2 |
1 Gbps | 30 | 500 | No | Medium production |
VpnGw1AZ – VpnGw5AZ |
650 Mbps – 10 Gbps | 30 | 500–10,000 | Yes | Production with a zone requirement |
Contoso chooses VpnGw1AZ: the traffic between the offices and Azure is modest (overnight synchronizations and access to a dashboard), but company policy requires zone redundancy on critical components, and the gateway is a single point of failure for both offices.
- Deploying the gateway with Azure CLI
#!/usr/bin/env bash
set -euo pipefail
NET_GROUP="rg-contoso-red-pro"
REGION="westeurope"
VNET_HUB="vnet-contoso-hub-pro"
GATEWAY="vgw-contoso-pro"
GW_IP="ip-vgw-contoso-pro"
TAGS=(entorno=produccion proyecto=contoso-reservas centro-coste=CC-1042
[email protected] criticidad=alta)
# 1. GatewaySubnet in the hub (the name is mandatory and literal).
az network vnet subnet create \
--resource-group "${NET_GROUP}" --vnet-name "${VNET_HUB}" \
--name GatewaySubnet --address-prefixes 10.10.255.0/27 --output none
# 2. Standard, zone-redundant public IP.
az network public-ip create \
--resource-group "${NET_GROUP}" --name "${GW_IP}" \
--sku Standard --allocation-method Static --zone 1 2 3 \
--tags "${TAGS[@]}" --output none
# 3. Virtual network gateway. CAREFUL: it takes between 20 and 45 minutes
# and it starts billing by the hour from the moment it is created.
az network vnet-gateway create \
--resource-group "${NET_GROUP}" --name "${GATEWAY}" \
--location "${REGION}" \
--vnet "${VNET_HUB}" \
--public-ip-addresses "${GW_IP}" \
--gateway-type Vpn --vpn-type RouteBased \
--sku VpnGw1AZ \
--tags "${TAGS[@]}" \
--no-wait
# 4. Representation of the Barcelona network (the other end's IP and ranges).
az network local-gateway create \
--resource-group "${NET_GROUP}" --name lng-oficina-barcelona \
--gateway-ip-address 198.51.100.10 \
--local-address-prefixes 10.100.0.0/16 \
--tags "${TAGS[@]}" --output none
# 5. The same for Palma.
az network local-gateway create \
--resource-group "${NET_GROUP}" --name lng-oficina-palma \
--gateway-ip-address 198.51.100.42 \
--local-address-prefixes 10.101.0.0/16 \
--tags "${TAGS[@]}" --output none
# 6. IPsec connections (the shared key must come from Key Vault, never from the script).
az network vpn-connection create \
--resource-group "${NET_GROUP}" --name con-barcelona-pro \
--vnet-gateway1 "${GATEWAY}" --local-gateway2 lng-oficina-barcelona \
--shared-key "${BARCELONA_KEY}" --output none
az network vpn-connection create \
--resource-group "${NET_GROUP}" --name con-palma-pro \
--vnet-gateway1 "${GATEWAY}" --local-gateway2 lng-oficina-palma \
--shared-key "${PALMA_KEY}" --output noneNotes on this script, because each one corresponds to a real mistake that is made often:
--vpn-type RouteBased: it is the modern type, mandatory for P2S, for multiple tunnels and for most scenarios.PolicyBasedis only used with old devices that support nothing else, and it has severe limits.--no-wait: the deployment takes up to 45 minutes. Without this option, your terminal sits blocked.- The shared key (
--shared-key) is a genuine secret: it must come out of Azure Key Vault (lesson 04-03), never out of a variable written into the repository. - The
198.51.100.xaddresses come from a range reserved for documentation (RFC 5737): in a real deployment you put the public IPs of the offices' firewalls. - The office device has to be configured as well, with the equivalent parameters. Azure generates configuration templates for the most common vendors.
Checking the state of the tunnels:
az network vpn-connection show \
--resource-group rg-contoso-red-pro --name con-barcelona-pro \
--query "{Connection:name, Status:connectionStatus, IngressBytes:ingressBytesTransferred, EgressBytes:egressBytesTransferred}" \
--output tableThe status should be Connected. If it shows Connecting indefinitely, 90% of the time it is a mismatch of IPsec parameters between the two ends or a different shared key.
And remember the economic detail from the previous lesson: thanks to --allow-gateway-transit on the hub and --use-remote-gateways on the spokes, this single gateway provides connectivity to vnet-contoso-pro and to vnet-contoso-dev. That is the saving that justifies the hub-and-spoke pattern.
- ExpressRoute: when it justifies its price
ExpressRoute is a private connection between your network and Azure through a telecommunications carrier. The traffic never goes over the internet at any point.
| Aspect | Site-to-site VPN | ExpressRoute |
|---|---|---|
| Path | The public internet, IPsec encrypted | The carrier's private circuit |
| Bandwidth | Up to ~10 Gbps (high SKUs), shared with the internet | 50 Mbps to 100 Gbps dedicated |
| Latency | Variable: it depends on the state of the internet | Predictable and stable |
| Availability SLA | 99.9% (99.95% with active-active) | 99.95%, with an end-to-end SLA from the carrier |
| Encryption | IPsec mandatory | Not encrypted by default (a private circuit); it can be added |
| Cost | Tens of euros a month plus data transfer out | Hundreds or thousands a month, plus the carrier's link |
| Setup | Hours | Weeks or months |
| Access to PaaS services by private IP | Requires Private Link | Microsoft peering or Private Link |
Peering models
| Peering | What it gives access to | Typical use |
|---|---|---|
| Private (Azure private peering) | Resources with a private IP in your virtual networks | The main one: VMs, databases and private endpoints |
| Microsoft (Microsoft peering) | Microsoft's public services (Microsoft 365, PaaS with a public endpoint) | Large Microsoft 365 rollouts and access to PaaS without the internet |
And two connection models: ExpressRoute Direct (you connect directly to Microsoft's network with 10 or 100 Gbps ports, for enormous volumes) and the usual one through a connectivity provider.
Does Contoso need it?
Marta Ríos evaluates it and decides that no, not yet:
| Criterion | Contoso's situation | Verdict |
|---|---|---|
| Data volume | Overnight sales synchronization: a few GB | The VPN is more than enough |
| Latency sensitivity | Overnight batch processes, not interactive | Not critical |
| Regulatory requirement not to cross the internet | There is none: IPsec satisfies the audit | Not compelled |
| Cost | Several thousand euros a year, plus the link | Not justified |
ExpressRoute is justified when any of these applies: regularly moving terabytes, migrating large databases, virtual desktops for hundreds of employees, interactive systems that cannot tolerate latency variability, or a compliance requirement that explicitly forbids crossing the internet. Contoso will reassess if it migrates the whole check-in system. A common pattern, incidentally, is to have ExpressRoute as the primary and a site-to-site VPN as backup, which is cheap and covers a circuit outage.
- Azure Virtual WAN, at a conceptual level
When the number of offices and virtual networks grows, building and maintaining gateways, peerings and route tables by hand becomes a full-time job. Azure Virtual WAN is the managed service that automates that work.
| Aspect | Hand-built hub-and-spoke | Azure Virtual WAN |
|---|---|---|
| Hub | A VNet you create and manage yourself | A managed virtual hub provided by Azure |
| Office connections | One by one, with gateways and local objects | Automated, with SD-WAN device integration |
| Routing between spokes | Requires an appliance or manual routes | Built-in transit between spokes |
| Multiple regions | Global peering and routes by hand | Hubs in several regions, interconnected on their own |
| When it pays off | Few networks and few offices | Many offices, several regions, VPN + ExpressRoute + P2S at once |
For Contoso, with two offices and three virtual networks, the manual hub-and-spoke from lesson 02-05 is simpler and cheaper. Virtual WAN would come into play if the airline grew to twenty branches or if it operated in several regions. It is enough that you know it exists and what problem it solves.
- Global delivery: the customer buying from South America
Let us switch direction. A passenger in Buenos Aires goes to www.contosoairlines.example to buy a flight. Everything is in West Europe. Let us see what that costs her.
The round-trip latency between Buenos Aires and Amsterdam is around 220 ms. A typical page load chains several operations in series:
| Operation | Round trips | Approximate time |
|---|---|---|
| DNS resolution | 1 | 220 ms (or less with caching) |
| TCP handshake | 1 | 220 ms |
| TLS negotiation | 1–2 | 220–440 ms |
| First HTTP request | 1 | 220 ms |
| Static resources (images, CSS, JS) | Several, in parallel | 220 ms minimum per batch |
Result: more than a second before anything appears, not counting the server's processing time. And in a ticket-sales funnel, every second of waiting translates into abandonment.
What global delivery fixes, and it is more than people assume:
- TLS termination at the edge: the TCP and TLS handshakes happen against a nearby point of presence (São Paulo, for example, about 30 ms away), not against West Europe. Only the already-established request travels to Europe, over persistent connections that are already open and optimized inside Microsoft's network.
- Static content caching: images, style sheets and scripts are served from the point of presence, without crossing the Atlantic.
- Optimal routing: traffic enters Microsoft's backbone at the closest point and travels over it, not over the public internet.
- Failover: if one region's origin does not respond, the global service sends the traffic to another.
- Azure Front Door, Azure CDN and Traffic Manager compared
| Aspect | Azure Front Door | Azure CDN | Traffic Manager |
|---|---|---|---|
| Layer | 7 (HTTP/S) | 7 (HTTP/S) | DNS |
| What it does with the traffic | Terminates it and forwards it from the edge | Serves and caches static content | It only answers the DNS query with a destination |
| TLS termination at the edge | Yes | Yes | No (it never sees the traffic) |
| Caching | Yes | Yes, it is its specialty | No |
| Routing by path or header | Yes | Limited | No |
| WAF | Yes (lesson 04-04) | Depending on the tier | No |
| Failover | Fast, using its own probes | — | Using probes, but limited by the DNS TTL |
| Protocols | HTTP/S only | HTTP/S only | Any |
| Failover speed | Seconds | — | Minutes (it depends on the client's DNS cache) |
Selection criteria, in the form of a decision:
- A website or web API accessible from several regions of the world, that you want to accelerate and protect → Azure Front Door. It is today's default answer, because it includes what used to be done with CDN plus Traffic Manager.
- Distribution of very large static files only (video, downloads, images) → Azure CDN, if its pricing model works out better for that profile.
- A service that does not speak HTTP (the legacy engine's protocol, a mail server, a database) or failover between regions without touching the application → Traffic Manager, because it works at the DNS level and is protocol-agnostic.
A warning about Traffic Manager that saves grief: since it only answers DNS queries, failover takes as long as the record takes to expire in the caches of clients and intermediate resolvers. With a 60-second TTL, real failover can take several minutes. It is not the mechanism for failing over in seconds.
Front Door for Contoso Bookings
#!/usr/bin/env bash
set -euo pipefail
GROUP="rg-contoso-reservas-pro"
PROFILE="fd-contoso-global"
ENDPOINT="contoso-reservas"
TAGS=(entorno=produccion proyecto=contoso-reservas centro-coste=CC-1042
[email protected] criticidad=alta)
# 1. Front Door Standard profile (Premium adds managed WAF and Private Link to the origin).
az afd profile create \
--resource-group "${GROUP}" --profile-name "${PROFILE}" \
--sku Standard_AzureFrontDoor --tags "${TAGS[@]}" --output none
# 2. Endpoint: the global name through which traffic enters.
az afd endpoint create \
--resource-group "${GROUP}" --profile-name "${PROFILE}" \
--endpoint-name "${ENDPOINT}" --enabled-state Enabled --output none
# 3. Origin group with its health probe and load balancing.
az afd origin-group create \
--resource-group "${GROUP}" --profile-name "${PROFILE}" \
--origin-group-name og-reservas \
--probe-request-type GET --probe-protocol Https \
--probe-path "/salud" --probe-interval-in-seconds 30 \
--sample-size 4 --successful-samples-required 3 \
--additional-latency-in-milliseconds 50 --output none
# 4. Primary origin: the West Europe application.
az afd origin create \
--resource-group "${GROUP}" --profile-name "${PROFILE}" \
--origin-group-name og-reservas --origin-name origen-westeurope \
--host-name app-contoso-reservas-pro.azurewebsites.net \
--origin-host-header app-contoso-reservas-pro.azurewebsites.net \
--http-port 80 --https-port 443 --priority 1 --weight 1000 \
--enabled-state Enabled --output none
# 5. Route with static content caching and redirection to HTTPS.
az afd route create \
--resource-group "${GROUP}" --profile-name "${PROFILE}" \
--endpoint-name "${ENDPOINT}" --route-name ruta-principal \
--origin-group og-reservas --supported-protocols Http Https \
--patterns-to-match "/*" --forwarding-protocol HttpsOnly \
--https-redirect Enabled --link-to-default-domain Enabled \
--enable-caching true --query-string-caching-behavior IgnoreQueryString \
--output none
echo "Front Door published at: https://$(az afd endpoint show -g "${GROUP}" --profile-name "${PROFILE}" --endpoint-name "${ENDPOINT}" --query hostName -o tsv)"The options that deserve an explanation:
| Option | Effect |
|---|---|
--probe-path "/salud" |
Reuses the health endpoint you created in App Service (lesson 02-03) |
--sample-size and --successful-samples-required |
How many probes are evaluated and how many must succeed for the origin to be considered healthy |
--additional-latency-in-milliseconds 50 |
The latency margin within which several origins are considered equally close |
--priority 1 |
The origin's priority: a second origin with priority 2 would be the backup |
--https-redirect Enabled |
Any HTTP request is redirected to HTTPS at the edge |
--query-string-caching-behavior |
Whether the query string forms part of the cache key. Careful: IgnoreQueryString is dangerous on flight search results pages |
That last point deserves a serious warning: do not cache personalized responses or availability results. If Front Door caches /vuelos?origen=BCN&destino=EZE ignoring the query string, one customer can see the flights another customer searched for. Contoso caches only /estatico/* (images, CSS, JS) and lets everything dynamic through uncached.
If Contoso later built a second deployment in North Europe, it would be enough to add it as an origin with priority 2, and Front Door would fail over on its own only when the primary's probe failed. Remember, however, the conscious decision from module 1: there is no multi-region active-active setup, on cost grounds.
- Public DNS with Azure DNS
Azure DNS hosts your domains' public DNS zones on Microsoft's infrastructure, with global anycast and no servers to maintain. It does not register domains (that is what App Service Domains or your usual registrar are for), it only hosts them.
NET_GROUP="rg-contoso-red-pro"
ZONE="contosoairlines.example"
# 1. Create the public zone.
az network dns zone create -g "${NET_GROUP}" -n "${ZONE}" --output none
# 2. See the name servers that have to be declared at the registrar.
az network dns zone show -g "${NET_GROUP}" -n "${ZONE}" \
--query nameServers --output tsv
# 3. CNAME record for www pointing at Front Door.
FD_HOST=$(az afd endpoint show -g rg-contoso-reservas-pro \
--profile-name fd-contoso-global --endpoint-name contoso-reservas \
--query hostName -o tsv)
az network dns record-set cname set-record \
-g "${NET_GROUP}" -z "${ZONE}" -n www \
--cname "${FD_HOST}" --ttl 3600 --output none
# 4. The domain verification record that Front Door requires.
az network dns record-set txt add-record \
-g "${NET_GROUP}" -z "${ZONE}" -n "_dnsauth.www" \
--value "<front-door-validation-token>" --output none
# 5. Alias at the zone apex (contosoairlines.example, without www).
# A CNAME is not allowed at the apex: an Azure alias record is used instead.
az network dns record-set a create \
-g "${NET_GROUP}" -z "${ZONE}" -n "@" \
--target-resource "$(az afd endpoint show -g rg-contoso-reservas-pro \
--profile-name fd-contoso-global --endpoint-name contoso-reservas --query id -o tsv)" \
--output noneStep 5 solves a classic problem: the DNS standard does not allow a CNAME at the zone apex (the domain without www). Azure DNS's alias records solve it by pointing directly at an Azure resource, and they also update themselves if the resource's IP changes.
About the TTL: a high value (3600 s) reduces queries and cost; a low one (60 s) lets you change destination quickly. Common practice: drop the TTL to 60 seconds a few days before a planned migration and raise it again afterwards.
- The cost of data transfer out
Here is the surprise everyone gets with their first Azure bill, and that is why it closes the module's technical content.
Azure's general rule:
- Data in (ingress) is free. Uploading to Azure costs nothing.
- Data out (egress) is billed. Everything that leaves for the internet, and a good part of what moves between regions or between zones.
| Type of traffic | Is it billed? |
|---|---|
| From the internet into Azure (inbound) | No |
| From Azure to the internet (outbound) | Yes, per GB, with the first 100 GB a month free |
| Between resources in the same region and the same VNet | No |
| Between availability zones in the same region | Yes, in some scenarios |
| Between regions (for example, West Europe → North Europe) | Yes |
| Through a virtual network peering | Yes, in both directions |
| Through a VPN or ExpressRoute | Yes (with ExpressRoute it depends on the plan) |
| Served from the Front Door or CDN cache | Yes, at a different and normally lower rate per geographic zone |
Where this hurts in Contoso's case:
- Boarding passes downloaded by passengers. Every PDF that goes out to the internet is billed. A million downloads of 300 KB is 300 GB a month: small, but real, and it grows with the business.
- The overnight synchronization with Barcelona's check-in system over the VPN: it leaves Azure, so it is billed.
- GZRS replication of the boarding pass account to North Europe: geo-replication has its own transfer cost.
- Traffic between the spokes and the hub over peering: it looks "internal", but it is billed per GB in both directions.
Four ways to reduce it, all applicable right away:
- Cache at the edge: every response served from the Front Door cache is one less egress from the region (and a faster one).
- Compress: turning on compression in Front Door and in App Service reduces the bytes served.
- Do not move data between regions without a reason: process where the data is.
- Watch the breakdown of the bill: in module 8 you will see how Cost Management breaks spend down by service and by meter type, and how Nuria Peña, the finance lead, reviews it every month with the team. Data transfer out is usually among the top three lines and almost nobody had budgeted for it.
- The module's final architecture and cleanup
graph TB
CLI["Global customers<br/>(Buenos Aires, Madrid, Barcelona…)"] --> DNS["Azure DNS<br/>contosoairlines.example"]
DNS --> FD["Azure Front Door<br/>fd-contoso-global<br/>TLS at the edge + caching"]
FD --> WEBAPP["App Service<br/>app-contoso-reservas-pro"]
WEBAPP --> API["App Service<br/>app-contoso-api-disponibilidad-pro"]
API --> SQL["db-reservas<br/>(module 3)"]
WEBAPP --> BLOB["sttarjetascontosopro<br/>Private Link"]
subgraph AZ["Azure · West Europe"]
FD
WEBAPP
API
SQL
BLOB
VMS["vm-motor-disponibilidad-01<br/>snet-gestion"]
GW["vgw-contoso-pro<br/>VpnGw1AZ"]
end
OFI["Barcelona and Palma offices<br/>10.100.0.0/16 · 10.101.0.0/16"] -->|site-to-site VPN| GW
MARTA["Marta Ríos from home"] -->|point-to-site VPN| GW
GW --> VMS
Cleanup, starting with the most expensive:
NET_GROUP="rg-contoso-red-pro"
# 1. Connections and gateway: FIRST OF ALL, it is what bills the most per hour.
az network vpn-connection delete -g "${NET_GROUP}" -n con-barcelona-pro
az network vpn-connection delete -g "${NET_GROUP}" -n con-palma-pro
az network vnet-gateway delete -g "${NET_GROUP}" -n vgw-contoso-pro
az network public-ip delete -g "${NET_GROUP}" -n ip-vgw-contoso-pro
# 2. Front Door.
az afd profile delete -g rg-contoso-reservas-pro --profile-name fd-contoso-global --yes
# 3. DNS zone (if it was a test one).
az network dns zone delete -g "${NET_GROUP}" -n contosoairlines.example --yes
# 4. Final check for residual spend across the whole subscription.
az network vnet-gateway list --query "[].{Gateway:name, SKU:sku.name, Group:resourceGroup}" -o table
az network public-ip list --query "[?ipConfiguration==null].{IP:name, Group:resourceGroup}" -o table
az disk list --query "[?diskState=='Unattached'].{Disk:name, GB:diskSizeGb}" -o tableDeleting the gateway takes several minutes. Do it before you leave, not afterwards: a VpnGw1AZ forgotten for a month costs more than the rest of this module's lab put together.
Common Mistakes and Tips
- Creating the VPN gateway "just to try it" and forgetting it. It bills by the hour from minute one, connected or not. It is the most expensive cost mistake in the whole module.
- Overlapping the P2S address pool with the Azure network or with the office network. The client connects, but reaches nothing. Reserve an exclusive range (
172.16.30.0/24at Contoso). - Using
PolicyBasedwhenRouteBasedis needed. It supports neither P2S nor multiple tunnels, and the whole gateway has to be rebuilt. - Getting the ranges wrong in the local network gateway. If one office subnet is missing, that part of the network never reaches Azure and the symptom is "it half works".
- Writing the VPN shared key into the script. It goes to Key Vault (04-03). A repository with an IPsec key in it is a security incident.
- Assuming that ExpressRoute encrypts the traffic. It is a private circuit, not encrypted by default. If the requirement is end-to-end encryption, it has to be added.
- Expecting Traffic Manager to fail over in seconds. It works through DNS: the clients' cache is in charge. For fast failover, Front Door.
- Caching dynamic or personalized content in Front Door. A cached flight search result can be shown to another customer. Cache only static content.
- Forgetting the alias record at the zone apex. You cannot use a CNAME at
@; Azure DNS alias records are the solution. - Not budgeting for data transfer out. It is one of the first lines on the bill and the one fewest people anticipate. Tie it to the budget you created in lesson 01-03.
- Tip: deploy the gateway with
--no-waitand use the 30-45 minutes to configure everything else. And give it a specific budget alert. - Tip: document the table of ranges (Azure, offices, P2S) in the repository. During a connectivity incident at three in the morning, that document is worth more than any pretty diagram.
Exercises
Exercise 1: choosing the right connectivity
For each Contoso Airlines need, state which solution you would use and justify it:
- Marta Ríos administers the VMs from a hotel during a conference.
- The 30 workstations in the Palma office access the operations dashboard and the Azure Files share every day.
- Contoso decides to migrate the whole check-in system and move 8 TB of history over a weekend, and afterwards to maintain continuous low-latency synchronization.
- The airline opens branches at 18 airports, each with its own local network, and wants to connect them all without managing 18 gateways.
Exercise 2: global delivery
The passenger in Buenos Aires takes more than a second to see the flight search page.
- Which global delivery service would you choose, and why over the other two?
- Which content would you cache and which would you not? Justify the risk of getting it wrong.
- Write the health probe configuration for the origin group and explain each parameter.
- If Contoso added a deployment in North Europe, how would you configure it so that it was a backup and not active-active?
Exercise 3: auditing the data transfer bill
Nuria Peña, the finance lead, asks why the networking section of the bill has gone up 40% this quarter.
- List at least four sources of data transfer out in Contoso's current architecture.
- For each one, propose a concrete measure to reduce it.
- Which traffic in the architecture is free and worth explaining to Nuria so that she does not chase it?
Solutions
Solution 1:
| Case | Solution | Justification |
|---|---|---|
| 1. Marta from a hotel | Point-to-site VPN with Entra ID authentication | It is an individual machine and a changing location; there is no VPN device to configure and the existing MFA is reused |
| 2. The 30 workstations in Palma | Site-to-site VPN | It connects the whole network transparently; and accessing Azure Files over SMB (port 445) practically requires private connectivity |
| 3. Migrating 8 TB plus low-latency synchronization | ExpressRoute | Volume and predictable latency: moving 8 TB over a VPN across the internet is slow and unstable. It is planned weeks in advance and the VPN is kept as backup |
| 4. 18 branches | Azure Virtual WAN | It manages the connections of many sites centrally, with built-in transit, instead of maintaining gateways, local objects and routes by hand |
Solution 2:
-
Azure Front Door. Over Azure CDN, because it is not only about caching static content: we also want to terminate TLS at the edge and accelerate dynamic content over Microsoft's backbone, plus the option of adding WAF (04-04). Over Traffic Manager, because that one only answers DNS queries and never touches the traffic: it would do nothing to reduce the connection-establishment latency, which is the bulk of the problem.
-
Cacheable and non-cacheable:
| Content | Cache? | Reason |
|---|---|---|
/estatico/* (CSS, JS, images, logos) |
Yes, with a long TTL | Identical for everyone and it changes rarely |
/vuelos?origen=…&destino=… |
No | It depends on real-time availability: caching it would sell seats that do not exist |
/mi-reserva/* |
No | Personal content; a caching mistake would show one passenger's data to another |
| The boarding pass PDF | No | It is served with a temporary SAS (lesson 02-04); caching it would defeat the protection |
The risk of getting it wrong is twofold and serious: showing one passenger's personal data to another (a privacy and GDPR incident) and selling seats that no longer exist.
- The health probe:
az afd origin-group create \
--resource-group rg-contoso-reservas-pro --profile-name fd-contoso-global \
--origin-group-name og-reservas \
--probe-request-type GET \ # the probe's method: GET, not HEAD, to exercise the application
--probe-protocol Https \ # it is checked over the same channel the customer uses
--probe-path "/salud" \ # the health endpoint created in lesson 02-03
--probe-interval-in-seconds 30 \ # frequency: a balance between reaction and load
--sample-size 4 \ # the last 4 samples are evaluated
--successful-samples-required 3 \ # with 3 good out of 4, the origin is considered healthy
--additional-latency-in-milliseconds 50- By adding the second origin to the same group with priority 2:
az afd origin create -g rg-contoso-reservas-pro --profile-name fd-contoso-global \
--origin-group-name og-reservas --origin-name origen-northeurope \
--host-name app-contoso-reservas-nor.azurewebsites.net \
--priority 2 --weight 1000 --enabled-state EnabledFront Door sends all the traffic to priority 1 while it is healthy and only fails over to 2 when the probes fail. With the same priority on both, the traffic would be split (active-active), which is precisely what Contoso ruled out on cost grounds in module 1.
Solution 3:
1 and 2. Sources of egress and measures:
| Source of egress | Reduction measure |
|---|---|
| Boarding pass PDFs downloaded by passengers | Compress the PDF; serve it through Front Door (per-zone rate, and lower); avoid duplicate re-sends by email |
| Overnight synchronization with Barcelona's check-in system over the VPN | Send only deltas instead of the full dump; compress the transfer |
GZRS replication of sttarjetascontosopro to North Europe |
Review whether every container needs geo-redundancy; regenerable data can go in a separate ZRS account |
| Traffic between hub and spokes over peering | Put the components that talk to each other the most in the same spoke |
| Website and API responses to internet clients | Turn on compression and caching in Front Door; reduce the size of the JSON responses |
- Free traffic, worth explaining so that nobody chases ghosts: all inbound data into Azure (boarding pass uploads, incoming requests, the initial migration load), and traffic within the same region and the same virtual network, such as the traffic from
snet-webtosnet-appor from the application to its database. In other words: processing data where it lives costs no transfer; moving it out does.
Conclusion
With this lesson you close module 2 and Contoso Airlines' platform is standing. You have solved the hybrid scenario: a point-to-site VPN with Microsoft Entra ID authentication so that Marta Ríos can administer from anywhere without exposing a single port, and a site-to-site VPN for Barcelona and Palma, with its four components — GatewaySubnet, a public IP, a virtual network gateway and a local network gateway — the choice of the VpnGw1AZ SKU with zone redundancy, and a single gateway serving every spoke of the hub-and-spoke. You know what ExpressRoute brings compared with a VPN — bandwidth, predictable latency, an SLA and not crossing the internet — its peering models, and why Contoso decides not to contract it yet. You know Azure Virtual WAN and the problem it solves when sites multiply. And in the other direction you have built global delivery: you understand where the thousand-plus milliseconds a passenger in Buenos Aires suffers come from, you have compared Front Door, CDN and Traffic Manager with clear selection criteria, you have published Contoso Bookings behind Front Door with a health probe, HTTPS redirection and caching of static content only, you have hosted the domain in Azure DNS with its alias record at the apex, and you know how to anticipate the data transfer out cost that will show up on the bill in module 8.
Recapping the whole module: you started by deploying virtual machines for the legacy availability engine, with their disks, their sizes and the difference between stopped and deallocated. Then you gave compute scaling and high availability with scale sets, automatic and scheduled rules, availability zones and a Load Balancer with health probes. You published Contoso Bookings and the Availability API on App Service, with plans, deployment slots and swap with warm-up so that new versions go live without interrupting sales. You stored the boarding passes in Azure Storage, settling the pending redundancy question — LRS in development, GZRS in production — and automating their lifecycle towards Cool and Archive. You built the virtual network with its subnets, NSGs, private DNS zones and private endpoints that took the database and the storage off the internet. And today you have joined that network with the offices and with the world.
You have compute, storage and networking. What is missing is what gives it all meaning: the data. The db-reservas database has been showing up in every lesson as a piece that exists but that you have neither designed nor deployed, and the decisions still to be made are not small ones: a relational database or a document store? Azure SQL Database, MySQL, PostgreSQL or Cosmos DB? What does each option cost, how does it scale and how does it recover if somebody deletes a table on a Friday afternoon?
In module 3, Azure Databases, we start exactly there: with the criteria for choosing the right data service — relational versus NoSQL, managed versus installed on a VM, cost versus performance — and then we will genuinely deploy Contoso Airlines' bookings database on Azure SQL Database, with its service tier, its backup, its point-in-time restore and its private connection to the network you have just built. See you there.
Azure Course
Module 1: Introduction to Azure
- What Is Azure?
- Service Models, Regions and Availability Zones
- Creating and Setting Up Your Azure Account
- A Tour of the Azure Portal
- Azure Resource Manager: Subscriptions, Resource Groups and Tags
- Azure CLI, PowerShell and Cloud Shell
Module 2: Core Azure Services
- Azure Virtual Machines
- Compute Scaling and High Availability
- Azure App Service
- Azure Storage: Blobs, Files, Queues and Tables
- Azure Networking: Virtual Networks, Subnets and NSGs
- Hybrid Connectivity and Global Delivery
Module 3: Azure Databases
- Choosing the Right Data Service
- Azure SQL Database
- Azure Cosmos DB
- Azure Database for MySQL
- Azure Database for PostgreSQL
- Data Analytics: Data Lake, Data Factory and Synapse
Module 4: Security in Azure
- Microsoft Entra ID and Identity Management
- RBAC and Managed Identities
- Azure Key Vault
- DDoS Protection and Web Application Firewall
- Microsoft Defender for Cloud
- Governance and Compliance with Azure Policy
Module 5: Azure DevOps
- Introduction to Azure DevOps
- Azure Repos
- Azure Pipelines: Continuous Integration
- Continuous Deployment with Environments and Approvals
- Azure Artifacts
- Infrastructure as Code with Bicep
Module 6: Advanced Azure Services
- Containers in Azure: Container Registry and Container Apps
- Azure Kubernetes Service (AKS)
- Azure Functions
- Azure Logic Apps
- Messaging and Events: Service Bus, Event Grid and Event Hubs
- Azure AI Services
Module 7: Monitoring and Management
- Azure Monitor: Metrics, Alerts and Dashboards
- Log Analytics and KQL Queries
- Application Insights
- Azure Automation and Runbooks
- Backup and Disaster Recovery
Module 8: Cost Management and Optimization
- Pricing Calculator and Cost Estimation
- Azure Cost Management: Analysis, Budgets and Alerts
- Reservations, Savings Plans and Azure Hybrid Benefit
- Azure Advisor
- Optimization Strategies and FinOps Culture
