Guide to Increasing Performance of WordPress Websites

In this post I will go step by step through optimizing PHP and WordPress to reduce page load times and increase requests/second of your website.

WordPress is used on over 42% of all websites on the global internet. Considering that there are over 1.1 billion websites this comes to over 460 million website using WordPress to serve content to their customers.

Actual and perceived performance of a website is a major factor in securing and keeping visitors to your website. With Google search engine being the major source of traffic generation and therefore routing, they consider any websites’ page load time to be a major factor in SERP ranking.

Assumptions and Pre-Requisites

The only thing I am assuming before starting on this tutorial is that you have admin rights on the machine you are working on. The machine could be a physical machine, such as your desktop or laptop or a cloud based server.

I will provide instructions on how to configure your software on both Linux and Windows.

Let’s start…

Install Apache Web Server

If you have a Linux instance running then setting up Apache is easy. Use the command below to setup Apache web server.

sohail@d1:~# sudo apt install apache2

Now we need to enable mod_rewrite. Use these command to enable it.

sohail@d1:/etc$ sudo a2enmod rewrite
Enabling module rewrite.
To activate the new configuration, you need to run:
  systemctl restart apache2

sohail@d1:/etc$ sudo service apache2 restart
sohail@d1:/etc$ 

Make sure the server is up and running by going to the browser and going to URL http://localhost. You will see the following webpage.

Apache HTTPD default page

Install MySQL

Install MySQL as that is a required component for WordPress. In this step, I will install MySQL and then create a new user for WordPress and an actual database for it to use.

sohail@d1:~$ sudo apt install mysql-server

Now that MySQL has been installed I will go create a new user for WordPress and then will create a WordPress database and give permissions to the newly created user.

sohail@d1:~$ sudo mysql
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 12
Server version: 8.0.30-0ubuntu0.22.04.1 (Ubuntu)

Copyright (c) 2000, 2022, Oracle and/or its affiliates.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> CREATE USER 'wp'@'localhost' IDENTIFIED WITH authentication_plugin BY 'abc123';
ERROR 1524 (HY000): Plugin 'authentication_plugin' is not loaded
mysql> CREATE USER 'wp'@'localhost' IDENTIFIED BY 'abc123';
Query OK, 0 rows affected (0.01 sec)

mysql> CREATE DATABASE wordpress CHARACTER SET UTF8MB4;
Query OK, 1 row affected (0.00 sec)

mysql> GRANT ALL ON wordpress.* to wp@localhost;
Query OK, 0 rows affected (0.00 sec)

mysql> flush privileges;
Query OK, 0 rows affected (0.00 sec)

mysql> exit

Here I have created a new user wp with the password abc123 (yes really creative here).

Then I proceeded to create a database wordpress followed by giving the user wp permissions to use it. Finally, I flushed permissions.

Install PHP and Update Settings

On Ubuntu, you can install PHP using the following command.

sohail@d1:~$ sudo apt install php

I will then install the following additional PHP extensions.

sohail@d1:~$ sudo apt install php-curl php-mbstring php-zip php-imagick php-json php-xml

sohail@d1:/var/www$ sudo apt install libapache2-mod-php php-mysql

Not all of these are required but I still like to install them as these are usually needed by different themes and plugins I use.

Now PHP is installed. To make sure everything is running as expected I will add an index.php page with phpinfo() to ensure the installation is working.

sohail@d1:~$ cd /var/www/html

sohail@d1:/var/www/html$ vi index.php


###### Enter the following lines in the index.php file ######
<?php
phpinfo();

I have used vi editor. You can use whichever editor you are comfortable with.

To test if my setup is working, I will go and check the page at http://localhost/index.php.

Apache PhpInfo() Output Example

Great…all looking good for now.

Install WordPress

This is a multi steps process. First I will add my domain name to hosts file. Then I will create create a virtual host in Apache. Finally I will copy WordPress files to location specified in virtual host .conf file before starting the install.

Let’s start…

Update Hosts file

On Linux the file is /etc/hosts whereas on Windows it is C:\Windows\system32\drivers\etc\hosts. Open the file and add the following entry.

127.0.0.1 wordpress.local

Save and close the file.

If you ping the file from console (command window), you should see the following.

sohail@d1:/etc$ ping wordpress.local
PING wordpress.local (127.0.0.1) 56(84) bytes of data.
64 bytes from localhost (127.0.0.1): icmp_seq=1 ttl=64 time=0.025 ms
64 bytes from localhost (127.0.0.1): icmp_seq=2 ttl=64 time=0.051 ms
64 bytes from localhost (127.0.0.1): icmp_seq=3 ttl=64 time=0.032 ms

Install Apache Virtual Host for Example Domain

