Host Static WordPress at BunnyCDN With WP2Static without Losing Comment, Search, Contact Form 7

Key Difference in Traditional vs Static WordPress

ParameterTraditional WordPressStatic WordPress
🌐 DNSPoints to WordPress Server IP addressPoints to CDN hostname linked with static Storage
🚀 Web PerfExpensive to get TTFB <200 ms worldwideInexpensive way to get TTFB <200ms worldwide
🏠 EnvLinux Ubuntu, PHP, MySQL, NGINX/ApacheCloud Storage for static hosting and CDN for seving
🛡️ SecurityBrute-force, SQL Injection, XSS is a common thingGreatly reduces the attack surface
🛒 E-ComYou can use WooCommerceYou can use Snipcart
🍻 SupportSearch, Comment, Contact Form 7, Users, WPMLSearch, Comment, Contact Form 7, Users, WPML

Guess, what? This blog is a live example of a Static WordPress for perf & security reasons.

Yes, my comment, search works. I can also use form if I want.

So how this works?

  • gulshankumar.net, www.gulshankumar.net points to BunnyCDN hostname which is linked to BunnyCDN Storage.
Serverless WordPress
Serverless WordPress Architecture. (Click to Zoom)

Before we proceed, there are some prerequisite things to do for the best user-experience. Once a custom environment is ready, for WP2Static plugin, we can deploy Static WordPress at BunnyCDN.

1. Use Google Custom Search Engine

Google Custom Search
Search Results
  • WordPress native search works at permalink like https://example.com/?s=search+query and it cannot work with Static HTML site. It will return homepage just like any query string.
  • WordPress Search is slow, uncached, often shows irrelevant result. Static site gives you strong opportunity to fix that by using Google Custom Search Engine. You can serve “Search Results” page always in HIT mode.

Read how to properly integrate CSE for GeneratePress Theme.

2. Take a complete Backup of WordPress

Just a hint, you may use UpdraftPlus or All in One Migration Premium plugin to take backup. Or, you can do manually as well.

3. Restore WordPress AS IS at Germany based LEMP Stack

Read how to deploy WordPress at LEMP Stack.

  • The most important thing is environment and LEMP is the best stack to perform well.
  • BunnyCDN Storage server is located in Germany. For faster deployment, it’s better to have Development site on same location.
  • Since we want to accept Comments, Contact Form 7 messages, allow Contributor as well; this is required for housekeeping.
  • Incase you don’t need comments or contact form 7, then you may keep local server at Linux machine (Windows OS is not recommended).

4. Link a Subdomain to WordPress for Managing Dashboard

  • We need to keep development area at a subdomain dev.gulshankumar.net address. This would be password protected.
  • In WordPress, Install and activate Multiple Domains plugin and configure as below.
  • Using Cloudflare DNS, point dev.gulshankumar.net to the LEMP Server IP where WordPress is installed. Keep it proxied with Cloudflare.
Adding development path

This plugin will take care of URL rewriting based on Request Hostname.

Do not directly change WordPress primary domain to dev.example.com. This will create problem. I have explained at the end of this article.

5. Password Protect Server excluding Contact Form 7 & Comment URL

## Allowed path
dev[dot]gulshankumar[dot]net/wp-json/contact-form-7/v1/contact-forms/1478/feedback
should return error 404 with below response body
{"code":"rest_no_route","message":"No route was found matching the URL and request method","data":{"status":404}}
dev[dot]gulshankumar[dot]net/wp-comments-post.php
should return special error 405
## Blocked Path ##
dev[dot]gulshankumar.net/
dev[dot]gulshankumar.net/anything/
should return 401 if credential not provided.

Thanks to CloudBooklet who helped me in setting up HTTP Authentication as per my requirement.

Install Apache Tools for .htpasswd generation

SSH your Server and type following commands

sudo -s
apt install apache2-utils -y

Generate Password

htpasswd -c /var/www/.htpasswd gulshan

where username is gulshan, enter the password. Now, you will see output like this

root@WordPress:~# htpasswd -c /var/www/.htpasswd gulshan
New password: 
Re-type new password: 
Adding password for user gulshan

Find hashed password using below command and save it at secure place.

cat /var/www/.htpasswd

Setup custom 401 page

  • Add a custom_401.html file at /var/www/html directory as per below configuration.

Configure NGINX Server Block for WP2Static

  • Edit your existing server block at /etc/nginx/sites-available/gulshankumar.net
  • You need to replace .gulshankumar.net with own domain. This is in the wildcard format to match development subdomain also.
Copy Form ID
  • Setup correct Contact Form 7 ID in the NGINX configuration.
  • Below rule will enable password protection as needed, also adds few useful tweaks for WP2Static.
server {
root /var/www/html;
index index.php index.html index.htm;
server_name .gulshankumar.net;
client_max_body_size 0;
server_tokens off;
# Grace period for crawling and deployment
fastcgi_read_timeout 10800;
# Show Real IP for Comment Author instead showing BunnyCDN IP
set_real_ip_from 0.0.0.0/0;
set_real_ip_from ::/0;
real_ip_header X-Forwarded-For;
# Display Custom 401 page
        error_page 401 /custom_401.html;
        location = /custom_401.html {
                root /var/www/html;
                internal;
        }
# Allow access to Development site only over HTTPS requests
    listen [::]:443 ssl http2 ipv6only=on;
    listen 443 ssl http2;
        ssl on;
        ssl_protocols TLSv1.2 TLSv1.3;
        ssl_certificate /etc/letsencrypt/live/gulshankumar.net/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/gulshankumar.net/privkey.pem;
        ssl_prefer_server_ciphers on;
        ssl_session_cache   shared:SSL:30m;
        ssl_session_timeout 30m;
        ssl_ciphers 'EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH';
error_page 404 /404.html;
error_page 500 502 503 504 /50x.html;
# Allow posting comments
location = /wp-comments-post.php {
  auth_basic off;
  fastcgi_pass unix:/run/php/php7.4-fpm.sock;
  include fastcgi_params;
  fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
  fastcgi_param SCRIPT_NAME $fastcgi_script_name;
}
# Allow CF7. Please replace 1478 to own form ID.
location = /wp-json/contact-form-7/v1/contact-forms/1478/feedback {
  auth_basic off;
  try_files $uri $uri/ /index.php?q=$uri&$args;
}
location / {
# Whitelist
satisfy any;
allow XXX.XX.XXX.XXX;   # Allow your office IP
allow 167.114.226.142;  # Allow WP Rocket Critical CSS
allow XX.XXX.XX.XX;     # Public IP
allow 10.4.6.192;       # Private IP
deny all;
auth_basic           "Secure Area";
auth_basic_user_file /var/www/.htpasswd;
try_files $uri $uri/ /index.php?q=$uri&$args;
}
location ^~ /wp-login.php {
# Whitelist
satisfy any;
allow XXX.XX.XXX.XXX;   # Allow your office IP
deny all;
 auth_basic           "Secure Area";
 auth_basic_user_file /var/www/.htpasswd;
 fastcgi_pass unix:/run/php/php7.4-fpm.sock;
 include fastcgi_params;
 fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
 fastcgi_param SCRIPT_NAME $fastcgi_script_name;
}
location ~* \.php$ {
if ($uri !~ "^/uploads/") {
fastcgi_pass unix:/run/php/php7.4-fpm.sock;
}
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param SCRIPT_NAME $fastcgi_script_name;
}
location = /favicon.ico {
# Whitelist
satisfy any;
allow XXX.XX.XXX.XXX;   # Allow your office IP
allow 167.114.226.142;  # Allow WP Rocket Critical CSS
allow XX.XXX.XX.XX;     # Public IP
allow 10.4.6.192;       # Private IP
deny all;
auth_basic           "Secure Area";
auth_basic_user_file /var/www/.htpasswd;
log_not_found off;
access_log off;
}
location = /robots.txt {
# Whitelist
satisfy any;
allow XXX.XX.XXX.XXX;   # Allow your office IP
allow 167.114.226.142;  # Allow WP Rocket Critical CSS
allow XX.XXX.XX.XX;     # Public IP
allow 10.4.6.192;       # Private IP
deny all;
auth_basic           "Secure Area";
auth_basic_user_file /var/www/.htpasswd;
log_not_found off;
access_log off;
allow all;
}
location ~* .(css|gif|ico|webp|jpeg|jpg|js|png)$ {
# Whitelist
satisfy any;
allow XXX.XX.XXX.XXX;   # Allow your office IP
allow 167.114.226.142;  # Allow WP Rocket Critical CSS
allow XX.XXX.XX.XX;     # Public IP
allow 10.4.6.XXX;       # Private IP
deny all;
auth_basic           "Secure Area";
auth_basic_user_file /var/www/.htpasswd;
expires 7d;
log_not_found off;
}
# Enable Gzip compression.
gzip on;
# Disable Gzip on IE6.
gzip_disable "msie6";
# Allow proxies to cache both compressed and regular version of file.
# Avoids clients that don't support Gzip outputting gibberish.
gzip_vary on;
# Compress data, even when the client connects through a proxy.
gzip_proxied any;
# The level of compression to apply to files. A higher compression level increases
# CPU usage. Level 5 is a happy medium resulting in roughly 75% compression.
gzip_comp_level 5;
# Compress the following MIME types.
gzip_types
        application/atom+xml
        application/javascript
        application/json
        application/ld+json
        application/manifest+json
        application/rss+xml
        application/vnd.geo+json
        application/vnd.ms-fontobject
        application/x-font-ttf
        application/x-web-app-manifest+json
        application/xhtml+xml
        application/xml
        font/opentype
        image/bmp
        image/svg+xml
        image/x-icon
        text/cache-manifest
        text/css
        text/plain
        text/vcard
        text/vnd.rim.location.xloc
        text/vtt
        text/x-component
        text/x-cross-domain-policy;
}
# End

Test Configuration

nginx -t

Reload NGINX

service nginx reload

Feel free to block TCP 80 in the Cloud Firewall of your server.

  • There is really no need of accepting any insecure request at Development area.
  • If you still want for your convenience, you may add a redirect at the top of server block.
server {
    listen 80;
    return 301 https://$host$request_uri;
}
...

6. Setup BunnyCDN

BunnyCDN is a globally fastest low-latency CDN. We will use it for serving our WordPress site.

Step 1. Add a Storage zone

This is where we will host WordPress Static version files.

Adding a new Storage zone
Adding a new Storage Zone

Step 2. Connect Storage Zone to Pull Zone

This step will tightly integrate your Storage with Pull zone to serve all requests from the CDN.

Storage and Pull zone Integration
Storage and Pull zone Integration

Set a name of your Pull zone

Adding Pull Zone
Pull zone

Skip introduction and head over the below basic configurations.

Step 3. In General Settings

  • Add minimum two custom hostnames: non-www and www version like gulshankumar.net, www.gulshankumar.net
Adding hostname to pull zone
Adding custom hostnames to Pull zone.

I am using Cloudflare for the DNS because it supports CNAME flattening.

  • Login to Cloudflare and point DNS as below. Then you would be able to install SSL Certificate in one click.
CNAME ---- @ ------- gulshankumar.b-cdn.net -- DNS only Mode
CNAME --- www ------ @ --- DNS only Mode
A ------- dev ------ LEMP Server IP ------- DNS and Proxy mode

⚠️ Please do not use Cloudflare Cache Everything or Ignore Query String rule for dev subdomain. To be on the safe side, add bypass cache rule at the top of all page rule. The matching URL should be like this *gulshankumar.net/*

Okay, let’s see the next step.

Step 5. Optimize Pull zone Caching behaviour

  • File Cache Expiration Time to 3 hours. This will act as default TTL for caching any file.
  • Query String Short: Enabled
  • Disable Cookies: Keep enabled for having cookieless domain.
  • Optimize for Media Files: Enabled
  • Vary Cache: Disable altogether. (Important for Search results, fbclid, utm and etc query string related pages)
Caching Configuration
Cache Settings

Step 6. Pull Zone Security

  • Do not block root path access.
Security
Security Settings
  • BunnyCDN has a beautiful way to represent logs detail. Keep Logging Enabled. It would be helpful in technical debugging.
logs
BunnyCDN Logs

Configure Edge Rule

BunnyCDN offer edge rule to customize the behaviour of Pull zone CDN. At the moment, there is no priority feature to execute rule in a order. In that case, Match None condition would be useful.

Case 1. Force custom hostname and non-www path

Your site can be accessed over BunnyCDN Pull Zone address as well as all added custom hostnames. Concerning branding, serve all requests from a single hostname as per site URL.

  • Action: Redirect URL
  • Description: Enforce Custom Hostname and non-www
  • Redirect URL: https://www.gulshankumar.net{{path}}
  • Condition matching: Match any
  • Condition: If Request URL (match any) *://gulshankumar.b-cdn.net/*
  • Condition: If Request URL (match any) *://www.gulshankumar.net/*

If your URL begins with www, please keep last request URL condition in non-www form. 😊

Case 2. Managing Redirection or Affiliate Links

For example, If you visit https://affiliate.gulshankumar.net/bunnycdn/ it will redirect to my affiliate link of BunnyCDN.

Things to know

  • Using Edge rule you can setup redirect with 301 response.
  • BunnyCDN serve HIT response for redirection with no-cache for browser. This eliminate the risk of serving old link. 👍
  • Previously, I had x-robots: noindex, nofollow header response with 3XX response. Currently, it is not possible to assign multiple actions but you can match multiple things. As solution, I keep rel="nofollow" tag in HTML whenever possible.
adding a redirect via edge rule
  • Action: Redirect URL
  • Description: Affiliate: BunnyCDN
  • Redirect URL: https://bunnycdn.com/?ref=uhs82glvx4
  • Condition matching: Match any
  • Condition: If Request URL (match any) */go/bunnycdn/*

Alternative method: 302 Redirect with Custom HTTP response

This will require two HTTP requests. First HTTP 200 for /go/bunnycdn/ and another 302 for the landing page. I feel this approach might be affordable if Edge rule becomes a premium feature after a certain limit in the future!

  1. Create a file /go/bunnycdn/index.html in Storage like this.
  2. Then set a response Header x-robots with value noindex, nofollow

Case 3. Using WordPress Comment & Contact Form 7 with Static Site

To handle WordPress comments and Contact Form 7 in a static site, proxy request with the origin server IP address by matching URL. BunnyCDN handle the “POST” method gracefully.

Advantages

  • ✅ No extra DNS lookup or HTTP requests
  • ✅ Privacy-Friendly
  • ✅ Amazing fast
Once again, BunnyCDN Edge Rule comes to the rescue. 😊
  • Action: Override origin
  • Description: Connect origin for Comment, Contact Form Solution
  • Origin URL: Enter Public IP address of Origin online LEMP server in the HTTPS scheme URL form.
  • Condition matching: ANY
  • Conditions: If request URL (match any) 
  • Trigger: https://example.com/wp-comments-post.php
  • Trigger: https://example.com/wp-json/contact-form-7/v1/contact-forms/1478/feedback

A few more things …

  • Replace 1478 my Form ID to own that you can find at Contact Form 7 page inside WordPress dashboard.
  • override cache time to 0 seconds set a response header Cache-Control: no-cache, no-store

⚠️ max-age=0 doesn’t mean browser is not suppose to cache, they can do due to last modified.

⚠️ Contact Form 7 uses content-type: application/json; charset=UTF-8 MIME type to make POST request on message submission where wp-comments-post.php uses text/html; charset=UTF-8 and it shouldn’t be intrepreted same as text/html type. If you add similar rule based on these MIME type then make sure to exclude these paths using MATCH NONE Condition.

Case 4. Redirect Comment Author to Thank you page

Generally when a visitor leave a comment on a WordPress Blog the POST request goes to https://example.com/wp-comments-post.php and they are redirected with HTTP status code 302 to https://example.com/permalink/?unapproved=575&moderation-hash=xyz with message “Your comment is awaiting moderation”.

In case of static site instead of serving same page over query string with HTTP 200 response, we can use the “unapproved” query string to redirect the Comment Author to Thank you page.

This is how it can be done.

Case 5. Fix Broken Background Elements

The plugin which I am going to use in this tutorial called “WP2Static” has one little issue. Sometimes, it doesn’t fetch background file from CSS.

Method 1: Use Include additional URLs feature which comes in this plugin.

Method 2: Leverage “Override origin” feature of BunnyCDN.

  1. Fix missing Contact Form 7 GIF loader

First, upload the missing file at a directory in the Storage zone file manager.

Then override the Origin URL by matching requested URL using “Edge rule”

Supporting GIF loader for Contact Form 7
  • Similarly, fix missing play button for native Video embed

Upload the file

Then override the origin to rewrite the request.

Supporting Play Button for default Video embed content

Case 6. Make WordPress Faster with HTML Caching

BunnyCDN is very flexible when it comes to setting up HTML Cache. They support a wide range of array to match request and set custom rule accordingly.

In laymen terms, when you open any site. Your browser send some information like user-agent, accept type, hostname to its server using Request Header and return some Information using Header Response for developer and browser to deal with it. In this part, we are going to talk about HTTP header Response.

  • Cache-Control: This header is used to set caching instruction for browser or proxy.
  • max-age: Hint client or proxy may use previous response body without any validation for fixed period of time.
  • s-maxage: This takes precedence over max-age to hint how long cached response a CDN/Proxy can serve.

HTML content are supposed to have freshness over time. It’s better to have short response time.

BunnyCDN supports last modified header. You can keep max-age=0 to effectively use 304 response. Browser don’t need to download whole response body for subsequent same request instead HTTP response only each time to check if browser can serve cached response or not. If not matched, then it will download fresh information with HTTP Status code 200.

We shouldn’t cache any POST request but just anything that matches text/html Content type.

  1. Action: Set Response Header
  2. Description: HTML CDN Cache Excluding POST request path
  3. Header name: Cache-Control
  4. Condition Matching: Match All
  5. Header value: max-age=0, s-maxage=25920000
  6. Conditions: If Response Header (Any): Content-type: Trigger: text/html and also add text/xml for the Sitemap.
  7. Conditions: If Request URL (Match None) : Trigger: https://example.com/wp-comments-post.php or https://example.com/wp-json/contact-form-7/v1/contact-forms/1478/feedback

Case 7. Setup Browser Caching

Static file such as CSS, JS, Images, etc doesn’t change often over time. It doesn’t mean, you should set 1 year cache. 7-8 days is enough. Also, there is one more reason why you should avoid 1 year caching.

  • In previous step (Pull zone Cache settings), concerning HTML document query string like fbclid, utm, q, etc – we have setup BunnyCDN to serve cache by ignoring all query string.
  • However, for “static content” respecting Query String is better to invalidate cache as per WordPress fundamental thing.
  • Unfortunately, this is currently not possible with BunnyCDN to deliver different response as per Query String specifically for static content. Therefore, I feel it’s better to set short term caching for static content.
  • Don’t worry about tool. The truth is quoted below.

Facebook study found that in 42% of cases, a cache is no more than 47 hours old.

code.fb.com

So, here we go.

Case 8. Enable HSTS

If previously you were using HSTS, you should continue over BunnyCDN as well. HSTS header instruct browser to always load request from the HTTPS path only. You can setup it this way for the text/html request. There is no need to do this for static resources.

  • Set a response header Strict-Transport-Security: max-age=63072000; includeSubDomains; preload for HTML requests only.

Case 9. Set Custom 404 page

  • Go to Storage zone
  • Create a new Directory called bunnycdn_errors and add a 404.html page inside it. Source: Official Documentation

Case 10. Enforce UTF-8 Charset

For some reason, BunnyCDN serve HTML content without any charset information. It’s better to pass UTF-8 Character for the HTML content.

Case 11. Serve WebP images

There are two simple ways.

  • The easiest way would be using BunnyCDN Optimizer in few clicks.
  • Using EWWW Image Optimizer plugin with JS rewrite.
  • Then run Bulk Optimization. You may skip compression and only attempt WebP conversion.
Converting JPEG to WebP
  • Check Network Console to find if your site is serving WebP images or not.

Do not enable Vary Cache by WebP in Pull Zone settings. It’s not required. Because, everything happens at client side.

Deploy Static WordPress to BunnyCDN Storage via WP2Static

WP2Static is a useful plugin created by Leon Stafford with performance, security and low operational cost in mind.

This plugin will export your WordPress in “Static version” to BunnyCDN Storage, and linked pull zone will serve it to your anonymous visitors.

The plugin comes in two flavour free and pro. This tutorial uses Free version 6.6.7 which can be downloaded from WordPress.org site.

This plugin works well in Linux environment and has ability of post-processing for optimized deployment.

Setup Guide

Follow below deployment configuration to BunnyCDN as shown below in the screenshot

  • Where will you host the optimized version of your site? Choose BunnyCDN
  • Destination URL: Set https://example.com as your primary WordPress domain

Tip: Keep your WordPress Profile username different than BunnyCDN Storage Zone name to prevent Chrome Auto-fill causing bad credential error for BunnyCDN. I learned this hard way.

WP2Static Settings

Crawling

You need to enter HTTP auth credential as we have setup in previous step while configuring NGINX server block.

  • My WP site requires Basic Auth to access
  • Basic auth user: Enter HTTP Auth username
  • Basic auth password: Enter auth password
  • Exclude certain URLs (optional): I prefer to exlcude following uneccessary path as per my requirement.
/gp_elements/
/elements/
/go/
/feed/
/sitemap.xml
Crawling

Processing

In processing tab, set as following

  • Relative URLs: It’s not important to enable it.
  • Base HREF: You do not need to enable this.
  • Remove cruft: Don’t remove WP <link> tags.

Advanced

You can keep maximum level crawling and deployment speed.

Advanced Options

Now, we are almost ready to deploy our first site. Before that, you need to understand that WP2Static uses WP_SITE_URL for crawling and deploy at BunnyCDN at storage.bunnycdn.com API hostname.

Your domain example.com, www.example.com or dev.example.com might be pointing somewhere. For smooth deployment, manually define LEMP server IP address in DNS hosts file. It can be public or private IP.

sudo -s
nano /etc/hosts

Point your Domain to LEMP Server IP

Manually pointed WordPress domain to LEMP Server IP

This little hack will speed up the process of crawling.

Deploy WordPress as Static to BunnyCDN Storage

Click on start static site export for the first deployment

Deploying Static WordPress with WP2Static

Upon successful deployment, you will see “Process completed” message.

Successfully deployed static version WordPress at BunnyCDN Storage

Next what? You can visit example.com, www.example.com to check your live site over CDN.

FAQs

Help me! Crawling or Deployment failed.

Please Check NGINX error log to see what happened. For example, it says BAD API RESPONSE, clearly means your credential was wrong.

How to fix “PHP Warning: fgets() expects parameter 1 to be resource, bool given in /home/gulshankumar.net/public_html/wp-content/plugins/static-html-output-plugin/plugin/WP2Static/SitePublisher.php on line 2” which I see in the error log?

That means you have entered wrong HTTP Auth credential.

Deployment showing older version

To avoid this problem, Set a bypass Cache rule in Cloudflare. Do not set cache by ignoring query string.

Pagination missing, how do I include?

Include it manually in the Plugin Crawling settings.pagination

Help me! WPML created page is broken!

First off, please use Subdirectory based WPML. Do not use query string method.

Second, do not deploy over development version subdomain, instead point primary domain to LEMP Stack IP in your work PC. This will do the trick. Why this work? There is a small bug in Multiple Domains which doesn’t override URL from the lang switcher widget. I have found a fix that works.

// Show alias Homepage as well
function filter_wpml_active_languages( $home_url) {
if (class_exists('MultipleDomain')) {
$multipleDomain = MultipleDomain::instance();
}
return $multipleDomain->fixUrl($home_url);
};
// add the filter
add_filter( 'wpml_url_converter_get_abs_home', 'filter_wpml_active_languages', 10 );

Why we need Multiple Domains plugin?

In case of localhost, you don’t need. If you need comment support, then yes it’s required for the proper configuration. Let me explain you basics.

Suppose, a visitor access static post at https://www.gulshankumar.net/permalink/ over CDN.

Comment POST request will goes to https://www.gulshankumar.net/wp-comments-post.php path.

Now WordPress don’t know which is your Anonymous path. It would simply return HTTP status 302 over actual WordPress path https://dev.gulshankumar.com/permalink?unapproved?comment_id&wp_hash=xyz with HTTP auth.

To resolve this problem, keep origin WordPress example.com, www.example.com as is before and later add an alias subdomain along with it using Multiple Domains Plugin for managing the WordPress dashboard.

Is my static site secure?

Of course, yes. In a static site, 99.99% requests goes to CDN. So it’s highly secure compared to WordPress.

Does it automatically purge CDN cache on Manual Deployment?

Yes. It does.

If I change my post permalink or delete a file, does it automatically reflect?

No. You need to delete manually.

Can I serve WebP images with BunnyCDN?

A clean approach would be enabling BunnyCDN optimizer. Second method, you can use EWWW plugin with “JS rewriter”, I have tested it works fine.

What are some best practices you would suggest?

Use SVG instead using Font-Awesome.

How can I speed up the process of Crawling?

Changing php-fpm pool settings from dynamic to static might help. nano /etc/php/7.4/fpm/pool.d/www.conf

Gutenberg editor says “Updating failed. Error message: The response is not a valid JSON response.”

* Whitelist /wp-json/ path in Cloudflare firewall.
* Sometime clearly cache can also fix.

Any question? Please ask at Gulshan Forum.

Comments are closed.