Troubleshooting Azure Front Door: Custom Domain Stuck in Pending
Azure Front Door has changed significantly since I last used it. The version I was familiar with is now labeled “Classic,” and the new version introduces a different setup experience. My goal was simple: deploy an Azure Front Door in front of a storage account configured with static web hosting, enable HTTPS using Front Door’s managed SSL certificate, and configure a custom domain, www.foobar.com, as the vanity URL for my website. Everything seemed to work smoothly at first—until I hit a frustrating roadblock. Despite following the prescribed steps for DNS validation, the custom domain remained stuck in a “Pending” state, with no clear resolution. Based on research I’ve done, this appears to be a recurring issue, leaving many users in the same frustrating predicament.
Provisioning Azure Front Door with Terraform
Creating a Front Door Profile
A Front Door profile is the container for all the components that make up your Front Door deployment. It includes the configuration for routing, security, and performance settings. The following Terraform code creates a new Front Door profile:
resource "azurerm_cdn_frontdoor_profile" "main" {
name = "af-${var.application_name}-${var.environment_name}"
resource_group_name = azurerm_resource_group.main.name
sku_name = "Standard_AzureFrontDoor"
}
Defining a Front Door Endpoint
A Front Door endpoint is the globally accessible entry point for your application traffic. All incoming requests are routed through this endpoint before being forwarded to your backend services.
resource "azurerm_cdn_frontdoor_endpoint" "main" {
name = "fd-${var.application_name}-${var.environment_name}"
cdn_frontdoor_profile_id = azurerm_cdn_frontdoor_profile.main.id
}
Configuring an Origin Group
An origin group is a collection of backend services that handle requests from Front Door. It supports load balancing and health probes to determine the availability of origins.
resource "azurerm_cdn_frontdoor_origin_group" "main" {
name = "og-${var.application_name}-${var.environment_name}"
cdn_frontdoor_profile_id = azurerm_cdn_frontdoor_profile.main.id
session_affinity_enabled = false
load_balancing {
additional_latency_in_milliseconds = 0
sample_size = 4
successful_samples_required = 3
}
health_probe {
interval_in_seconds = 100
path = "/index.html"
protocol = "Http"
request_type = "HEAD"
}
}
Because my site is hosted using Azure Storage Account Web Hosting, I ensured the health probe targeted index.html.
Setting Up an Origin
An origin represents a specific backend resource, such as an Azure Storage account or an App Service, that serves content to users through Front Door.
resource "azurerm_cdn_frontdoor_origin" "main" {
name = "origin-storage-${var.application_name}-${var.environment_name}"
cdn_frontdoor_origin_group_id = azurerm_cdn_frontdoor_origin_group.main.id
enabled = true
certificate_name_check_enabled = false
host_name = azurerm_storage_account.main.primary_web_host
origin_host_header = azurerm_storage_account.main.primary_web_host
http_port = 80
https_port = 443
priority = 1
weight = 1000
}
Setting Up the Custom Domain
Defining a Custom Domain
A custom domain allows you to use a user-friendly domain name instead of the default Front Door endpoint. The TLS settings enable HTTPS using Front Door’s managed certificate.
resource "azurerm_cdn_frontdoor_custom_domain" "main" {
count = var.custom_domain != null ? 1 : 0
name = "fd-customdomain-${var.application_name}-${var.environment_name}"
cdn_frontdoor_profile_id = azurerm_cdn_frontdoor_profile.main.id
host_name = var.custom_domain
tls {
certificate_type = "ManagedCertificate"
minimum_tls_version = "TLS12"
}
}
Creating a Route
A route defines how requests to your Front Door endpoint are processed and forwarded to your backend origin. It ensures HTTPS redirection and applies the routing rules necessary for the custom domain.
resource "azurerm_cdn_frontdoor_route" "main" {
name = "route-${var.application_name}-${var.environment_name}"
cdn_frontdoor_endpoint_id = azurerm_cdn_frontdoor_endpoint.main.id
cdn_frontdoor_origin_group_id = azurerm_cdn_frontdoor_origin_group.main.id
cdn_frontdoor_origin_ids = [azurerm_cdn_frontdoor_origin.main.id]
enabled = true
forwarding_protocol = "HttpsOnly"
https_redirect_enabled = true
patterns_to_match = ["/*"]
supported_protocols = ["Http", "Https"]
cdn_frontdoor_custom_domain_ids = var.custom_domain != null ? [azurerm_cdn_frontdoor_custom_domain.main[0].id] : []
link_to_default_domain = true
}
Associating the Custom Domain
Finally, the custom domain must be explicitly linked to the Front Door route to complete the setup.
resource "azurerm_cdn_frontdoor_custom_domain_association" "main" {
count = var.custom_domain != null ? 1 : 0
cdn_frontdoor_custom_domain_id = azurerm_cdn_frontdoor_custom_domain.main[0].id
cdn_frontdoor_route_ids = [azurerm_cdn_frontdoor_route.main.id]
}
Notice how the route references the custom domain (if I specified one).
The Sticking Point: Custom Domain Stuck in “Pending”
Despite completing the DNS steps as instructed, the custom domain remained in a “Pending” state. Checking the Front Door portal, I saw the validation process hanging indefinitely.
Go check the custom domain’s status: PENDING.
Go look at the Front Door Manager:
Attempting to manually validate the domain or retry the process yielded no change. I even tried disassociating the domain from the route and re-adding it, but the status remained stuck. Worse yet, I found no option to force a refresh or restart the validation process. At this stage, I was essentially locked out of making further progress.
The DNS record is there:
I cant’ delete the custom domain unless I disassociate the route but even I do that and attempt to manually perform this operation I am stuck in “Pending” for the custom domain.
From discussions with others experiencing the same issue, this appears to be a widespread problem. Many users report being stuck in this exact situation with no clear solution, indicating an underlying issue with the Azure Front Door validation process.
Others Experience
Here is a recent thread about it on the technical support forums. This issue also seems to crop up with others trying to implement Front Door custom domains via Infrastructure-as-Code. Here is a GitHub issue in Bicep and another one that was closed (maybe because it was considered a duplicate?). John Downs explains the structure quite well:
First, you need to add the custom domains to the AFD profile. You can do this easily in Bicep. Here’s an example that shows how to do this, assuming you’re using a Front Door-managed TLS cert.
Second, you need to associate each of those custom domains with the route. It’s up to you whether you do this at AFD creation or if you update the route afterwards (bearing in mind the note above). Here’s an example that shows how a route references custom domains. Also, if you’re adding a large number of custom domain resources, you can do that with a loop — a resource loop for creating each of the custom domain resources, and a property loop to refer to those domains within the route. However, note that there’s a chance you’ll run into a rate limit. (It might be fine — I’m not sure.) If you do, you can control the batch size in Bicep so it only deploys, say, 4 at a time.
Of course, this seems to be exactly what Terraform is attempting to do on my behalf. It creates the custom domain, it then associates it with the route. John gives an example in Bicep which looks pretty much identical to my Terraform code. However, after I create the TXT DNS record, I am still stuck in “Pending”.
Conclusion
While the new version of Azure Front Door offers promising capabilities, it also seems to come with frustrating issues — particularly when setting up custom domains. The inability to move past the “Pending” state, even after correctly configuring DNS records, is a serious roadblock.
If you’re encountering this issue, you’re not alone. Hopefully, I can figure out how to resolve this soon, as it is currently leaving me stranded with no recourse. Big sad.
More to come…