Our domain is added to the hosts file. Now we are ready to create a virtual host for it so Apache HTTPD know where to go to serve pages.

On Linux go to the following folder and add a new virtual host by creating a file wordpress.conf.

sohail@d1:/var/www/html$ cd /etc/apache2/sites-available/
sohail@d1:/etc/apache2/sites-available$ vi wordpress.conf

Add the following content to wordpress.conf.

<VirtualHost *:80>
	ServerName  wordpress.local
	ServerAdmin [email protected]
	DocumentRoot /var/www/wordpress

	<Directory /var/www/wordpress>
		Options FollowSymLinks MultiViews
		AllowOverride All
		Order allow,deny
		allow from all
	</Directory>


	ErrorLog ${APACHE_LOG_DIR}/error.log
	CustomLog ${APACHE_LOG_DIR}/access.log vhost_combined
</VirtualHost>

Create files to the wordpress folder. The path will be as set in the DocumentRoot above.

Now copy WordPress files to the folder pointed to in wordpress.conf. In my case it is /var/www/wordpress.

Enter the command as shown below.

sohail@d1:/etc/apache2/sites-available$ cd /var/www

sohail@d1:/var/www$ sudo wget https://wordpress.org/latest.zip
--2022-10-22 14:36:04--  https://wordpress.org/latest.zip
Resolving wordpress.org (wordpress.org)... 198.143.164.252
Connecting to wordpress.org (wordpress.org)|198.143.164.252|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 22774224 (22M) [application/zip]
Saving to: ‘latest.zip’

latest.zip                                         100%[===============================================================================================================>]  21.72M  6.72MB/s    in 3.2s    

2022-10-22 14:36:08 (6.72 MB/s) - ‘latest.zip’ saved [22774224/22774224]

sohail@d1:/var/www$ sudo unzip -q latest.zip 

sohail@d1:/var/www$ sudo chown -R www-data wordpress/

sohail@d1:/var/www$ sudo chgrp -R www-data wordpress/

With WordPress files in place, now I am ready to enable the config and restart Apache.

sohail@d1:/var/www$ sudo a2ensite wordpress.conf 
Enabling site wordpress.
To activate the new configuration, you need to run:
  systemctl reload apache2

sohail@d1:/var/www$ sudo service apache2 restart

Installing WordPress

With successful setup of Apache HTTPD, MySQL and PHP, my next step is to install WordPress.

Open the URL in the browser and go to http://wordpress.local.

Since we are doing just a standard install, simply follow instructions shown as is. Copy the following information on the settings page.

WordPress Settings page during installation.

Once the installation has completed open the URL http://wordpress.local and you will be your sparkling new website running.

With the default install there is only a single post Hello world! is showing. To do performance testing I will update the content of this post and add about 4,000 bytes of text to it. If you are following the exact steps you may want to just copy content from this page on my GitHub.

My Test Environment

Test machine

  • Operating system: Windows 10 Professional 64 bits
  • CPU: AMD ThreadRipper 1920X 12-core processor.
  • RAM: 32 GB
  • Storage: 8 TB

WordPress VM

  • Operating system: Ubuntu 22.04
  • CPU: 4 cores allocated
  • RAM: 4 GB
  • Storage: 100 GB

Test tool: Apache AB running from Windows host.

WordPress Performance Testing – First Run

The first thing I want to do is establish baseline performance numbers for WordPress with out of the box setting for Apache, MySQL, PHP and WordPress.

Note: I have noticed that 22.04 has OpCache enabled by default. Not sure if I turned it on by mistake by it is working. For this test I am going to run the following command before starting my test.

sohail@d1:/etc/php/8.1/mods-available$ sudo phpdismod opcache

sohail@d1:/etc/php/8.1/mods-available$ sudo service apache2 restart

My test URL: http://wordpress.local/2022/10/22/hello-world/

From command line window from my host machine I enter the following ab command.

C:\apps\apache\httpd\bin>ab.exe -n 1000 -c 5 http://wordpress.local/2022/10/22/hello-world/

The result summary for the first run below.

WordPress Performance Test Results Unoptimized First Run

Enabling PHP OpCache

Before going to the next performance run, I want to enable PHP OpCache. This should increase performance of the WordPress install.

So let’s start…

Install/Enable PHP OpCache on Ubuntu and Windows

With latest versions of Ubuntu OpCache is already installed and enabled. Since in previous versions it was not installed I had to first install it and then enable it.

Regardless since I did disable the OpCache in the first step, I will enable it here and restart Apache HTTPD.

sohail@d1:/etc/php/8.1/mods-available$ sudo phpenmod opcache

sohail@d1:/etc/php/8.1/mods-available$ sudo service apache2 restart

