Skip to content

Domains and HTTPS

Custom domains require a multi-pass Pulumi deploy because of Azure binding/certificate ordering and CDN validation.

  1. Deploy without relying on custom hosts being fully validated yet (first pulumi up may fail on custom domain resources until DNS exists — that is expected).
  2. Entra Postgres principal for the app is created automatically (Database); only intervene if you set auto_create_db_principal=False.
  3. Retrieve deploy SSH key from {name}_deploy_ssh_key_url and configure the Git remote; use {name}_deploy_url for webhooks.
  4. Point CDN hostname at cdn_cname (and TXT validation if exported).
  5. Point website hostnames (CNAME / A / AAAA) and create asuid TXT records from {name}_site_domain_verification_id.
  6. Re-deploy with custom hosts in place.
  7. Re-deploy again so managed certificates can attach to existing hostname bindings.
  8. Manually enable HTTPS on the custom CDN domain in the Azure portal (Azure API limitation: azure-rest-api-specs#17498).
  9. Configure DKIM/SPF/etc. for Communication Services custom domains in the Azure portal.

CDN custom domain

Stack exports:

  • cdn_cname — CNAME target for your CDN hostname
  • When cdn_host is set: cdn_validation_record_txt_name / cdn_validation_record_txt_value

Create the DNS records, then redeploy so the custom domain resource can succeed.

App Service custom domains

For each hostname (including aliases on HostDefinition):

asuid.example.com.      TXT  "<{name}_site_domain_verification_id>"
asuid.www.example.com.  TXT  "<same verification id>"

Also create DNS records as appropriate for your layout:

  • CNAME → {name}_site_domain_cname
  • A → each address in {name}_site_inbound_ipv4 (list; current + possible inbound IPs)
  • AAAA → {name}_site_inbound_ipv6

Use the inbound IPs (not outbound) when apex/A or AAAA records are required.

Hostname bindings and certificate attachments are created one host at a time on each App Service (Azure returns HTTP 409 if two site updates overlap). Certificates need an existing binding, so a second deploy after bindings exist is required for HTTPS on the web app.