Using Cloudflare with Azure App Service for WordPress — Without Azure Blob Storage

Cloudflare can provide Azure-hosted WordPress sites with edge security, TLS, DNS proxying, compression and static asset caching—without requiring Azure Front Door.

This KloudStack Labs review documents a working configuration using Cloudflare directly in front of an Azure App Service. WordPress uploads are served from the App Service’s local persistent storage; Azure Blob Storage is not used in this configuration.

Blob Storage integration and media offloading will be covered in a separate review.

Architecture

The resulting request path is:

Visitor → Cloudflare → Azure App Service

Cloudflare provides the public edge layer, while Azure App Service remains the application origin.

The configuration includes:

  • Cloudflare proxied DNS
  • Cloudflare edge TLS
  • Full (strict) TLS between Cloudflare and Azure
  • An Azure App Service custom domain
  • A Cloudflare Origin CA certificate installed in App Service
  • Azure access restrictions allowing only Cloudflare
  • Cloudflare WAF and WordPress security rules
  • Static asset caching
  • WordPress and W3 Total Cache controlling HTML freshness
  • Local WordPress media under /wp-content/uploads/

Why consider Cloudflare instead of Azure Front Door?

Azure Front Door is a capable global edge service, but it can add significant cost and operational complexity to smaller WordPress environments.

Cloudflare provides many of the same core capabilities:

  • Global reverse proxy
  • CDN caching
  • Managed TLS
  • HTTP/2 and HTTP/3
  • Brotli and gzip compression
  • DDoS protection
  • Web Application Firewall capabilities
  • Redirect rules
  • Rate limiting
  • Origin protection

For this lab, removing Azure Front Door produced a simpler path:

Cloudflare → Azure App Service

It also eliminated the additional Front Door hop and associated configuration.

This is not necessarily the correct architecture for every workload. Azure Front Door remains useful when an application needs Azure-native routing across multiple regions, Private Link origins, advanced load balancing or other Azure-specific integrations.

Before starting

You will need:

  • An Azure App Service running WordPress
  • A custom domain
  • The domain’s DNS zone managed by Cloudflare
  • Access to Azure App Service custom domains, certificates and networking
  • Access to the WordPress administrator
  • W3 Total Cache or another WordPress caching solution, if required

Take a copy of the existing DNS records and document the current origin before making changes.

If replacing Azure Front Door, retain the existing Front Door configuration during the initial validation period so it remains available as a rollback path.

1. Add the Azure App Service custom domain

Azure App Service must recognise the public hostname that Cloudflare will use when connecting to the origin.

In the Azure portal:

  1. Open the App Service.
  2. Select Custom domains.
  3. Select Add custom domain.
  4. Enter the apex domain, such as example.com.
  5. Complete domain ownership validation.
  6. Add the domain to the App Service.

Azure may request an asuid TXT record to validate ownership.

During a reverse-proxy migration, Azure may warn that the domain does not have a matching A record pointing directly to App Service. Domain ownership can still be validated through the TXT record.

After adding the domain, it may initially display No binding until a certificate is uploaded and bound.

Microsoft documents the general process in Set up an existing custom domain in Azure App Service.

2. Create a Cloudflare Origin CA certificate

Cloudflare needs to validate the certificate presented by Azure App Service when using Full (strict) encryption.

A Cloudflare Origin CA certificate can be used when the origin is designed to receive traffic only through Cloudflare.

In Cloudflare:

  1. Open the domain.
  2. Go to SSL/TLS → Origin Server.
  3. Select Create certificate.
  4. Generate an RSA 2048 private key and certificate.
  5. Include the apex and wildcard hostnames:
    • example.com
    • *.example.com
  6. Select an appropriate validity period.
  7. Create the certificate.
  8. Save the certificate and private key securely.

Cloudflare displays the private key only during certificate creation. Treat it as a production secret.

A Cloudflare Origin CA certificate is trusted by Cloudflare but not by ordinary web browsers. If Cloudflare proxying is disabled, visitors may receive an untrusted certificate warning when connecting directly to the origin.

See Cloudflare Origin CA certificates for additional details.

3. Convert the certificate into a PFX file

Azure App Service expects a password-protected PFX certificate for a bring-your-own-certificate binding.

Cloudflare provides the certificate and private key in PEM format, so they must be packaged into a PFX file before uploading to App Service.

