Azure Front Door - CDN Plan for Staging/Prod

Background

Game spin requests show ~732ms end-to-end in the browser network tab, while pack-alpha server-side processing is only 148ms. The remaining ~584ms is pure network overhead (client distance to germanywestcentral). Azure Front Door terminates TLS at the nearest edge PoP and routes traffic over Azure's backbone, reducing the client-to-server round trip significantly.

Expected result after Front Door: ~200ms (down from ~732ms), without any server-side changes.

To reach 100ms, Front Door must be combined with server-side RGS optimizations (see separate doc).


Current Staging State (no CDN)

Browser --(internet, full RTT)--> Container Apps (germanywestcentral)
AppFQDN
pack-alpha-stagingpack-alpha-staging.kindfield-50ee1da3.germanywestcentral.azurecontainerapps.io
feg-rgs-stagingfeg-rgs-staging.kindfield-50ee1da3.germanywestcentral.azurecontainerapps.io
feg-cms-stagingfeg-cms-staging.kindfield-50ee1da3.germanywestcentral.azurecontainerapps.io
feg-external-stagingfeg-external-staging.kindfield-50ee1da3.germanywestcentral.azurecontainerapps.io

No CDN or Front Door profile exists in the subscription today.


Scope: What Gets Front Door

AppFront Door?Reason
pack-alphaYESGame frontend calls this directly - biggest latency impact
feg-externalYESOperator integrations call this from outside Azure
feg-cmsNOInternal admin users only, scale-to-zero, cold starts acceptable
feg-rgsNOCalled by pack-alpha over VNet (4-5ms internal hop) - CDN would add latency

Changes Required

1. New Azure Front Door Standard Profile

One profile per environment (staging, prod) in the same resource group. Front Door Standard supports: custom domains, managed TLS, dynamic forwarding, WAF (optional).

  • No caching configured - game API responses are dynamic, caching is not the goal
  • Edge termination is the sole benefit: TLS handshake and TCP at PoP, Azure backbone to origin

2. Endpoint + Origin Group + Route (per app, x2)

For each of pack-alpha and feg-external:

  • Endpoint: gets a .z01.azurefd.net hostname
  • Origin group: points to the Container App FQDN as origin, with health probe on /games/health (pack-alpha) or /health (external)
  • Route: forward all traffic (/*) to origin, caching disabled

3. Migrate Custom Domains from Container App to Front Door

Custom domains currently bound directly to Container Apps must move to Front Door.

DNS change (per domain):

# Before
yourdomain.com  CNAME  pack-alpha-staging.kindfield-50ee1da3.germanywestcentral.azurecontainerapps.io

# After
yourdomain.com  CNAME  <pack-alpha-endpoint>.z01.azurefd.net

Steps:

  1. Add custom domain to Front Door (Front Door issues managed TLS cert automatically)
  2. Update DNS CNAME to point to Front Door endpoint
  3. Remove custom domain binding from Container App

4. Lock Down Container Apps to Front Door Only

Without this, the .azurecontainerapps.io URL remains publicly accessible, bypassing Front Door.

Pulumi change - add IP restriction to ingress:

ingress: {
  external: true,
  targetPort: ...,
  transport: 'http',
  allowInsecure: false,
  ipSecurityRestrictions: [
    {
      name: 'allow-front-door',
      ipAddressRange: 'AzureFrontDoor.Backend', // Azure service tag
      action: 'Allow',
    },
  ],
},

Additionally, validate the X-Azure-FDID header in the app to ensure requests came through your specific Front Door instance (not any other customer's Front Door). The FDID is available from the Front Door profile resource after creation.


Cost Estimate (Front Door Standard)

ComponentPriceMonthly (staging)
Base fee$35/month per profile$35
Custom domains$5/month each~$10 (pack-alpha + external)
Requests~$0.009 per 10KLow for staging
Data transfer out~$0.08-0.17/GBLow for staging
Estimated total~$45-55/month

Excluding CMS from Front Door does NOT reduce cost - the $35 base fee is per profile, not per origin. The only saving is the $5/month custom domain fee if CMS had a domain on Front Door.


Pulumi Implementation Notes

Resources to add in feg_slot_be/infra/src/index.ts (gated by a new enableFrontDoor config):

  • cdn.Profile (SKU: Standard_AzureFrontDoor)
  • cdn.AFDEndpoint x2 (pack-alpha, external)
  • cdn.OriginGroup x2
  • cdn.AFDOrigin x2 (pointing to Container App FQDNs)
  • cdn.Route x2
  • Update ContainerApp ingress with ipSecurityRestrictions after Front Door is provisioned

The feg_common/infra stack (RGS, CMS, external) would need the external app's Front Door resources too - or the Front Door profile can live in feg_slot_be/infra and origins from feg_common are added as additional origins in the same profile.


Architecture After Front Door

Browser --(~10ms)--> Front Door PoP --(~15ms Azure backbone)--> pack-alpha (148ms) --> back
Total: ~200ms

The VNet, Redis private endpoint, and inter-service communication (pack-alpha -> RGS) are completely unaffected by this change.

Built with LogoFlowershow