Hight load VPS and WordPress optimization

Posted on : by : Amigo

This manual is the result of our WordPress and VPS optimization for high load projects. By trial and error, we have found the best solution to meet the following criterias:

  • Stable and cheap VPS (~10$)
  • Ability to hold 50 people online
  • Debian OS 7 wheezy x64 (minimal)

What has been tested on VPS:

  • Nginx – as main web server;
  • Varnish – as front end caching server before nginx.
  • PHP 5.4 / 5.5 – php-fpm, we checked whole stuff: fast-cgi-cache, opCache (APC, xAPC, APCu) & etc.
  • Memcached
  • Mysql – it’s strongly recommended to use MariaDB, but in our tests we use MySQL, because we dont have a lot of dynamic queries. We store everything in cache.

What WordPress plugins has been tested:

  • Most popular caching plugins like: W3, SJ caching, WP-FFPC, WP Super Cache & etc.
  • WordPress optimization plugins: Autoptimize, EWWW Image Optimizer.

Load testing services:

  • http://blitz.io
  • http://loadstorm.com
  • http://loadimpact.com
  • Software: ab / siege

By default we took php 5.5 with opCache out of the box. You may use php 5.4 or later with APC, APCu.

This is the list of web server confs that we used in our tests:

  • varnish + nginx (php-fpm caching in tmpfs, gzip) + wp-ffpc (memcached) + Autoptimize
  • varnish + nginx (pagespeed caching in tmpfs, gzip) + wp-ffpc (memcached) + Autoptimize
  • nginx (gzip) + php-fpm + wp-ffpc (memcached) + Autoptimize
  • nginx (gzip) + php-fpm (cgi caching in tmpfs) + wp-ffpc (memcached) + Autoptimize
  • & etc.

As you can see there were a lot of difference confs, but we found the best solution for our purpose :)

Best solution:

  • nginx + pagespeed_mod  (memcached caching) + gzip;
  • WordPress + wp-ffpc (memcached) + wp-super-cache + autoptimize + EWWW Image Optimizer
  • Mysql (you may use MariaDB if you understand the differences)

VPS hardware:

  • 1 core Intel Xeon E5 (2.5 GHz)
  • 4 GB RAM
  • 15 GB (RAID-1)

You may use this manual on other VPS or dedicated servers with RAM >= 1 GB, our tests on 512 mb of RAM still good but not enough for best performance.

Installing Nginx and Pagespeed module

1) Let’s add fresh repository:

Source code   
deb http://packages.dotdeb.org wheezy all
gpg --keyserver keys.gnupg.net --recv-key 89DF5277
gpg -a --export 89DF5277 | sudo apt-key add -

2) Since we are using minimal Debian 7 wheezy, you may setup your own language (optional).

Source code   
dpkg-reconfigure locales

3) Adding Ngninx repository  http://nginx.org/en/linux_packages.html

Source code   
wget http://nginx.org/keys/nginx_signing.key
sudo apt-key add nginx_signing.key

In /etc/apt/sources.list

Source code   
deb http://nginx.org/packages/debian/ wheezy nginx
deb-src http://nginx.org/packages/debian/ wheezy nginx

4) Make & Install Nginx + pagespeed_mod http://serverfault.com/questions/605056/adding-pagespeed-module-to-installed-nginx/637116#637116

Source code   
sudo apt-get install build-essential zlib1g-dev libpcre3 libpcre3-dev unzip
mkdir -p /usr/src/nginx-pagespeed/
cd /usr/src/nginx-pagespeed/
sudo apt-get source nginx-full
cd nginx-1.6.2/

Download last version of ngx_pagespeed

Source code   
wget https://github.com/pagespeed/ngx_pagespeed/archive/release-1.9.32.2-beta.zip
unzip release-1.9.32.2-beta.zip
cd ngx_pagespeed-release-1.9.32.2-beta/
wget https://dl.google.com/dl/page-speed/psol/1.9.32.2.tar.gz
tar -xzvf 1.9.32.2.tar.gz
cd /usr/src/nginx-pagespeed/nginx-1.6.2

Configuring nginx (by default installation PATHs are different, so set them manually):

Source code   
./configure --add-module=/usr/src/nginx-pagespeed/nginx-1.6.2/ngx_pagespeed-release-1.9.32.2-beta/ \
--prefix=/etc/nginx \
--sbin-path=/usr/sbin/nginx \
--conf-path=/etc/nginx/nginx.conf \
--error-log-path=/var/log/nginx/error.log \
--http-log-path=/var/log/nginx/access.log \
--pid-path=/var/run/nginx.pid \
--lock-path=/var/run/nginx.lock \
--http-client-body-temp-path=/var/cache/nginx/client_temp \
--http-proxy-temp-path=/var/cache/nginx/proxy_temp \
--http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp \
--http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp \
--http-scgi-temp-path=/var/cache/nginx/scgi_temp \
--with-http_realip_module \
--with-http_addition_module \
--with-http_sub_module \
--with-http_dav_module \
--with-http_flv_module \
--with-http_mp4_module \
--with-http_gunzip_module \
--with-http_gzip_static_module \
--with-http_random_index_module \
--with-http_secure_link_module \
--with-http_stub_status_module \
--with-http_auth_request_module \
--with-file-aio \
--with-ipv6

If no errors, let’s make it!

Source code   
make
checkinstall

WARNING!!! Do NOT make install, DO checkinstall

Source code   
sudo checkinstall --pkgname nginx --pkgversion 1.6-custom --install

After that, you will get this message:

Source code   
Done. The new package has been installed and saved to
 /usr/src/nginx-pagespeed/nginx-1.6.2/nginx_1.6-custom-1_amd64.deb
 You can remove it from your system anytime using:
      dpkg -r nginx

