Tips / Nginx

Improving WordPress performance: Nginx + PHP-FPM + MySQL + Memcached + W3 Total Cache

WordPress is one of the leading publishing platforms on the planet, it’s easy to publish content, performs great on the SEO side, but there is one thing that could be better: site performance. However, for that we can do a number of things that will improve wordpress performance.

Wordpress speed

Days ago I published a post called 20 ways to Optimize WordPress Performance and while you can follow that guide as a start for the WordPress side, on this particular tutorial I will teach you how to optimize WordPress on the server side, with a simple step to step that will explain How to install Worpdress on Nginx with PHP-FPM + MySQL + W3 Total Cache plugin integrated with Memcached.

Tutorial Requirements

  • A Cloud server, VPS or Dedicated Server is needed with root access.
  • In case you don’t have a VPS/Dedicated yet, I can recommend you this great providers:
    1. A Small Orange
    2. A2 Hosting
  • CentOS Linux is the distribution we will use in this tutorial, you can apply the general guides for other distros, but file, directory names and paths may change a little bit.

Optimizing Wordpress with Nginx, PHP-FPM, MySQL, W3 Total Cache + Memcached

We are going to install WordPress on Nginx, with PHP-FPM as php parser, with MySQL server with W3 Total Cache plugin integrated with Memcached server.

Installing and configuring Nginx

First let’s see what is our OS and server architecture:

cat /etc/redhat-release ; arch

Now download the proper version of Nginx, our web server:

cd /usr/local/src

Install the repo:

rpm -i nginx-release-centos-6-0.el6.ngx.noarch.rpm

Install Nginx:

yum install nginx

Done! Nginx is now installed.

Nginx Configuration:

Create the logs directory:

mkdir /etc/nginx/logs

Edit the main configuration file /etc/nginx/nginx.conf and add your virtual host /etc/nginx/conf.d/

Replace “” with the name of your real website. This is a basic working configuration for WordPress:

nano -w /etc/nginx/nginx.conf

Delete the default content and ensure your config stays as you see below:

user  nginx;

# Replace worker_process value with the # of CPUs you have
worker_processes  4;

error_log  logs/error.log crit;

worker_rlimit_nofile  8192;

