Server - Speed Optimization
Znači, koraci su sledeći:
-
Switch to PHP-FPM (FastCGI Process Manager) and nginx
-
Enable SPDY (recompile nginx to 1.6.0) http://nginx.org/en/docs/http/ngx_http_spdy_module.html But it can be enabled over CloudFlare also. CloudFlare also uses nginx as reverse proxy.
-
Enable Google Pagespeed module
Test if it is enabled:
curl -s -I http://www.hostingtipp.ch/ | grep X-Page-Speed
-
Secure SSL
5 Tools to Speed Up Your Web Site
Switch to nginx (done)
NOT SURE THIS PERMALINKS FIX IS THE BEST WAY. READ THESE ALSO: Wordpress permalinks - Nginx Library WordPress NGINX Rewrite Rules
PHP-FPM is recommended over fcgid as it provides every benefit that fcgid has, with the added advantage of a shared opcode cache for all processes.
Fix for permalink errors
There is a very important fix for permalink errors in Wordpress, that is noticable as 404 errors on every page other than home page.
# wordpress permalinks 404 fix
if (!-e $request_filename) { rewrite ^(.*)$ /index.php break; }
The best explanation is found in this post. So, we should use this and not the above, but this one doesn’t work as duplicate locations are set.
# fix permalinks 404
location ~ /$ { try_files $uri $uri/ /index.php?$args; }
Another fix for Plesk and nginx is here
Finally found a working replacement without an if statement:
rewrite !.(js|ico|gif|jpg|png|css|pdf|mov|mp3|eot|svg|ttf|woff|otf|txt|swf)$ /index.php break;
rewrite /$ /index.php break;
Enable GZip compression in nginx (done)
Every command and it’s meaning is explained in nginx admin-guide. Also, the best configuration was found and explained here.
|
|
Test with
curl -s -H "Accept-Encoding: gzip,deflate,sdch" -I http://www.save-up.ch | grep -i Content-Encoding
Sources:
- ngx_http_gzip_module
- How to enable gzip in NGINX
- How-to enable gzip support on nginx
- Enable GZIP Compression on nginx Servers
- Enable GZIP on Plesk
Run nginx -t
or service nginx configtest
to test the nginx configuration and after restart or reload nginx by running service nginx restart
Best online test tools to check if compression is enabled, are on Check GZIP compression and WhatsMyIP.org
More nginx tweaks (done)
|
|
Really good source with explanations is here.
Expires
Expiring is much more complicated. Don’t do it for dynamic data - only for static one.
Keep Alive
Keep Alive is enabled by default in nginx, but it’s nice do decrease timeout from default of 65 seconds to 30s.
So set keepalive_timeout
to 30 in /etc/nginx/nginx.conf
.
HTTP Keepalive Connections and Web Performance Is Keep-Alive Enabled Checker
Worker Processes and Worker Connections
For the number of cores type grep processor /proc/cpuinfo | wc -l
. To get practical maximum open file descriptors type ulimit -n
.
Change in /etc/nginx/nginx.conf
:
worker_processes -> auto
worker_connections -> 10240
worker_rlimit_nofile -> 100000 just below worker_processes line
Very nice boilerplate of nginx settings is here: h5bp/server-configs-nginx
Optimizing Nginx Configuration How To Optimize Nginx Configuration Tuning nginx worker_process to obtain 100k hits per min Nginx Tuning For Best Performance
Depending on needs, sendfile can be either totally useless or completely essential. But it never can degrade performance.
sendfile on;
tcp_nopush on;
tcp_nodelay on;
Nginx Optimization: Understanding sendfile, tcp_nodelay and tcp_nopush
Enable SPDY in nginx (done)
SPDY protocol 3.1 is implemented in nginx. The problem is that you can’t use SPDY without SSL.
- check build options: ngnix -V
- download ngnix new version
- /.configure with options from pt1 and add –with-http_spdy_module
- make
- make install
Let’s do it:
# needed packages
apt-get install build-essential libssl-dev libpcre3 libpcre3-dev
# download source
cd /usr/local/src/
wget http://nginx.org/download/nginx-1.6.2.tar.gz
tar -xvf nginx-1.6.2.tar.gz
cd nginx-1.6.2/
# get the current configuration directives
#
nginx -V
# nginx version: nginx/1.6.0
# TLS SNI support enabled
# configure arguments: --prefix=/usr/share --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 --lock-path=/var/lock/nginx.lock --pid-path=/var/run/nginx.pid --http-client-body-temp-path=/var/lib/nginx/body --http-fastcgi-temp-path=/var/lib/nginx/fastcgi --http-proxy-temp-path=/var/lib/nginx/proxy --http-scgi-temp-path=/var/lib/nginx/scgi --http-uwsgi-temp-path=/var/lib/nginx/uwsgi --user=nginx --group=nginx --with-ipv6 --with-file-aio --with-http_ssl_module --with-http_realip_module --with-http_sub_module --with-http_dav_module --with-http_gzip_static_module --with-http_stub_status_module
# append an `--with-http_spdy_module` option
./configure --prefix=/usr/share --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 --lock-path=/var/lock/nginx.lock --pid-path=/var/run/nginx.pid --http-client-body-temp-path=/var/lib/nginx/body --http-fastcgi-temp-path=/var/lib/nginx/fastcgi --http-proxy-temp-path=/var/lib/nginx/proxy --http-scgi-temp-path=/var/lib/nginx/scgi --http-uwsgi-temp-path=/var/lib/nginx/uwsgi --user=nginx --group=nginx --with-ipv6 --with-file-aio --with-http_ssl_module --with-http_realip_module --with-http_sub_module --with-http_dav_module --with-http_gzip_static_module --with-http_stub_status_module --with-http_spdy_module
make
make install
# Our nginx now supports SPDY
Now, we need to change the default Plesk template and reconfigure every domain. We do that by making a custom domain template:
mkdir -p /usr/local/psa/admin/conf/templates/custom/domain
cp /usr/local/psa/admin/conf/templates/default/domain/nginxDomainVirtualHost.php /usr/local/psa/admin/conf/templates/custom/domain/
nano /usr/local/psa/admin/conf/templates/custom/domain/nginxDomainVirtualHost.php
# append `spdy` after `ssl` in only one line
# ($OPT['default'] ? ' default_server' : '') . ($OPT['ssl'] ? ' ssl spdy' : '') ?>;
# reconfigure domains
plesk sbin httpdmng --reconfigure-domain hostingtipp.ch
Finally, when definitely sure, do that for all domains:
plesk sbin httpdmng --reconfigure-all
Plesk 12 Nginx Update und SPDY aktivieren unter Debian
Enable SPDY on Nginx Enabling SPDY for Nginx in Plesk SPDY Nginx in Plesk 12 SPDY support in Nginx
Check for SPDY on SPDYCheck
Optimize & secure SSL (done)
I have a separate post on this huge area.
Google Pagespeed module for nginx ( done )
Google has PageSpeed modules that execute optimization on my server. There was also PageSpeed Service that optimized web site automatically and serve it from Google servers, exactly like CDN. Sadly, the PageSpeed Service not currently accepting new signups.
We will be using ngx_pagespeed
module, and for that, we need to recompile nginx. Later, we will enable pagespeed only on desired domains by using custom nginx directives.
Performance improvements are not mind blowing, but as an advanced tuning technique, it’s ok.
CloudFlare or MaxCDN already do similar optimizations so it’s not that big deal to enable Pagespeed. On the other side - not sure in CloudFlare speed, and I don’t want to pay MaxCDN for that.
How to install?
If you’re using Nginx you need to build from source.
Sources:
Caching
There are multiple types of caching:
-
Opcode Cache - Zend Opcache is final and only sensible solution as it the best performer and is included in core of the current PHP version.
-
Object Cache APCu is almost the only viable solution. And, in Wordpress, it can be controlled with multiple plugins.
-
Database Cache Is not crucial as MySQL Query cache is already doing a quite nice job of optimizing database query results.
-
Full-page Cache
- nginx fastcgi_cache: implemented in nginx itself using disk.
Can be speedup by using shared memory as disk. Should be very fast, but needs to be purged from application somehow - Wordpress has plugin for that. Without purging, should be used as Microcache for no more than 5 sec. - varnish: out of question as doesn’t support SSL without added pound reverse-proxy.
- memcached as data store. Ngnix knows to read directly from memcached, with module.
- APCu as full-page data store, using the plugin. Should be the fastest compared to Memcached or Redis, but slower than nginx.
- nginx fastcgi_cache: implemented in nginx itself using disk.
-
CDN Cache
Full Page Cache
nginx w/ fastcgi_cache module
This is the same as proxy_cache
directives which are used for reverse proxy caching.
|
|
Setting per domain:
|
|
There should already be a header X-Cache-Debug
Test this:
curl -s -I http://www.save-up.ch/ | grep -i X-Nginx-Cache
curl -s -I http://www.save-up.ch/ | grep -i X-Cache-Debug
We can just leave short caching periods. This is why this is often
called microcaching
.
But we can do a lot more for Wordpress - see: download.kyup.com/wordpress/conf.d
If we want to be sure that we purged cached data, we can delete files directly in cache path or we can install a third-party module like ngx_cache_purge
There are a lot of Wordpress Plugins for nginx cache control.
Purging with the help of ngx_cache_purge
-
The most famous one is Nginx Helper and works very good. It is the one I selected.
-
Nginx Proxy Cache Purge is doing the same thing, with the same mechanism. Please note that the guy stayed focused on reverse proxy cache.
-
NGINX Manager is little unmaintained.
-
Network Nginx Proxy Cache Purge seems of a little less quality, also focused on reverse proxy cache.
Nginx + WordPress + fastcgi_cache with conditional purging 40 Million hits a day on WordPress
How to Setup FastCGI Caching with Nginx on your VPS
Add this for purging:
location ~ /purge(/.*) {
fastcgi_cache_purge WORDPRESS "$scheme$request_method$host$1";
}
The size of the cache:
du -h -s /dev/shm/nginx/
Q: These two lines are not exactly the same?
fastcgi_cache_key "$scheme$request_method$host$request_uri";
vs.
fastcgi_cache_purge WORDPRESS "$scheme$request_method$host$1";
A: Yes - In purge block, $request_uri contains
part /purge
at the
beginning for every cached page-url. So $1
variable captures
correct cached-url - without /purge
in the beginning.
Purge all cache manually from shell by deleting all files altogether:
find /dev/shm/nginx -type f -delete
How to clear the cache of nginx?
Microcaching
Why You Should Always Use Nginx With Microcaching Nice comments: Microcaching for a Faster Site
In http {}
block:
fastcgi_cache_path /var/cache/nginx2 levels=1:2 keys_zone=microcache:5m max_size=1000m;
Put in location ~ \.php$
block:
I see you use fastcgi_cache_use_stale updating
, that is an important
setting. Without it your performance would be much lower in real world
scenarios.
log_format custom_microcache ‘$remote_addr - $remote_user [$time_local] ' ‘"$request" $status $body_bytes_sent ' ‘"$http_referer" “$http_user_agent” nocache:$no_cache’;
Purging by deleting cache files
Plugins to support this don’t need nothing on server side as they search for cached files in nginx cache dir and try to delete them. PHP script has to have sufficient rights to delete cache files - doesn’t look very secure to me.
-
NGINX Cache Optimizer besides this is also i Memcached object cache.
Only for reverse proxy_cache
But this comment is like a bible: Use a fragment cache for WordPress (by Rarst)
Varnish doesn’t support SSL
How to install Varnish on Plesk
Varnish doesn’t support SSL. It can be done with pound in front of it. But nginx does, so this is why we will be using nginx cache.
Memcached / Redis as store
If your box can handle the entire cache on its own, memcache/redis will only slow you down. APCu is shared memory - used right it will blow away memcached/redis.
All you need is nginx caching and APC at this point.
Memcache/Redis comes into the picture only when you have to scale your cache beyond a single box.
Memcached
Blazing fast WordPress with Nginx and Memcached
Redis
We can use Redis as a store for full page caching
WordPress Caching with Nginx and Redis WordPress › wp-redis-cache
Wordpress Plugins for Redis
How To Install and Use Memcache
APCu as full-page store
APCu can be also used as storage backend for full-page caching. As it is the best type of object caching for Wordpress, I will use it here, also.
Wordpress Plugins
There is a separate article on that.
Latest PHP > separate file
In case of Apache, this also sets multiple PHP versions. But, you can’t use multiple PHP versions for php-fpm, but you can update to any php-fpm version.
My current version was PHP 5.4.36 - the new one, installed is 5.6.6.
This whole section isextracted into separate article.
PHP Opcode Cache
eAccelerator and APC are dormant and probably dead. That leaves us with Xcache and Zend. But, considering that Zend Opcache is included in PHP 5.5, the selection is simple.
And not only that, but XCache is no more the best opcode cache around as this comparison article concludes.
Note that Zend Opcache is not enabled by default.
List of PHP accelerators on Wikipedia
PHP, memcache & w3-total cache for WordPress
PHP’s Zend Opcache Config & Web Viewer
PHP Performance I: Everything You Need to Know About OpCode Caches
PHP Session Store
We can put PHP session data into a shared memory, or even in key-value db like Redis or Memacached.
“–with-mm”?
PHP User Data Cache (Database Cache & Persistent Object Cache)
Persistent Object Caching WP Object Cache
APCu is userland caching: APC stripped of opcode caching in preparation for the deployment of Zend Optimizer+ as the primary solution to opcode caching in future versions of PHP.
APCu uses the same PHP functions that APC used so you don’t have to worry about breaking your application when switching over.
APCu only implements key/value store, and as Memcache or Redis are much better in that. Sometimes, APCu can be a great alternative for small scale applications that don’t need distributed caching systems.
Considering the APCu (formerly APC user cache) user cache, it’s a storage for applicative cache, you can tell Drupal to use it the same way as redis. Main problem with APCu is that it will store cache in the PHP shared memory, which means that you need to have a lot of dedicated RAM to the PHP processes to store Drupal data into it. Plus, if you multiple PHP frontends, each frontend will carry its own shared memory, data in those frontends may differs: this means that you can have a cache desync between PHP frontends; That’s why we oftenly prefer to use a memcache, or redis or mongodb.
The OPCode cache (formerly APC, xcache, etc…) : only serves the purpose of storing compiled version of PHP code into memory, and make it run faster - this has nothing to do with the later The applicative cache : purely business stuff that Drupal will store into a raw storage in order to avoid to do some business computations too often and be faster
How came to APCu: The Future of Caching in PHP
/usr/local/php566/bin/pecl remote-info APCu
/usr/local/php566/bin/pecl install APCu-beta
/usr/local/php566/lib/php/20131226/apcu.so
extension=apcu.so
Enable and configure APCu:
echo '
; configuration for APCu
; extension: /usr/local/php566/lib/php/20131226/apcu.so
;
extension=apcu.so
apc.enabled=1
apc.shm_size=128M
apc.ttl=7200
apc.mmap_file_mask=/tmp/apc.XXXXXX
' > /etc/php5/php566/fpm/conf.d/20-apcu.ini
When APC is compiled with mmap support (Memory Mapping), it will use only one memory segment (shm_segment). MMAP support is recommeded.
Wordpress plugins
Object cache plugins are always drop-in plugins that upload file object-cache.php
.
Object cache is explained simple: WordPress allows you to replace the cache API with a drop-in - a file that gets placed directly in your wp-content
folder. If you create your own cache drop-in or use an existing plugin, you can make the object cache persist longer than a single page load. When you do that, transients, change a bit.
Note: Enable object cache only if there are more than 700-800 blog posts on your blog. If you have less posts then no need of enabling it.
Memcached as store
PHP, memcache & w3-total cache for WordPress tollmanz/wordpress-pecl-memcached-object-cache
Install memcached:
apt-get install memcached
apt-get install libmemcached-dev
/usr/local/php566/bin/pecl install memcached --with-libmemcached-dir=/usr/lib
/usr/lib/x86_64-linux-gnu/
How to flush memcached instance?
All the right answers are here.
apt-get install libmemcached-tools
memcflush --servers=localhost:11211
You can also do that with netcat or telnet, but this is the best way as far I am concerned.
Redis as store
-
Redis Object Cache and improved version: Redis Object Cache
-
WP Redis is also an object cache
-
apt-get install libmemcached-dev
-
/usr/local/php566/bin/pecl download memcached tar xzvf memcached-.tgz rm memcached-.tgz cd memcached-*
/usr/local/php566/bin/phpize ./configure –disable-memcached-sasl –with-php-config=/usr/local/php566/bin/php-config –with-libmemcached-dir=/usr
make checkinstall -D –pkgname=“php-memcached-custom” make install
remove it anytime with
dpkg -r php-memcached-custom
The problem was non-working:
/usr/local/php566/bin/pecl install memcached
Enable and configure memcached in PHP:
echo '
; configuration for memcached
; /usr/local/php566/lib/php/20131226/memcached.so
;
extension=memcached.so
' > /etc/php5/php566/fpm/conf.d/30-memcached.ini
To check functionality:
service php5-fpm restart
W3TC is not working with memcached but only with memcache PHP extension.
That shit worked out of the box:
/usr/local/php566/bin/pecl install memcached
echo '
; configuration for memcache extension
; /usr/local/php566/lib/php/20131226/memcache.so
;
extension=memcache.so
' > /etc/php5/php566/fpm/conf.d/30-memcache.ini
service php5-fpm restart
You can have both PHP extensions enabled. So, because of W3TC i disabled memcached-one.
It seems that PHP has two memcached libraries named memcache and memcached
Put sessions in memcached?
Thus, to see a performance boost from minification, having both an OpCode and Userland Cache is extremely important.
APCu | Miscellaneous Knowledge
SSL support
Enable SSL for SPDY support.
Force redirect to SSL
We need something that doesn’t cause redirect loops. We can use nginx variables like $scheme
, $ssl_protocol
or $https
# force https
if ($ssl_protocol = "") { return 301 https://$server_name$request_uri; }
This solution, with if
statement is the only valid solution, albeit
slower, as Plesk includes the same nginx.conf
file in both server
directives for HTTP and HTTPS.
Keep in mind, while testing changes, you should use a 302 temporary redirect instead of 301 permanent, to save hair-pulling when you discover you fixed it an hour earlier but the changes didn’t reflect in your browser.
How to force or redirect to SSL in nginx? Pitfalls - Nginx Community Force SSL in location with nginx http-https redirect / Positive SSL on nginx | DigitalOcean Force SSL and NO-www with Nginx Configuration - Heroku Forums
Enable HTTP/2 on nginx
Performance of HTTP/1.1 vs HTTP/2 Known implementations of HTTP/2
CDN
For us, based on hosting locations, using CDN has sense only for foreign, non-german customers. Based on CloudFlare data center locations, the closest is Frankfurt. Hetzner datacenters are in Falkenstein and Nuremberg, both at similar distance as Frankfurt.
Database optimization
On our system, it was already enabled.
mysql -hlocalhost -usave-up-ch -p"Xtpx85#3" -e "show variables like 'query_cache_%'"
WOOW Nginx Secure SSL Web Server @ Calomel.org
Copied from W3 Total Cache plugin configuration:
# CORS fonts for CDN
#
location ~ \.(ttf|ttc|otf|eot|woff|font.css)$ {
add_header Access-Control-Allow-Origin "*";
}
# gzip static content
#
gzip on;
gzip_types text/css text/x-component application/x-javascript application/javascript text/javascript text/x-js text/richtext image/svg+xml text/plain text/xsd text/xsl text/xml image/x-icon;
# Cache static content
#
location ~ \.(css|htc|less|js|js2|js3|js4)$ {
expires 31536000s;
add_header Pragma "public";
add_header Cache-Control "max-age=31536000, public";
}
location ~ \.(html|htm|rtf|rtx|svg|svgz|txt|xsd|xsl|xml)$ {
expires 3600s;
add_header Pragma "public";
add_header Cache-Control "max-age=3600, public";
}
location ~ \.(asf|asx|wax|wmv|wmx|avi|bmp|class|divx|doc|docx|eot|exe|gif|gz|gzip|ico|jpg|jpeg|jpe|json|mdb|mid|midi|mov|qt|mp3|m4a|mp4|m4v|mpeg|mpg|mpe|mpp|otf|odb|odc|odf|odg|odp|ods|odt|ogg|pdf|png|pot|pps|ppt|pptx|ra|ram|svg|svgz|swf|tar|tif|tiff|ttf|ttc|wav|wma|wri|woff|xla|xls|xlsx|xlt|xlw|zip)$ {
expires 31536000s;
add_header Pragma "public";
add_header Cache-Control "max-age=31536000, public";
add_header Link "<$scheme://$host$uri>; rel=\"canonical\"";
}
Missing Vary Accept-Encoding header
Specify a Vary: Accept-Encoding header
Uncomment all the gzip_
directives in nginx configuration:
sed -i -re 's/# (gzip_.*)$/\1/gi' /etc/nginx/nginx.conf
Specially important ones are gzip_types
and gzip_vary
.
Problem is maybe that gzip_vary on
adds the Vary
header only to non-gzipped
responses those can be gzipped, but were not gzipped for some reasons.
Source is Igor Sysoev, from
here.
When SPDY is enabled the Vary: Accept-Encoding
headers
disappear. It’s because SPDY require user agents to support compression
and that draws header useless. Source is here
Solution is not a really good, but anyway, to please GTmetrix:
location ~* \.(?:css|js|jpg|jpeg|gif|png|ico|cur|gz|svg|svgz|mp4|ogg|ogv|webm|htc)$ {
expires 1w;
access_log off;
add_header Cache-Control "public";
# add missing vary header in SPDY to please GTmetrix and such
add_header Vary "Accept-Encoding";
}
Something similar is mentioned here for fonts.
Configure memcached
Increase memory
The one thing we must do is to configure memcached to use much more memory. Default was 64Mb and I want to increase that to 4G (4096M):
Note that the daemon will grow to this size, but does not start out holding this much memory.
sed -i -re 's/^-m .*$/-m 4096/gi' /etc/memcached.conf
service memcached restart
Enable logging
In short, you just need to add or uncomment two lines to
/etc/memcached.conf
: -v
and lofgile /path/to/log
and restart the
daemon with service memcached restart
.
Or more elegantly, execute
sed -i -re 's/^# -v$/-v/gi' /etc/memcached.conf
to set -v
that will print out errors and warnings in log.
Err: Failed to write, and not due to blocking: Connection reset by peer
Probably some file descriptor limit.
# Soft / hard (max value) limit per current user
ulimit -Sn
ulimit -Hn
# Set them both
ulimit -n 50000
Increasing ulimit and file descriptors limit on Linux | Glass Onion Blog php unable to connect to memcached at times when under high load - Stack Overflow
There is also a parameter in memcached: Maximize core file limit
Memcached limit on result size of 1M
Not sure how to check this? The error would look like this: Values may not be more than 1000000 bytes in length; received 1071339 bytes
This is now a user-configurable parameter, so you can increase this
limit with -I 15M
or anything else. Maximum object size you can
specify is 128M but the default remains at 1M.