This can be completed with OpenSSL.

The resulting PFX should include:

  • The Cloudflare Origin CA certificate
  • The matching private key
  • The relevant Cloudflare Origin CA chain
  • A strong export password

Do not store the plaintext private key in a synchronised Desktop or OneDrive folder.

Move the files into a protected location, such as:

C:\Users\<username>\AppData\Local\KloudStack\Cloudflare-Origin

For a production KloudStack implementation, certificate generation, PFX packaging, secure storage, binding and expiry monitoring should be automated. The private key and PFX should be stored in Azure Key Vault or another suitable secrets platform.

4. Upload and bind the certificate in Azure

In the App Service:

  1. Go to Certificates.
  2. Open Bring your own certificates (.pfx).
  3. Select Add certificate.
  4. Upload the PFX.
  5. Supply the PFX password.
  6. Return to Custom domains.
  7. Select Add binding for the domain.
  8. Choose the uploaded certificate.
  9. Use an SNI SSL binding.

The custom domain should now display:

  • Status: Secured
  • Binding type: SNI SSL
  • Certificate: the uploaded Cloudflare Origin certificate

Azure’s certificate-binding process is documented in Secure a custom domain with TLS in Azure App Service.

5. Restrict App Service access to Cloudflare

Without access restrictions, someone who discovers the Azure App Service origin could bypass Cloudflare and connect directly to the application.

Azure App Service access restrictions can be used to allow Cloudflare’s public proxy ranges and deny unmatched traffic.

In Azure:

  1. Open App Service → Networking.
  2. Open Access restrictions.
  3. Select Enabled from select virtual networks and IP addresses.
  4. Add allow rules covering Cloudflare’s current IPv4 ranges.
  5. Add allow rules covering Cloudflare’s current IPv6 ranges.
  6. Leave Unmatched rule action set to Deny.
  7. Save the configuration.

Cloudflare publishes its current ranges on its Cloudflare IP addresses page.

Cloudflare recommends allowing its published ranges and blocking other origin traffic to prevent visitors from bypassing its security layer. See Protect your origin server for the associated guidance.

Important operational requirement

Cloudflare’s address ranges are not represented by an Azure service tag.

A production platform should therefore:

  • Retrieve the official ranges automatically
  • Compare them with the Azure access restrictions
  • Apply additions or removals safely
  • Record changes
  • Alert if synchronisation fails

Hard-coded Cloudflare ranges should not be assumed to remain unchanged indefinitely.

After applying the rules, direct access to the default azurewebsites.net hostname may return 403 Forbidden. This is expected if it does not meet an allow rule.

Azure documents access-rule ordering and implicit denial behaviour in Set up Azure App Service access restrictions.

6. Configure Cloudflare DNS

Create or update proxied Cloudflare DNS records for the public domain.

For example:

Type: CNAME
Name: @
Target: example-app.azurewebsites.net
Proxy status: Proxied

For www:

Type: CNAME
Name: www
Target: example-app.azurewebsites.net
Proxy status: Proxied

The orange-cloud status must be enabled for traffic to pass through Cloudflare.

Keep required validation TXT records, including Azure asuid records. They may be needed if the custom domain must be revalidated or recreated later.

7. Configure SSL/TLS

In Cloudflare, set:

SSL/TLS encryption mode: Full (strict)

This provides encryption across both parts of the connection:

  • Browser to Cloudflare
  • Cloudflare to Azure App Service

Full (strict) also validates the origin certificate. Cloudflare documents this in Full (strict) SSL/TLS encryption.

Recommended supporting settings include:

  • Always Use HTTPS: On
  • Minimum TLS version: TLS 1.2
  • TLS 1.3: On
  • Automatic HTTPS Rewrites: On, where required
  • HTTP/2: On
  • HTTP/3: On
  • HTTP/2 to Origin: On

Avoid enabling HSTS until HTTPS has been fully validated across every required hostname. Incorrect HSTS configuration can make recovery difficult because browsers retain the policy.

8. Redirect www to the apex domain

Cloudflare Redirect Rules can perform the redirect without sending the request to WordPress.

Example match:

Hostname equals www.example.com

Example dynamic destination:

concat("https://example.com", http.request.uri.path)

Configure the rule to:

  • Preserve the query string
  • Return HTTP 301
  • Remain active

This results in:

