This Old Blog

WordPress Renovation – Server Performance Tuning

This post is part of a series of posts detailing the renovation of my WordPress blog, http://byronpate.com. In my last post, I walked through steps to Nginx, PHP, and Percona setup on my new Vultr server. When I wrapped up that post I had everything setup and ready to go to host a WordPress website. In this article, I’m going to go a little deeper into server performance tuning for WordPress. 

Server Performance Tuning for WordPress

Now I’m going to do some tuning of Nginx, Percona, and PHP to help maximize performance. Before I jump into the updates. I’m starting with a default Nginx server block that looks like this:

server {
    listen 80;
    listen [::]:80;
    root /var/www/byronpate;
    index index.php index.html index.htm;

    server_name byronpate.com www.byronpate.com www2.byronpate.com;

    location ~ /.well-known {
                allow all;
    }

    location / {
                try_files $uri $uri/ /index.php?$args;
    }

    location ~ \.php$ {
        try_files $uri =404;
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass unix:/run/php/php7.0-fpm.sock;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include fastcgi_params;
    }

}

Enable Client Side Caching

I’m going to enable Client Side Caching to make sure that browsers cache images, stylesheets, and javascript. This is an important part of server performance tuning because it prevents static content from being downloaded repeatedly. I’ll add the following location block into my Nginx server block that tells the client that this content expires after 1 year.

location ~* \.(jpg|jpeg|gif|png|ico|css|js)$ {
  expires 365d;
}

Enable TLS and HTTP/2 in Nginx

I want to make sure I’m using HTTP/2 for my website. To support HTTP/2 I need to enable TLS. In my last article I installed Nginx 1.10 and Let’s Encrypt, and in this version, all that’s needed is to enable HTTP/2 in my server block as follows.

server {
    listen 80;
    listen [::]:80;
    root /var/www/byronpate;
    index index.php index.html index.htm;

    server_name byronpate.com www.byronpate.com www2.byronpate.com;

    location ~ /.well-known {
                allow all;
    }

    location / {
                try_files $uri $uri/ /index.php?$args;
    }

    location ~* \.(jpg|jpeg|gif|png|ico|css|js)$ {
  	expires 365d;
    }

    location ~ \.php$ {
        try_files $uri =404;
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass unix:/run/php/php7.0-fpm.sock;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include fastcgi_params;
    }

}

server {
    listen 443 ssl http2;
    listen [::]:ssl 443 http2;
    root /var/www/byronpate;
    index index.php index.html index.htm;

    server_name byronpate.com www.byronpate.com www2.byronpate.com;

    include snippets/ssl-byronpate.com.conf;
    include snippets/ssl-params.conf;

    location ~ /.well-known {
                allow all;
    }

    location ~* \.(jpg|jpeg|gif|png|ico|css|js)$ {
  	expires 365d;
    }

    location / {
                try_files $uri $uri/ /index.php?$args;
    }

    location ~ \.php$ {
        try_files $uri =404;
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass unix:/run/php/php7.0-fpm.sock;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include fastcgi_params;
    }

}

 Nginx Server Tuning

Now I’m going to update the main Nginx configuration. I’m going to apply the following server performance tuning to Nginx. In the Events block increase the worker_connections to 1024, enable multi_accept and epoll.

events {
  worker_connections 1024;
  multi_accept on;
  use epoll;
}


Next, I’ll increase the default Nginx timeouts.

client_body_timeout 12;
client_header_timeout 12;
keepalive_timeout 15;
send_timeout 10;

I’m going to disable Nginx Access Logging. I use Google Analytics to track activity, so the Access Logs are not really used. Error messages are still logged to error.log. But by disabling access logging, I reduce additional io on the server.

access_log off;

server performance tuningLast but not least I’m going to enable Gzip HTTP Compression by making the following changes to /etc/nginx/nginx.conf. Compression can have a huge performance benefit and its very easy to enable in Nginx. After restarting Nginx, you can confirm if Gzip is enabled using http://checkgzipcompression.com/