Make nginx directories:

Source code   
mkdir -p /var/log/nginx/ /var/cache/nginx/client_temp

Go to http://kbeezie.com/debian-ubuntu-nginx-init-script/ and create /etc/init.d/nginx file, but dont forget to change DAEMON PATH.

Source code   
DAEMON=/usr/sbin/nginx

Adding nginx into loader

Source code   
/usr/sbin/update-rc.d -f nginx defaults

Installing PHP-FPM & Zend opCache

Source code   
sudo apt-get install php5-fpm php5-cli php5-common php5-cgi php5-mysql php5-gd php5-apc memcached php5-memcached

Setup Zend opCache (if your php version 5.4 or less)

Source code   
apt-get install -y php-pear
apt-get install -y build-essential php5-dev
pecl install zendopcache-7.0.3

Create WWW directory and other special magic:

Source code   
mkdir /home/www
chmod -R a-rwx,u+rwX,g+rX /home/www && chown www-data:www-data -R /home/www

Create directory for cache (we use tmpfs)

Source code   
mkdir /run/shm/fcgi-cache/
chown www-data:www-data -R /run/shm/fcgi-cache/

Edit: /etc/php5/fpm/php-fpm.conf, it should be like this:

Source code   
[global]
pid = /var/run/php5-fpm.pid
include=/etc/php5/fpm/pool.d/*.conf
error_log = /var/log/php5-fpm/error.log
log_level = warning
daemonize = yes

Edit: /etc/php5/fpm/pool.d/www.conf

Source code   
[www]
user = www-data
group = www-data
listen = /var/run/php5-fpm.$pool.sock
listen.owner = www-data
listen.group = www-data
listen.allowed_clients = 127.0.0.1
pm = dynamic
pm.max_children = 5
pm.start_servers = 2
pm.min_spare_servers = 1
pm.max_spare_servers = 3
pm.max_requests = 100
slowlog = /var/log/php5-fpm/slow.$pool.log
request_slowlog_timeout = 9
chdir = /
catch_workers_output = yes
php_flag[display_errors] = off
php_admin_value[error_log] = /var/log/php5-fpm/error.$pool.log
php_admin_flag[log_errors] = on

Create directory:

Source code   
mkdir /var/log/php5-fpm && chown www-data:www-data /var/log/php5-fpm

Then go to /etc/php5/mods-available and create opcache.ini

—>>> opcache.ini

Source code   
# path to opcache mod
zend_extension=/usr/lib/php5/20100525/opcache.so
opcache.memory_consumption=128
opcache.interned_strings_buffer=8
opcache.max_accelerated_files=4000
# if your site more static you may increase this value
opcache.revalidate_freq=60
opcache.fast_shutdown=1
# enable opcache interface for cli
opcache.enable_cli=1

Create link:

Source code   
sudo ln -s /etc/php5/mods-available/opcache.ini /etc/php5/conf.d/5-opcache.ini

 Memcached configuration

Source code   
sudo apt-get install memcached
sudo apt-get install php5-memcache
sudo apt-get install php5-memcached

Open Memcached config in /etc/memcached.conf and setup this values, pay attention to -m you may increase this value if you need (Standart WordPress blog with 1000 pages will take ~50-100mb in memcache)

Source code   
-d
logfile /var/log/memcached.log
-m 256
-p 11211
-u nobody
-l 127.0.0.1

If you want to monitor memcached stats, use this soft:
http://phpmemcacheadmin.googlecode.com/files/phpMemcachedAdmin-1.2.2-r262.zip

MySQL

Source code   
sudo apt-get install bsdutils <strong>(if you have minimal OS)</strong>
sudo apt-get install mysql-server

MySQL phpAdmin (optional)

Source code   
wget http://dl.cihar.com/phpMyAdmin/master/phpMyAdmin-master-latest.tar.gz

Configuring Nginx & Pagespeed module

You may take any working nginx.conf (there are many of them, ask Google). We add 1 line in our currient config:

Source code   
# Virtual hosts & pagespeed mod in conf.d
include /etc/nginx/conf.d/*.conf; 
include /etc/nginx/sites-enabled/*;

Create /etc/nginx/conf.d/pagespeed_mod.conf with this values:

Source code   
pagespeed On;
pagespeed FileCachePath "/run/shm/ngx_cache";
pagespeed FileCacheSizeKb 25600;
pagespeed FileCacheCleanIntervalMs 3600000;
pagespeed FileCacheInodeLimit 500000;
pagespeed RewriteLevel PassThrough;
pagespeed EnableFilters canonicalize_javascript_libraries,extend_cache,extend_cache_pdfs,combine_css,combine_javascript,move_css_above_scripts,insert_dns_prefetch,rewrite_javascript,rewrite_images,prioritize_critical_css,rewrite_css,rewrite_style_attributes,convert_meta_tags,lazyload_images,collapse_whitespace,move_css_to_head,remove_comments,remove_quotes,defer_javascript,inline_css,inline_javascript;
pagespeed UseNativeFetcher on;
resolver 8.8.8.8;
pagespeed LRUCacheKbPerProcess     2048;
pagespeed LRUCacheByteLimit        8192;
pagespeed CreateSharedMemoryMetadataCache "/run/shm/ngx_shared" 6400;
pagespeed CssInlineMaxBytes 1024;
pagespeed JsInlineMaxBytes 1024;
# Memcached
pagespeed MemcachedServers "127.0.0.1:11211";

Pay attention to “EnableFilters” line and setup there filters that you need. Also pagespeed mod stores cache in tmpfs, but only if memcached is out of space, that’s why you need to configure your memcached server memory to more than you probably need