events {
worker_connections  800; # you might need to increase this setting for busy servers
use epoll; #  Linux kernels 2.6.x change to epoll

http {
server_names_hash_max_size 2048;
server_names_hash_bucket_size 512;

server_tokens off;

include    mime.types;
default_type  application/octet-stream;

sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout  10;

# Gzip on
gzip on;
gzip_min_length  1100;
gzip_buffers  4 32k;
gzip_types    text/plain application/x-javascript text/xml text/css;

ignore_invalid_headers on;
client_max_body_size    20m;
client_body_buffer_size 15m;
client_header_timeout  400;
client_body_timeout 400;
send_timeout     400;
connection_pool_size  256;
client_header_buffer_size 4k;
large_client_header_buffers 4 32k;
request_pool_size  4k;
output_buffers   4 32k;
postpone_output  1460;

# Cache most accessed static files
open_file_cache          max=10000 inactive=10m;
open_file_cache_valid    2m;
open_file_cache_min_uses 1;
open_file_cache_errors   on;

# Website virtual host includes 
include "/etc/nginx/conf.d/*.conf";

Now let’s add the virtual host file:

nano -w /etc/nginx/conf.d/

Add this content:

server {
 access_log off;
 error_log logs/ warn;

listen 80;

location ~* .(gif|jpg|jpeg|png|ico|wmv|3gp|avi|mpg|mpeg|mp4|flv|mp3|mid|js|css|wml|swf)$ {
root /path/to/your/;
 expires max;
 add_header Pragma public;
 add_header Cache-Control "public, must-revalidate, proxy-revalidate";

location / {
 root /path/to/your/;
 index index.php index.html index.htm;

# WordPress Rewrite rules
try_files $uri $uri/ /index.php?$args;

# PHP-FPM parsing
 location ~ .php$ {
 root /path/to/your/;
 try_files $uri =404;
 fastcgi_pass unix:/tmp/php5-fpm.sock;
 fastcgi_index index.php;
 fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
 include fastcgi_params;

Remember to replace /path/to/your/ for the real path of your website, it could be /var/www/ or whatever. Read more about Nginx configuration at Nginx official docs.

Installing and configuring PHP-FPM

PHP-FPM comes on the default CentOS 6.x repo, so you only need to run a simple yum command to install the required packages.

you install php-fpm

I also recommend you installing this common php modules:

yum install php-mysql php-xcache php-imap php-cli php-devel php-gd php-mbstring php-mcrypt php-pear

PHP-FPM configuration files are located at /etc/php-fpm.d/. This is a basic working configuration:

Edit the file www.conf and try to find the listen variable, then add a ; at the beginning of the line, that will comment the line and deactivate the use of the 9000 port. Then add this line:

listen = /tmp/php5-fpm.sock

It should look like:

;listen =
listen = /tmp/php5-fpm.sock

Scroll down on the same file and make sure this variables are set like as you see below:

listen.owner = nginx = nginx
listen.mode = 0666

On this three last variables we set Nginx as owner of the user and group, and set to 0666 the file socket permissions to avoid any permission issues in the future.

Ensure /tmp directory has writing permissions:

chmod 1777 /tmp -v

Ensure your website path is created:

mkdir -p /path/to/your/

Start Nginx and PHP-FPM:

service nginx start
service php-fpm start

Read more about PHP-FPM from the official documentation.


Installing and configuring MySQL server

Install the MySQL client and server

yum install mysql mysql-server

Start MySQL:

service mysqld start

Set a root password:

/usr/bin/mysqladmin -u root password 'yourpasswordhere'

Replace “yourpasswordhere” with your real MySQL root password. At /etc/my.cnf you will find the MySQL configuration file. This is a basic MySQL configuration:

nano -w /etc/my.cnf

Then ensure this variables are set as you see:

At “[mysqld]” block, add this:

# Activate query cache

# Max number of connections

# Reduce timeouts

If your VPS or Dedicated Server has more than 4GB of RAM, you can configure the query_cache_size to up to 128M without any problems on most installations.

Apply changes:

service mysqld restart

Btw, remember to add a database to use with your WordPressd installation:

mysql -u root -p

Now introduce the MySQL root password you chosen before:

Create the database name

create database dbname;

Add user and password

GRANT ALL PRIVILEGES ON dbname.* TO 'user'@'localhost' IDENTIFIED BY 'yourpassword';
flush privileges;

Exit the MySQL terminal


Of course, remember to replace the database name (dbname), mysql user (user) and password (yourpassword) with the real ones you will use in your WordPress installation.

Installing and configuring Memcached

Memcached is a memory based cache system that will cache your most common WordPress operations, allowing you to reduce server load and gain faster load speeds. Let’s install Memcached.

Add the Epel repo into your system:

cd /usr/local/src
rpm -i epel-release-6-8.noarch.rpm

Install Memcached system daemon and the PHP-Memcache module:

yum install memcached -y
pecl install memcache

If you see you have a file called /etc/php.d/memcache.ini, then everything is ready. If you don’t, you need to add the extension manually:

Add memcache extension into the PHP configuration:

echo "" >> /etc/php.ini

Restart the service to apply changes:

service php-fpm restart

This is a basic memcached configuration. This config depends on how much RAM you have available. On this example we will assign 512 MB, but tweak it as you need:

nano -w /etc/sysconfig/memcached

Configuration example with 512 MB of cache and 512 max connections:


Start the memcached service:

service memcached start

Finally, let’s install Worpdpress:

cd /path/to/your/
tar -xvpzf latest.tar.gz
mv wordpress/* ./
rm worpress -rf
cp wp-config-sample.php wp-config.php -fv

Now, edit the WP configuration file:

nano -w wp-config.php

And add your MySQL information, example:

/** The name of the database for WordPress */define('DB_NAME', 'dbname');

/** MySQL database username */define('DB_USER', 'user');

/** MySQL database password */define('DB_PASSWORD', 'yourpassword');

/** MySQL hostname */define('DB_HOST', 'localhost');

Replace “db”, “user” and “yourpassword” with the real name of your MySQL connection information you previously created when we did the MySQL server setup. DB_Host almost 99% of the times uses ‘localhost’ as the value, if you don’t have a remote MySQL server you don’t need to change this.

Now load your WordPress website from your browser at:

Final step:

Move to your WP Admin – Plugins and install W3 Total Cache.

If you have troubles installing due to the lack of a FTP server, let’s add one quickly:

yum install proftpd -y

Add a FTP user to use with your WordPress website and change the owner of all files:

useradd -d /path/to/your/ username
chown username.username /path/to/your/ -R

Replace “/path/to/your/” and “username” with your real paths and username you want to create.

Set a password for the new user:

passwd username

Start the FTP server:

service proftpd start

Once you have W3 Total Cache installed, in the left menu you will find a section called Performance, click on General Settings. Then set Page Cache, Database Cache and Object Cache to use Memcached server. Remember to activate Browser cache also.

Everything is ready now, at this point you should have WordPress running on Nginx, PHP-FPM, MySQL, W3 Total Cached integrated with Memcached.

To get the best possible performance I will always recommend the use of SSD disks, which are 10x times or more faster than tradditional SATA hard disks.

Need extra performance for WordPress?

Start using Cloudflare, it works great with WordPress + Nginx and can give your site an extra boost with it’s CDN network for static files.


Popular search terms:

  • ubuntu nginx php-fpm memcached
  • php-fpm memcached
  • php fpm wordpress
  • best performance centos 7

Esteban Borges

Linux Geek, Webperf Addict, Nginx Fan. CTO @Infranetworking

  • Robin

    The only real reason to use memcached is if you are running an application or website that lives on multiple separate servers – loadbalancing iow.

    Most people are not and don’t need it. Therefore, APC is the opcode cache solution in the vast majority of cases – unless I’m missing something?

    here’s a good overview for those interested:

  • Anders

    I follow this setup for Nginx and PHP-FPM but I installed OPcache instead for Memcached
    Lower the number of child processes in FPM to work around 250MB on my 1GB memory KVM

    Blazing fast comparing to Apache.

    Thank you, /Anders

  • Thanks for detailed article. For me Nginx + FPM + WP Super Cache also has worked well. I stored the super cache directory in tmpfs partition in RAM. It gave good performance too.