Skip to content

Self-hosting

Two unusual properties drive the choice: the app hosts PowerShell in-process with warm, long-lived runspace pools (so it must stay warm and is memory-heavy), and it signs into Exchange with a Managed Identity (so it wants Azure compute - MI only works there).

Recommendation: Azure Container Apps, with App Service as the simpler alternative.

Option Verdict Why
Azure Container Apps Recommended Container-native; native Managed Identity; ingress idle timeout configurable to 30 min (vs App Service’s fixed ~240s). Set minReplicas ≥ 1 so the warm pools survive.
Azure App Service (Linux container) Simpler alternative Native MI; Always On keeps pools warm; flat predictable price; matches the config below. Hard ~240s request ceiling.
AKS Only if already on Kubernetes Full control, heaviest ops.
Azure Functions / serverless Not a fit The 230s ceiling + cold-start/stateless model fights the warm-pool design.

Reliability essentials (any platform): keep it warm (minReplicas ≥ 1 / Always On); 2-4 GiB memory headroom (PowerShell + EOM + pools); ≥ 2 instances for HA - stateless between requests, so no session affinity; wire /readyz (real pool probe) as readiness and /healthz as liveness; Managed Identity for Exchange Online + a certificate (from Key Vault) for Purview/IPPS - IPPS has no MI path; put Front Door / APIM in front for WAF/TLS/CORS.

Production config:

appsettings.Production.json
{
"ExchangeOnline": { "Organization": "<tenant>.onmicrosoft.com",
"ConnectionMode": "SystemAssignedManagedIdentity", "PoolSize": 3 },
"AzureAd": { "Instance": "https://login.microsoftonline.com/",
"TenantId": "<tenant-guid>", "ClientId": "<app-id>",
"Audience": "api://<app-id>" },
"License": { "Key": "<from Key Vault>" }
}

Assign Exchange.ManageAsApp + a directory role to the host’s managed identity. No client secrets in production.

Indicative cost (Container Apps, US list/PAYG): ~$35-75/mo for a lean single-replica pilot, ~$110-185/mo for production HA (2 replicas + Front Door) - a low-volume-but-stays-warm profile, so you pay for 1-2 small always-on replicas, not per request. The Dockerfile, the Microsoft.App Bicep, identity wiring, the deploy flow, and the full cost breakdown are in the Azure Container Apps reference.