In our previous KloudStack Labs review, we demonstrated how Cloudflare can replace Azure Front Door as the public edge for WordPress running on Azure App Service—without using Azure Blob Storage.
That configuration used the following request path:
Visitor → Cloudflare → Azure App Service → WordPress local storage
This follow-on review extends the architecture to WordPress environments that already offload media to Azure Blob Storage through W3 Total Cache.
The resulting architecture is:
Dynamic application traffic
Visitor
↓
Cloudflare
↓
Azure App Service
↓
WordPress
Media traffic
Visitor
↓
Cloudflare
↓
Cloudflare Cloud Connector
↓
Azure Blob Storage
Cloudflare now provides the public DNS, TLS, WAF, redirect and caching layer for both the WordPress application and its Blob-hosted media. Azure Front Door is no longer required in either request path.
This review covers:
- Routing WordPress media from Cloudflare directly to Azure Blob Storage
- Preserving the existing W3 Total Cache URL structure
- Installing a Cloudflare Origin CA certificate on Azure App Service
- Restricting the App Service origin to Cloudflare
- Retaining dynamic WordPress cache bypasses
- Validating Blob content and Cloudflare cache behaviour
- Troubleshooting Origin CA, access restriction and W3TC authentication errors
Starting architecture
The WordPress environment already used:
- Azure App Service for Linux
- A containerised WordPress application
- Azure Blob Storage for WordPress uploads
- W3 Total Cache for Blob offloading and hostname rewriting
- Azure Front Door as the public edge and CDN
- A custom apex domain
- A path-based media structure
Media URLs followed a pattern similar to:
https://example.com/wpblob123456/wp-content/uploads/2026/07/image.webp
The first path segment is the Azure Blob container name:
wpblob123456
The remaining path identifies the object inside the container:
wp-content/uploads/2026/07/image.webp
The objective was to preserve these public URLs while replacing the Azure Front Door media origin route with Cloudflare.
Changing every existing media URL was unnecessary and would have introduced avoidable migration risk.
Final request paths
After migration, dynamic WordPress requests use:
Visitor
↓
Cloudflare proxy
↓
Azure App Service custom domain
↓
WordPress
Requests beginning with the Blob container path use:
Visitor
↓
Cloudflare proxy
↓
Cloud Connector path route
↓
Azure Blob Storage
For example:
https://example.com/wpblob123456/wp-content/uploads/2026/07/image.webp
is routed to:
https://examplestorage.blob.core.windows.net/wpblob123456/wp-content/uploads/2026/07/image.webp
The public hostname remains the WordPress domain, while Cloudflare changes the origin used for the matching media path.
Why preserve path-based Blob URLs?
A separate media hostname such as media.example.com is a valid architecture, but it is not always necessary.
Preserving path-based URLs provides several practical benefits:
- Existing WordPress content does not need to be rewritten.
- W3 Total Cache can continue using the primary website hostname.
- Media remains same-origin from the browser’s perspective.
- Cross-origin resource sharing configuration is generally simpler.
- Existing search-engine indexing and references remain intact.
- The migration can be rolled back without changing stored WordPress URLs.
- Application and media traffic can still use different origins behind Cloudflare.
This approach allows the public URL structure to remain stable while the infrastructure behind it changes.
1. Complete the App Service configuration
Before changing the Blob route, Cloudflare must be able to reach Azure App Service directly.
The App Service configuration requires:
- The apex domain added as an App Service custom domain
- Domain ownership validated using the Azure
asuidTXT record - A valid TLS certificate covering the apex domain
- An SNI SSL binding
- App Service access restrictions allowing Cloudflare
- The Cloudflare apex record proxied to the App Service hostname
The complete App Service configuration is covered in the earlier review:
Using Cloudflare with Azure App Service for WordPress — Without Azure Blob Storage
2. Create the Cloudflare Cloud Connector route
The Blob Storage route must match the path structure generated by W3 Total Cache.
In this example, the route is:
/wpblob123456/*
The destination is the Azure Storage account hostname:
examplestorage.blob.core.windows.net
The container name remains part of the request path. Cloudflare forwards the request to the Storage account using the original URI:
/wpblob123456/wp-content/uploads/2026/07/image.webp
Azure Blob Storage interprets the first path segment as the container and the remainder as the object name.
This avoids introducing a Worker solely to rewrite the Blob path.
Cloud Connector configuration
Create a route similar to:
Route:
/wpblob123456/*
Destination:
examplestorage.blob.core.windows.net
The exact Cloudflare interface may change as Cloud Connector develops, but the important behaviour is:
- Match only the Blob container path.
- Send matching requests to the Azure Blob hostname.
- Preserve the complete URI.
- Leave all other requests using the App Service origin.
Do not route the entire domain to Blob Storage.
3. Retain the W3 Total Cache Blob configuration
W3 Total Cache remains responsible for uploading WordPress media to Azure Blob Storage.
The Azure Storage CDN configuration should include:
Account name:
examplestorage
Container:
wpblob123456
Replace site's hostname with:
example.com
W3TC then generates URLs such as:
https://example.com/wpblob123456/wp-content/uploads/2026/07/image.webp
Cloudflare recognises the container prefix and routes the request to Blob Storage.
Storage account key
W3TC requires an Azure Storage account access key for authenticated upload and container operations.
If the W3TC connection test returns:
AuthenticationFailed
The MAC signature found in the HTTP request is not the same as any computed signature
the stored key does not match the current Storage account key.
Retrieve the current key from:
Azure Storage account
→ Security + networking
→ Access keys
Copy the key value—not the connection string—and replace the W3TC Account key.
Do not expose the Storage account key in screenshots, logs, tickets or documentation.
After replacing it:
- Save the W3TC settings.
- Run the Microsoft Azure Storage upload test.
- Confirm that the container can be listed.
- Upload or synchronise a test object.
- Confirm that the public Cloudflare URL returns the object.
The public Blob route can continue working even while the W3TC connection test fails. Public delivery and authenticated upload are separate operations.
4. Configure Cloudflare caching
Azure Blob objects commonly provide long-lived cache headers.
A typical response might contain:
cache-control: public, max-age=31536000
Cloudflare was configured to respect the origin’s browser cache headers rather than replace them globally.
The expected first request is:
CF-Cache-Status: MISS
A subsequent request should return:
CF-Cache-Status: HIT
A warmed media response should resemble:
HTTP/2 200
content-type: image/webp
cache-control: public, max-age=31536000
server: cloudflare
cf-cache-status: HIT
Azure Blob headers may still appear, including:
x-ms-blob-type
x-ms-version
x-ms-request-id
These confirm that the underlying object was served by Azure Blob Storage.
Azure Front Door headers should no longer appear.
In particular, the response should not contain:
x-azure-ref
x-cache: CONFIG_NOCACHE
5. Keep WordPress HTML dynamic at Cloudflare
The Blob route does not change the cache strategy for WordPress HTML.
Our safe baseline remains:
- WordPress HTML: dynamic at Cloudflare
- WordPress admin: bypass
- WordPress login: bypass
- WordPress REST API: bypass where required
- Logged-in users: bypass
- Preview requests: bypass
- Static files: cache normally
- Blob media: cache at Cloudflare using the origin headers
This allows WordPress and W3 Total Cache to control page freshness while Cloudflare handles static and Blob-hosted assets.
Expected homepage response:
CF-Cache-Status: DYNAMIC
Expected warmed media response:
CF-Cache-Status: HIT
This avoids the content-publishing problem where an updated post or homepage remains stale at the edge until someone manually purges Cloudflare.
6. Install the correct Cloudflare Origin CA certificate
Cloudflare Full (strict) requires Azure App Service to present a valid certificate for the public hostname.
When creating the certificate in Cloudflare, include both:
*.example.com
example.com
Before packaging the certificate into a PFX, inspect its metadata:
openssl x509 `
-in "Origin Certificate.txt" `
-noout `
-subject `
-issuer `
-dates `
-ext subjectAltName
The output must contain:
DNS:*.example.com
DNS:example.com
Do not assume the certificate contains the correct names merely because it was created from the correct Cloudflare zone.
During our implementation, an incorrectly generated certificate contained only:
CN=Cloudflare
Azure accepted the PFX as a certificate resource, but it could not be selected for the custom-domain binding because it did not match the domain.
Create an Azure-compatible PFX
Download Cloudflare’s Origin CA RSA root:
Invoke-WebRequest `
-Uri "https://developers.cloudflare.com/ssl/static/origin_ca_rsa_root.pem" `
-OutFile "cloudflare-origin-ca-rsa-root.pem"
Package the certificate, matching private key and chain:
openssl pkcs12 -export `
-out "example.com-cloudflare-origin.pfx" `
-inkey "Private Key.txt" `
-in "Origin Certificate.txt" `
-certfile "cloudflare-origin-ca-rsa-root.pem" `
-name "example-cloudflare-origin" `
-keypbe PBE-SHA1-3DES `
-certpbe PBE-SHA1-3DES `
-macalg SHA1
OpenSSL prompts for an export password. Retain this password securely because Azure requires it during upload.
Do not share or display the private-key contents.
In Azure App Service:
- Open Certificates.
- Select Bring your own certificates (.pfx).
- Upload the PFX.
- Enter the export password.
- Validate and add the certificate.
- Return to Custom domains.
- Add an SNI SSL binding for the apex domain.
The custom domain should then display:
Status: Secured
Binding type: SNI SSL
7. Allow Cloudflare through App Service access restrictions
If App Service previously allowed only Azure Front Door, changing the Cloudflare origin directly to App Service will produce:
HTTP 403
x-ms-forbidden-ip
This does not indicate a Cloudflare TLS or DNS failure. It means the Cloudflare proxy address was rejected by the App Service access restrictions.
Cloudflare publishes its current proxy ranges at:
Create Azure App Service allow rules for all current Cloudflare ranges and leave:
Unmatched rule action: Deny
Azure multi-source access restriction rules accept up to eight IP ranges per rule, so the Cloudflare ranges can be divided into a small number of logical rules.
For example:
AllowCloudflareIPv4-A
AllowCloudflareIPv4-B
AllowCloudflareIPv6
Do not add the Cloudflare ranges as HTTP header filters. They are network source ranges.
Retain the Azure Front Door allow rule during the migration so Front Door remains available as a rollback path.
After confirming the Cloudflare route is stable, the Front Door rule can be removed as part of decommissioning.
8. Validate the Blob object itself
A successful HTTP status does not prove that Cloudflare and Azure returned identical content.
For an exact migration test:
- Request the object directly from Azure Blob Storage.
- Request the same object through the Cloudflare public URL.
- Save both responses.
- Calculate a SHA-256 hash for each file.
- Compare the results.
The hashes must match.
Example:
Get-FileHash ".\azure-blob.webp" -Algorithm SHA256
Get-FileHash ".\cloudflare-blob.webp" -Algorithm SHA256
Matching hashes confirm that:
- The Cloud Connector route points to the correct Storage account.
- The container path is preserved.
- The requested object is correct.
- Cloudflare is not returning an unexpected file or error document.
- No transformation has changed the object.
9. Test the complete migration
The final validation should include all of the following.
Main site
https://example.com/
Expected:
HTTP 200
server: cloudflare
cf-cache-status: DYNAMIC
WWW redirect
https://www.example.com/path/?test=1
Expected:
HTTP 301
location: https://example.com/path/?test=1
Blob media
https://example.com/wpblob123456/wp-content/uploads/2026/07/image.webp
Expected after warming:
HTTP 200
server: cloudflare
cf-cache-status: HIT
W3TC authenticated connection
Expected:
Test passed
Azure Front Door removal
The main-site and media responses should not contain Azure Front Door headers.
Origin restriction
Requests arriving from unapproved networks should be rejected by App Service.
WordPress publishing
Publishing or updating content should be reflected immediately without manually purging Cloudflare HTML.
Migration issues encountered
Several issues were identified during the implementation.
Incorrect Origin CA hostnames
The first certificate did not contain the required .com.au names. Azure could store it but could not bind it to the domain.
Lesson:
Always inspect the certificate SANs before creating the PFX.
Missing certificate chain
The initial PFX did not include the Cloudflare Origin CA root certificate and Azure could not load it successfully.
Lesson:
Package the leaf certificate, matching private key and relevant CA chain together.
App Service blocked Cloudflare
After changing the apex origin from Front Door to App Service, Azure returned x-ms-forbidden-ip.
Lesson:
Add and save every Cloudflare IPv4 and IPv6 range before changing the production origin.
W3TC Blob authentication failed
The media URL worked publicly, but the W3TC Azure Storage test returned a MAC signature error.
The stored Storage account key was no longer valid. Replacing it with the current Azure key resolved the connection.
Lesson:
Public object delivery and authenticated W3TC upload tests validate different parts of the architecture.
Front Door remained in the request path
The site returned successfully through Cloudflare, but x-azure-ref remained in the response.
The Cloudflare apex CNAME was still targeting Azure Front Door.
Lesson:
A successful Cloudflare response does not prove that Front Door has been removed. Inspect the response headers.
Final architecture
The completed architecture is:
┌─────────────────────────┐
│ Cloudflare │
│ DNS, TLS, WAF, redirect │
│ and CDN caching │
└───────────┬─────────────┘
│
┌──────────────────┴──────────────────┐
│ │
Dynamic WordPress requests /wpblob-container/*
│ │
▼ ▼
Azure App Service custom domain Cloudflare Cloud Connector
│ │
▼ ▼
WordPress Azure Blob Storage
Cloudflare is the only public edge presented to visitors.
Azure App Service handles application traffic, while Azure Blob Storage handles WordPress media. The URL structure remains consistent across both origins.
What worked well
The completed configuration provided:
- Removal of Azure Front Door from the live request path
- Cloudflare DNS and reverse proxying
- Full strict end-to-end TLS
- A protected Azure App Service origin
- Direct Cloudflare-to-Blob delivery
- Existing W3TC media URLs without content rewriting
- Cloudflare edge caching for Blob objects
- Dynamic WordPress HTML
- Edge-level
wwwredirects - WordPress-specific WAF controls
- Authentication rate limiting
- A retained rollback path during migration
Operational considerations
This architecture still requires ongoing management.
Cloudflare IP ranges should be synchronised automatically with Azure App Service access restrictions. A production control plane should:
- Retrieve the official Cloudflare ranges.
- Compare them with the current Azure rules.
- Apply additions and removals safely.
- Record every change.
- Alert when synchronisation fails.
Storage account keys should also be rotated deliberately. Any key rotation must update W3 Total Cache or another upload integration using Shared Key authentication.
Long-lived cached media should use versioned or immutable filenames. Replacing an object under the same URL may leave older copies in Cloudflare or visitors’ browser caches until expiration.
The Cloudflare Origin CA certificate should be tracked in the organisation’s certificate inventory even when it has a long validity period. Cloudflare does not currently provide expiry notifications for Origin CA certificates.
Conclusion
Cloudflare can replace Azure Front Door for WordPress environments using both Azure App Service and Azure Blob Storage.
The important design decision is to separate routing by request path:
WordPress requests → Azure App Service
Blob media requests → Azure Blob Storage
Cloudflare provides a single public edge across both origins while W3 Total Cache continues handling authenticated media uploads and URL generation.
The most important implementation lessons were:
- Verify Origin CA hostnames before packaging the certificate.
- Include the Cloudflare CA chain in the Azure PFX.
- Allow all Cloudflare networks before changing the origin.
- Inspect headers to prove Front Door has left the request path.
- Validate Blob objects using hashes, not only HTTP status codes.
- Treat W3TC authentication separately from public media delivery.
The result is a simpler and more cost-effective edge architecture that retains Azure App Service for WordPress, Azure Blob Storage for scalable media and Cloudflare for security, TLS, routing and CDN delivery.

Leave a Reply