https://www.example.com/path/?query=value

redirecting to:

https://example.com/path/?query=value

The redirect is processed at Cloudflare’s edge and does not consume App Service resources.

9. Use Cloudflare for static assets—not WordPress HTML

Our initial lab configuration used a Cloudflare Cache Rule to cache public WordPress HTML at the edge.

While this produced CF-Cache-Status: HIT, it created an important content-management problem: after publishing a post, the homepage could remain stale until Cloudflare was manually purged.

The official Cloudflare WordPress plugin includes Automatic Cache Management. Cloudflare states that it uses WordPress hooks to purge associated URLs when posts, pages, attachments or comments change.

However, in our test, it did not reliably invalidate HTML cached through our modern Cloudflare Cache Rule.

The safe baseline was therefore:

  • Disable the custom Public WordPress HTML Cache Rule.
  • Keep WordPress dynamic bypass protections.
  • Allow Cloudflare to cache supported static files normally.
  • Let WordPress and W3 Total Cache manage HTML/page caching.

After making this change:

Homepage: CF-Cache-Status: DYNAMIC
Post HTML: CF-Cache-Status: DYNAMIC
Static assets: CF-Cache-Status: HIT after warming

Publishing or updating a post then updated the homepage without requiring a manual Cloudflare purge.

This is essential for a managed customer environment. Site editors should not need to understand or manually operate a CDN cache whenever content changes.

Cloudflare documents its plugin behaviour in Cloudflare WordPress Plugin Automatic Cache Management.

10. Configure W3 Total Cache

For the no-Blob-Storage configuration:

  • W3TC CDN functionality should be disabled.
  • Existing Blob Storage or CDN hostname rewriting should be removed.
  • Page cache can remain enabled.
  • Browser cache can remain enabled, subject to review.
  • Object cache should be reviewed separately based on the WordPress architecture.
  • Empty all W3TC caches after changing CDN settings.

Media should resolve through normal WordPress paths such as:

https://example.com/wp-content/uploads/2026/07/image.jpg

It should not use an old rewritten Blob route such as:

https://example.com/blob-prefix/wp-content/uploads/2026/07/image.jpg

After changing W3TC CDN settings:

  1. Empty all W3TC caches.
  2. Purge Cloudflare once.
  3. Clear generated theme or page-builder assets if required.
  4. Inspect the resulting HTML.
  5. Confirm images use /wp-content/uploads/.
  6. Check the browser Network panel for 404 responses.

Browser caching warning

A Cloudflare purge does not remove files already stored in visitors’ browser caches.

If static media is given a long browser lifetime and an image is replaced using the same filename, some visitors may continue seeing the old image.

The preferred strategy is to use immutable or versioned asset URLs:

logo-v2.png

rather than repeatedly overwriting:

logo.png

11. Install the Cloudflare WordPress plugin

The official Cloudflare WordPress plugin can be installed for settings management and cache-purge integration.

Use a restricted Cloudflare API token rather than the Global API Key.

Limit the token to:

  • The required Cloudflare account
  • The specific customer zone
  • Only the permissions needed by the plugin

Relevant permissions may include:

  • Zone: Read
  • Zone Analytics: Read
  • Zone Settings: Edit
  • Cache Purge: Purge
  • DNS: Read

Do not scope a customer WordPress token to every account and every zone.

Avoid client-IP restrictions unless the App Service outbound addresses are known and operationally stable. WordPress makes API calls from Azure, not from the administrator’s browser.

The plugin can remain enabled for static asset purging and Cloudflare integration. It should not be considered sufficient evidence that every custom HTML caching rule will be invalidated correctly.

12. Add WordPress security rules

Cloudflare can block common malicious requests before they reach PHP or consume App Service CPU.

Block PHP execution in uploads

Example expression:

starts_with(http.request.uri.path, "/wp-content/uploads/")
and http.request.uri.path contains ".php"

Action:

Block

WordPress uploads should not normally contain executable PHP files.

Block sensitive WordPress and development files

Examples include:

/.env
/.git
/wp-config.php
/wp-content/debug.log
/phpinfo.php
/composer.json
/composer.lock

Action:

Block

Rate-limit authentication requests

Match:

/wp-login.php
/xmlrpc.php

Apply a per-IP rate limit suitable for the application.

Be careful not to make the threshold so restrictive that legitimate administrators or integrations are blocked.

