Azure Container Apps
The serverless profile: scale-to-zero containers. Deliberately not Azure Functions — AS2 needs long uploads and same-connection synchronous receipts, which FaaS models handle poorly. The same as2d image runs here unchanged; a ready-made bicep template deploys the whole environment (Container Apps environment, Log Analytics, ingress, secrets).
Deploy
az group create -n as2d-rg -l westeurope
az deployment group create -g as2d-rg -f aca.bicep \
-p image=<registry>/as2d:<tag> \
-p postgresUrl='postgres://...?sslmode=require' \
-p partnershipsToml=@partnerships.toml \
-p licenseContent=@license.lic \
-p keyFiles='{"files":[
{"name":"me.key.pem","value":"-----BEGIN PRIVATE KEY-----..."},
{"name":"me.cer.pem","value":"-----BEGIN CERTIFICATE-----..."},
{"name":"partner.cer.pem","value":"-----BEGIN CERTIFICATE-----..."}]}'
TLS is terminated by the Container Apps ingress; the output of the deployment is your partner-facing HTTPS URL.
Choices baked into the template
- State must be PostgreSQL — instances are ephemeral at scale-to-zero. Azure Database for PostgreSQL, or a managed free tier for minimal cost.
- Payloads and keys default to Postgres + secret-mounted PEM files.
For Azure-native storage pass
extraConfigwith[storage.blob]/[storage.key_vault]; the app has a system-assigned managed identity — grant it Key Vault Secrets User and the keystore authenticates with no credentials in config. - Scale-to-zero caveat: the retry worker lives inside as2d, so queued
retries and asynchronous MDNs only progress while a replica is awake.
Set
minReplicas=1if partners depend on async receipts;minReplicas=0is fine for synchronous-only traffic (cold start of the static binary is comfortably inside partner HTTP timeouts). - License renewal: Container Apps secret volumes do not reliably
update in place — after renewing, re-run the deployment (or restart the
revision) with the new
licenseContent. The 14-day grace window exists precisely so this is never an emergency.
Cost
Consumption plan with minReplicas=0 plus a free-tier Postgres is
approximately $0 at idle — you pay per request-second of compute.
See Cost profiles.