WordPress Performance Testing – Second Run

Second run is similar to the first, except that I now have enabled OpCache. Below are results of the AB test.

WordPress Performance Test Results with OpCache Second Run

Results

Total time taken

The performance of the website has gone up significantly. From taking 56.161 seconds to complete the first run fetching 1,000 requests the time has gone down to 17.944 seconds.

Time/Request

Another significant improvement here. Time/request has also come down to 89.718 ms from 280.806 ms.

Third Test Run Setup

For this final test run, I need to setup the following.

  • Redis server.
  • Add PHP extension for Redis.
  • Add Redis Object cache to WordPress.

Redis Server Install

sohail@d1:~$ sudo apt install redis-server

Install PHP Extension for Redis

sohail@d1:~$ sudo apt install php-redis

sohail@d1:~$ sudo service apache2 restart

Install WordPress Redis Object Cache Plugin

Login to your WordPress and in Admin go to Plugins->Add New, and enter redis object cache in the search box.

Redis Object Cache Plugin WordPress Install

Install the plugin and activate it.

To enable object cache you will need to go to Settings->Redis and click on Enable Object Cache button.

WordPress Performance Testing – Third Run

Now I have both PHP OpCache and Redis server installed with WordPress able to use the benefits of this extra layer of caching using the newly added plugin.

I am going to test the same URL in exactly the same manner to see if I can get additional performance improvements.

Here are my results.

WordPress Performance Test Results with OpCache and Redis Third Run

Strange. I did not notice significant performance improvements. Request/second has gone up by 1.

I expected a lot more… Well maybe the cache plugin is not working. I went an looked at Redis and found that the plugin is working.

sohail@d1:~$ redis-cli
127.0.0.1:6379> keys *
 1) "wp:wp_theme_relationships:5"
 2) "wp:post_tag_relationships:1"
 3) "wp:comment:1"
 4) "wp:comment:get_comments-46612f2dd3b604b784c3eb3dac699d60-0.30692800 1666479464"
 5) "wp:posts:2"
 6) "wp:default:is_blog_installed"

There were many more entries but I only copied a subset to show that Redis cache is working. There maybe other factors at play such as lack of resources on the VM running the website.

I am going to increase resources for the virtual machine and re-run the tests.

Well, I did increase resources to the following values:

  • RAM: 8 GB
  • vCPU: 8 cores

What I found was that performance did go up. Another 18% or so. But running the test from Step 2 also resulted in increase in performance.

Conclusion of Testing

What I found is that enabling PHP OpCache significantly increases performance of a PHP based website.

Adding Redis cache to the mix, in scope of WordPress only with the plugin did not get me any significant improvement in performance. I am assuming it may help as the load on the site grows. This is where I will do further testing to figure out the scenario where Redis with WordPress can add value.

Lookout for an update on this…


Bonus Performance Section Using Reverse Proxy

Ok, in all of the testing I have done above, I was happy until I moved to the third run where I had both PHP OpCache enabled as well as a Redis server installed with a supporting WordPress Redis Object Cache plugin.

I thought why not go one step further and put an Nginx reverse proxy with caching enabled in front of the web server where I installed WordPress.

Check out my post on setting up Nginx as a reverse proxy and cache in front of Apache

Well, that is exactly what I did.

Note: I did adjust RAM and vCPU to match earlier test results so my test numbers are meaningful.

Shown below are the numbers I have with the following options enabled.

  • PHP OpCache enabled.
  • Nginx Reverse Proxy with Caching settings enable.

My test run with AB is the same as well using the following command.

ab.exe -n 1000 -c 5 http://wordpress.local/2022/10/22/hello-world/
WordPress Performance Test Results with OpCache and Nginx Fourth Run

Conclusion (Final)

Oh, just plain awesome. Adding a reverse proxy with caching, and I will focus on the caching part, the performance shoots up crazy. From approximately 56 request/second it has gone up to 994 requests/second. That is an increase of over 1700%.

1st run
No Caching
2nd run
PHP OpCache
3rd run
PHP OpCache and Redis
Bonus run
PHP OpCache and RP Caching
Total time for test56.161 seconds17.944 seconds17.64 seconds1.005 seconds
Requests / Second17.8155.7356.69994.87
Time / Request280.806 ms89.718 ms88.198 ms5.026 ms
Time / Request (across all threads)56.161 ms17.944 ms17.64 ms1.005 ms

Sure in actual real life scenarios the improvements may be lower than this but I still expect significant improvements in performance by using a reverse proxy with Cache.

I do hope you found this post useful. Let me know if you have any questions on this.

Learn how to Setup Nginx as Reverse Proxy Server with Caching

Leave a Comment