gzip on;
gzip_disable "msie6";
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_buffers 16 8k;
gzip_http_version 1.1;
gzip_min_length 256;
gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript application/vnd.ms-fontobject application/x-font-ttf font/opentype image/svg+xml image/x-icon;

Percona Server Performance Tuning

I’m going to make a few tweaks to the Percona MySQL configuration. I’m making the following changes that will help optimize my server for running WordPress:

  • skip_name_resolve – Since all of my SQL connections will be coming from localhost I don’t need to enable DNS resolution. Turning this off will help with response time.
  • query_cache_size – This is a well-known bottleneck on queries, so it’s recommended to disable it.
  • innodb_flush_log_at_trx_commit – WordPress is mostly database reads, with a few updates and adds when authoring. Given that the transactional nature of the website is very low I’m turning off full ACID compliance to improve performance.
  • innodb_buffer_pool_size – One of the more important settings, this sets how much memory is allocated to table and index data caching. Setting it as high as possible is the best option. My server has 768MB, so I’m setting the buffer pool to 200MB or roughly 25% of the server’s memory.

To apply these changes I’m going to edit /etc/mysql/percona-server.conf.d/mysqld.cnf as follows:

[mysqld]
user   = mysql
pid-file = /var/run/mysqld/mysqld.pid
socket   = /var/run/mysqld/mysqld.sock
port   = 3306
basedir    = /usr
datadir    = /var/lib/mysql
tmpdir   = /tmp
lc-messages-dir  = /usr/share/mysql
explicit_defaults_for_timestamp

# Instead of skip-networking the default is now to listen only on
# localhost which is more compatible and is not less secure.
bind-address = 127.0.0.1

log-error    = /var/log/mysql/error.log

# Recommended in standard MySQL setup
sql_mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES

# Disabling symbolic-links is recommended to prevent assorted security risks
symbolic-links=0

skip-name-resolve
query_cache_size = 0
innodb_flush_log_at_trx_commit = 0
innodb_buffer_pool_size=200M

PHP Tuning

Finally, for PHP 7 I’m going to make several updates. The first section includes the following changes:

  • max_execution_time – Set the PHP execution time to 600 seconds, the default is 0 or unrestricted.
  • memory_limit – Set the memory limit to 128MB
  • error_reporting – Disable verbose error reporting
  • display_errors  – Disable showing error messages
  • log_errors – Disable error logging
  • user_ini.filename – Disable user-defined php.ini files
  • realpath_cache_size – Increase the number of open PHP files cached. For WordPress, this is a helpful setting.
  • cgi.check_shebang_line – Disable PHP CGI

The opcache settings enable and optimize OPcache. OPcache is an important feature in PHP7. It improves PHP performance by storing precompiled script bytecode in memory cache. Cached PHP scripts do not need to be loaded from disk and parsed on each request. I’m increasing the amount of memory that OPcache can use so that more of my WordPress files are stored in cache.

I updated /etc/php/7.0/fpm/php.ini to apply the following changes:

max_execution_time=600
memory_limit=128M
error_reporting=0
display_errors=0
log_errors=0
user_ini.filename=
realpath_cache_size=2M
cgi.check_shebang_line=0

opcache.enable=1
opcache.enable_cli=1
opcache.save_comments=0
opcache.fast_shutdown=1
opcache.validate_timestamps=1
opcache.revalidate_freq=60
opcache.use_cwd=1
opcache.max_accelerated_files=100000
opcache.max_wasted_percentage=5
opcache.memory_consumption=128
opcache.consistency_checks=0

In my next update I’ll start updating my WordPress website, including changing the theme.

Update - 2016.09.28Be sure to read the other articles in the This Old Blog series:

Byron Pate
I am Byron Pate, and I’m a technology enthusiast. I work in Atlanta, Georgia as a Solution Architect. I write about technology, troubleshooting, and infrastructure.
We will be happy to hear your thoughts

      Leave a reply