13. Restore the original visitor IP

When Cloudflare proxies traffic, Azure App Service sees Cloudflare as the network source.

Cloudflare provides the original visitor address in headers such as:

CF-Connecting-IP
X-Forwarded-For

The origin web server and WordPress security tools must be configured to trust these headers only when the request originates from an approved Cloudflare address.

For an Nginx-based WordPress container, this generally requires:

real_ip_header CF-Connecting-IP;
real_ip_recursive on;

along with set_real_ip_from entries for Cloudflare’s current ranges.

This should be managed from the same source used to maintain App Service access restrictions.

After configuration, verify that:

  • Nginx access logs contain the visitor IP.
  • WordPress sees the visitor IP.
  • Wordfence sees the visitor IP.
  • Application Insights records the visitor IP appropriately.
  • Rate-limiting logic does not treat every visitor as one Cloudflare address.

14. Validate the configuration

Do not rely only on what the dashboards display.

Test the live site and inspect the response headers.

Expected HTML response

server: cloudflare
cf-cache-status: DYNAMIC

Expected warmed static asset response

server: cloudflare
cf-cache-status: HIT

Depending on the client’s request headers, static resources may also return:

content-encoding: br

or:

content-encoding: gzip

Additional tests

Confirm that:

  • The apex domain loads over HTTPS.
  • www redirects to the apex domain.
  • Paths and query strings survive the redirect.
  • WordPress login remains uncached.
  • /wp-admin/ remains uncached.
  • /wp-json/ remains uncached.
  • Logged-in sessions remain uncached.
  • Static CSS, JavaScript, fonts and images are cached.
  • A PHP request inside uploads receives a Cloudflare 403.
  • Sensitive file requests receive a Cloudflare 403.
  • A normal nonexistent file reaches the origin and returns 404.
  • The Azure Front Door headers no longer appear.
  • The default App Service hostname remains inaccessible externally.
  • Publishing a post updates the homepage without a manual Cloudflare purge.

Final architecture

The completed lab configuration is:

Visitor
   ↓
Cloudflare DNS, TLS, WAF, redirects and static CDN
   ↓
Azure App Service access restrictions
   ↓
WordPress on Azure App Service
   ↓
Local persistent WordPress uploads

WordPress HTML remains dynamic at Cloudflare, while static resources benefit from Cloudflare’s distributed edge network.

What worked well

The Cloudflare and Azure App Service integration successfully provided:

  • A simpler edge architecture
  • Full strict end-to-end TLS
  • Direct Cloudflare-to-App-Service delivery
  • Origin access restrictions
  • Static asset caching
  • Brotli and gzip compression
  • HTTP/2 and HTTP/3
  • Edge redirects
  • WordPress-specific WAF rules
  • Authentication rate limiting
  • Immediate WordPress publishing without manual CDN purging

What still needs further review

This configuration intentionally serves media from App Service storage.

For larger or multi-instance WordPress deployments, the next review should cover:

  • Azure Blob Storage media offloading
  • A dedicated media hostname
  • Cloudflare in front of Azure Blob Storage
  • URL and origin routing
  • Cache invalidation for replaced media
  • W3 Total Cache integration
  • Private containers or signed access
  • Cross-origin headers
  • Image optimisation
  • Storage redundancy
  • Migration of existing media
  • Multi-instance upload consistency

The preferred long-term media path may look like:

Visitor → media.example.com → Cloudflare → Azure Blob Storage

This separates application traffic from media delivery while retaining Cloudflare as the public CDN layer.

Conclusion

Cloudflare can operate effectively as the public edge for WordPress running on Azure App Service without Azure Front Door or Azure Blob Storage.

The most important lesson from the lab was not to assume that edge-cached WordPress HTML will always be invalidated correctly.

For the initial KloudStack baseline, the reliable configuration is:

  • Cloudflare for DNS, proxying, TLS, WAF and static assets
  • Azure App Service as the protected origin
  • W3 Total Cache for WordPress HTML caching
  • Cloudflare HTML responses left dynamic
  • WordPress media served from local App Service storage

This provides meaningful CDN and security benefits without making content publishing dependent on manual Cloudflare cache purges.

Next KloudStack Labs review: Cloudflare with Azure Blob Storage for WordPress media delivery.


Posted

in

by

Tags:

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *