Optimize Wordpress, Nginx and PHP to Reduce Server Response Time

2018-09-10 1564 words 8 mins read

Yesterday my son made his first blog in life according to the Step-by-step Tutorial Show How to Build a Nice WordPress Blog with Perfect 100 Score of Google Pagespeed Insights and A Rating of SSL Certificate within 2 Hours I wrote earlier.

Because the cost of the server is determined by his own way of making money, he is currently purchasing Vultr's cheapest server, $3.50 per month, 1 CPU, and only 512MB of the smallest server.

WordPress is a very memory-intensive CMS system. It is estimated that 512MB will be not enough to run wordpress after adding several plug-ins and templates.

The response time of the server may not meet the requirements of Google Speed ​​Insights.

Just like my own blog, the initial speed is not slow, but after using DIVI and adding a lot of other plug-ins, the test results in Google Speed ​​Insights shows the server response time is more than 200ms.

The speed of the website is import for visitors. This must be solved. After some Google, I found a solution.

This solution has soem references from Howtoforge's post Configuring Your LEMP System (Linux, nginx, MySQL, PHP-FPM) For Maximum Performance , Thanks for that.

But Howtoforge wrote that post a few years ago, mainly for PHP5, I changed some code for PHP 7.2 and wordpress issue in my tutorial.

 

I will set some code which need you to modify to red color.

Reduce the disk I/O rate


Ok, first log in to the fxdiary.com server remotely.
ssh jesse@fxdiary.com

Add noatime and nodiratime for the mount, this is to reduce the disk I/O rate, the command is as follows:
sudo nano /etc/fstab

After opening the file, find the following
errors=remount-ro 0 1

Modify it to the red part
errors=remount-ro,noatime,nodiratime,usrjquota=quota.user,grpjquota=quota.group,jqfmt=vfsv0 0 1

Save and exit, then run
sudo mount -o remount /

Configure the nginx conf file


Run:
sudo nano /etc/nginx/nginx.conf

Modify as follows
http {
...
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 2;
types_hash_max_size 2048;
server_tokens off;
...
}

Keepalive_timeout changed from the default value of 65 seconds to a more reasonable 2 seconds

Open file cache
http {
...
##
# File Cache Settings
##

open_file_cache max=5000 inactive=20s;
open_file_cache_valid 30s;
open_file_cache_min_uses 2;
open_file_cache_errors on;
...
}

Enable caching of SSL sessions
http {
...
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2; # Dropping SSLv3, ref: POODLE
ssl_prefer_server_ciphers on;

...
}

Turn on fastCGI cache
http {
...
## Nginx FastCGI Cache
fastcgi_cache_path /var/cache/nginx/ levels=1:2 keys_zone=cachezone:10m max_size=2g inactive=60m;
fastcgi_cache_key $scheme$request_method$host$request_uri;
fastcgi_cache_lock on;
fastcgi_cache_revalidate on;
fastcgi_cache_background_update on;
fastcgi_cache_use_stale error timeout invalid_header updating http_500;
fastcgi_cache_valid any 60m;
fastcgi_pass_header Set-Cookie;
fastcgi_pass_header Cookie;
fastcgi_ignore_headers Cache-Control Expires Set-Cookie;

...
}

The /var/cache/nginx/cache directory must exist and have permission to write, so after saving the disk, run the following command
sudo mkdir /var/cache/nginx

sudo chown www-data:www-data /var/cache/nginx

So nginx.conf is modified, I posted the full text of nginx.conf on fxdiary.com for reference.
user www-data;
worker_processes auto;
pid /run/nginx.pid;
include /etc/nginx/modules-enabled/*.conf;

events {
worker_connections 768;
# multi_accept on;
}

http {

##
# Basic Settings
##

sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 2;
types_hash_max_size 2048;
server_tokens off;

# server_names_hash_bucket_size 64;
# server_name_in_redirect off;

open_file_cache max=5000 inactive=20s;
open_file_cache_valid 30s;
open_file_cache_min_uses 2;
open_file_cache_errors on;
include /etc/nginx/mime.types;
default_type application/octet-stream;

##
# SSL Settings
##
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;

##
# Logging Settings
##

access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;

##
# Gzip Settings
##

gzip on;

gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_buffers 16 8k;
gzip_http_version 1.1;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;

##
## Nginx FastCGI Cache
fastcgi_cache_path /var/cache/nginx/ levels=1:2 keys_zone=cachezone:10m max_size=2g inactive=60m;
fastcgi_cache_key $scheme$request_method$host$request_uri;
fastcgi_cache_lock on;
fastcgi_cache_revalidate on;
fastcgi_cache_background_update on;
fastcgi_cache_use_stale error timeout invalid_header updating http_500;
fastcgi_cache_valid any 60m;
fastcgi_pass_header Set-Cookie;
fastcgi_pass_header Cookie;
fastcgi_ignore_headers Cache-Control Expires Set-Cookie;
# Virtual Host Configs
##

include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
}

Configure the virtual host conf


Run:
sudo nano /etc/nginx/sites-available/fxdiary.com

Added fastcgi caching function, but need to be set to log into WordPress as Admin or Editor with no cache.
location ~ \.php$ {

include snippets/fastcgi-php.conf;
fastcgi_pass unix:/var/run/php/php7.2-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;

set $skip_cache 0;
# POST requests and url's with a query string should always skip cache
if ($request_method = POST) {
set $skip_cache 1;
}
if ($query_string != "") {
set $skip_cache 1;
}
# Don't cache url's containing the following segments
if ($request_uri ~* "/wp-admin/|/xmlrpc.php|wp-.*.php|/feed/|index.php|sitemap(_index)?.xml") {
set $skip_cache 1;
}
# Don't use the cache for logged in users or recent commenters
if ($http_cookie ~* "comment_author|wordpress_[a-f0-9]+|wp-postpass|wordpress_no_cache|wordpress_logged_in") {
set $skip_cache 1;
}
# (for some reason, add_header fails if included in prior if-block)
if ($skip_cache = 1) {
add_header Set-Cookie "_mcnc=1; Max-Age=2; Path=/";
add_header X-Microcachable "0";
}
# Bypass cache if no-cache cookie is set
if ($http_cookie ~* "_mcnc") {
set $skip_cache 1;
}

fastcgi_cache_bypass $skip_cache;
fastcgi_no_cache $skip_cache;
fastcgi_cache cachezone;
include fastcgi_params;
fastcgi_buffer_size 128k;
fastcgi_connect_timeout 60s;
fastcgi_send_timeout 60s;
fastcgi_read_timeout 60s;
fastcgi_buffers 256 16k;
fastcgi_busy_buffers_size 256k;
fastcgi_temp_file_write_size 256k;
}

This is full file for  /etc/nginx/sites-available/fxdiary.com:
server {
listen 80;
listen [::]:80; ## listen for ipv6

server_name fxdiary.com www.fxdiary.com;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl;
listen [::]:443 ssl; # managed by Certbot
server_name fxdiary.com www.fxdiary.com;

root /var/www/html;
index index.php index.html index.htm index.nginx-debian.html;
location = /favicon.ico { log_not_found off; access_log off; }
location = /robots.txt { log_not_found off; access_log off; allow all; }
location ~* \.(css|gif|ico|jpeg|jpg|js|png|woff)$ {
expires max;

log_not_found off;
}
location / {

try_files $uri $uri/ /index.php$is_args$args;
}

location ~ \.php$ {

include snippets/fastcgi-php.conf;
fastcgi_pass unix:/var/run/php/php7.2-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;

set $skip_cache 0;
# POST requests and url's with a query string should always skip cache
if ($request_method = POST) {
set $skip_cache 1;
}
if ($query_string != "") {
set $skip_cache 1;
}
# Don't cache url's containing the following segments
if ($request_uri ~* "/wp-admin/|/xmlrpc.php|wp-.*.php|/feed/|index.php|sitemap(_index)?.xml") {
set $skip_cache 1;
}
# Don't use the cache for logged in users or recent commenters
if ($http_cookie ~* "comment_author|wordpress_[a-f0-9]+|wp-postpass|wordpress_no_cache|wordpress_logged_in") {
set $skip_cache 1;
}
# (for some reason, add_header fails if included in prior if-block)
if ($skip_cache = 1) {
add_header Set-Cookie "_mcnc=1; Max-Age=2; Path=/";
add_header X-Microcachable "0";
}
# Bypass cache if no-cache cookie is set
if ($http_cookie ~* "_mcnc") {
set $skip_cache 1;
}

fastcgi_cache_bypass $skip_cache;
fastcgi_no_cache $skip_cache;
fastcgi_cache cachezone;
include fastcgi_params;
fastcgi_buffer_size 128k;
fastcgi_connect_timeout 60s;
fastcgi_send_timeout 60s;
fastcgi_read_timeout 60s;
fastcgi_buffers 256 16k;
fastcgi_busy_buffers_size 256k;
fastcgi_temp_file_write_size 256k;
}

location ~ /\.ht {
deny all;
}

ssl_certificate /etc/letsencrypt/live/fxdiary.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/fxdiary.com/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;

}

PHP-FPM emergency settings


if suddenly crashed, php can automatically restart. Run command
sudo nano /etc/php/7.2/fpm/php-fpm.conf

Change the emergency settings to the following:
; If this number of child processes exit with SIGSEGV or SIGBUS within the time
; interval set by emergency_restart_interval then FPM will restart. A value
; of '0' means 'Off'.
; Default Value: 0
emergency_restart_threshold = 10
; Interval of time used by emergency_restart_interval to determine when
; a graceful restart will be initiated. This can be useful to work around
; accidental corruptions in an accelerator's shared memory.
; Available Units: s(econds), m(inutes), h(ours), or d(ays)
; Default Unit: seconds
; Default Value: 0
emergency_restart_interval = 1m

CTRL-X saves and exits.

To reduce network overhead, you can replace TCP with UNIX socket. Run the following command:
sudo nano /etc/php/7.2/fpm/pool.d/www.conf

Open the www.conf file and find the following statement, change to the red label section
; Set permissions for unix socket, if one is used. In Linux, read/write
; permissions must be set in order to allow connections from a web server. Many
; BSD-derived systems allow connections regardless of permissions.
; Default Values: user and group are set as the running user
; mode is set to 0660
listen.owner = www-data
listen.group = www-data
listen.mode = 0660

After changing to the socket mode, you may often encounter 502 errors, you need to increase the number of connections per socket. Run the following command
sudo nano /etc/sysctl.conf

Add the file to the last line
net.core.somaxconn = 4096

CTRL-X saves and exits, then run the following command to activate
sudo sysctl -p

Now all configuration is complete, run the following command to restart php and nginx
sudo service php7.2-fpm restart

sudo service nginx restart

Checking the results


Check with Google Pagespeed Insights again. The "Reduce server response time" optimization suggestiong is removed.

With the setting of fastCGI cache, the website speed has been increased greatly.

I tested this website with pingdom, installed with commercial template Divi and lots of heavy-duty plugins, and the network speed performance is still good.

The best of all, this site is only used  the $5/m vps at current time.



Update:

For bloggers who always update posts frequently, using cache is also a double-edged sword. It is common to modify and modify, but the cache will save the original post, for the visitors, an updated version is not visible within a certain time limit.

Every time you update a post, you need to delete the cache. For our configuration, run the following command after logging in to the remote server:
sudo rm -rf /var/cache/nginx/*

 

Can it be automatically implemented, automatically purge the cache after updating the content?

I found a free plug-in. Nginx Cache

The setup is also very simple, just paste our cache directory.



Ok, edit it and save it. Open it with other devices to see this post and update it. The plugin has no problem.

You can safely edit and modify later, without worrying about cache cleanup again.

This is the benefit of "automation."

 

author

Authored By Jesse Lau

A freelancer living in New Zealand, engaged in website development and program trading. Ever won 1st ranking twice in the Dukascopy Strategy Contest. This article is licensed under a Creative Commons Attribution 4.0 International License.

We notice you're using an adblocker. If you like our webite please keep us running by whitelisting this site in your ad blocker. We’re serving quality, related ads only. Thank you!

I've whitelisted your website.

Not now

Post Your Comments Here:

Our website uses cookies to improve your user experience. If you continue browsing, we assume that you consent to our use of cookies. More information can be found in our privacy policy Got it