Alt text
23Jan

Hight load VPS and WordPress optimization

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:

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).

dpkg-reconfigure locales

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

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

In /etc/apt/sources.list

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

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

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):

./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!

make
checkinstall

WARNING!!! Do NOT make install, DO checkinstall

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

After that, you will get this message:

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:

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.

DAEMON=/usr/sbin/nginx

Adding nginx into loader

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

Installing PHP-FPM & Zend opCache

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)

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:

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)

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:

[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

[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:

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

# 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:

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

 Memcached configuration

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)

-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

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

MySQL phpAdmin (optional)

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:

# 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:

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.

Benchmark screenshots (best perfomance):

50 users onlineav

Memcached stats during the test:

 

memcached stat

Server feels OK even with 50 users online, so right now we have ~20-25 users online in rush hours and free space to grow :)

List of WordPress plugins installed:

Autoptimize – good plugin for CSS, HTML, JS optimization (We use it for CSS, HTML).
Dagon Design Sitemap Generator
GoCodes
Google XML Sitemaps
New Adman
No Image Link
Post Chapter – *our plugin (not in public repository)
Top Level Categories
Wordpress Popular Posts
WP-ASC
WP-FFPC – best plugin for object caching
WPLANG Lite – language file optimization
WP Super Cache – static cache (dont need it any more)
Yet Another Related Posts Plugin
Wordpress (Robot) – *our plugin for correct robots.txt (not in public repository)

Post a comment

Your email address will not be published.Required fields are marked*