Optimize WordPress with Nginx

If you follow my last two tutorials How to install LEMP web server with Nginx, PHP-FPM 5.5, MySQL 5.5 on Centos Linux and How To Install WordPress with nginx on Centos 6. You should have your WordPress website running with LEMP nginx, php-fpm and mysql stack. WordPress works perfectly fine with Apache, but you will run into some minor problems with WordPress and nginx

To install WordPress theme without ftp logins

We have not installed ftp server to our LEMP web server with Nginx, PHP-FPM 5.5, MySQL 5.5 on Centos Linux, You can install vsftpd server on centos 6 if you want to. For me, I don’t need an extra ftp server since I don’t need to upload/download anything from web server, you can install/delete WordPress themes/plugins without a ftp server by Force Direct Filewrites For install and upgrades.
edit wp-config.php file

# nano /usr/share/nginx/html/wp-config.php

and add

define('FS_METHOD', 'direct');

Next you have to give write permission to wp-content themes and plugins directory

# chmod 777 /usr/share/nginx/html/wp-content
# chmod 777 /usr/share/nginx/html/wp-content/themes
# chmod 777 /usr/share/nginx/html/wp-content/plugins
# chmod 777 /usr/share/nginx/html/wp-content/uploads
WordPress pretty/fancy permalinks with Nginx

Default WordPress Permalink Settings is http://yourdomain.com/?p=123 which somewhat … not fancy. If you want to change your WordPress Permalink Settings to something else like /%post_id%/%postname%/ you will have to add try_files option under the / location to nginx configure file or else you will get error 404 page not found.

# nano /etc/nginx/conf.d/default.conf

Search for

    location / {
        root   /usr/share/nginx/html;
        index  index.html index.htm index.php;
    }
and add
try_files $uri $uri/ /index.php?q=$uri&$args;

You should have something like this

    location / {
        root   /usr/share/nginx/html;
        index  index.html index.htm index.php;
        try_files $uri $uri/ /index.php?q=$uri&$args;
    }

You will have to restart nginx after modified nginx configure file.

# service nginx restart
Adjust nginx worker_processes

nginx worker_processes value should be the number of your vps or dedicated server’s cpu cores since nginx uses a fixed number of workers to handles incoming requests.
To check the number of CPU core:

$ grep ^processor /proc/cpuinfo | wc -l

Then set nginx_processes accordingly

# nano /etc/nginx/nginx.conf

In my case my vps only has 1 vcpu core, I set nginx_processes to 1

worker_processes  1;
Gzip Compression

Gzip is disabled by default in nginx, we should always use gzip compression to reduce the size of transmitted data.

# nano /etc/nginx/nginx.conf

Search for

# gzip on

and replace with

gzip on;
gzip_comp_level 3;
gzip_buffers 16 8k;
gzip_vary on;
gzip_proxied any;
gzip_min_length  1000;
gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript;
gzip_disable "MSIE [1-6]\.(?!.*SV1)";
Save the file and restart nginx
# service nginx restart
php-fpm user/group

If you won’t want to deal with files/directories permission problem with php-fpm processes, you can change user/group for php-fpm. By default php-fpm will use apache user/group. In centos 6, you can change user/group for php-fpm in www.conf file.

# nano /etc/php-fpm.d/www.conf

Search for

; Unix user/group of processes
; Note: The user is mandatory. If the group is not set, the default user's group
;       will be used.
; RPM: apache Choosed to be able to access some dir as httpd
user = apache
; RPM: Keep a group allowed to write in log dir.
group = apache
Change user/group to the user/group you want to run php-fpm
; Unix user/group of processes
; Note: The user is mandatory. If the group is not set, the default user's group
;       will be used.
; RPM: apache Choosed to be able to access some dir as httpd
user = namhuy
; RPM: Keep a group allowed to write in log dir.
group = namhuy
Moving nginx $document_root to different location

If you want to store your www or public_html directory in your /home/user directory, you may run into File not found error because PHP files are not readable by the PHP process. To solve this problem, you have to make the files/directories world readable.

chmod a+x /home/user/
chmod a+x /home/user/public_html
phpmyadmin and nginx

If you downloaded phpmyadmin and it gives you blank page when you try to access phpmyadmin directory with your web browser. The first place to look is nginx error log.

# cat /var/log/nginx/error.log

This is the error for phpmyadmin

2014/04/30 16:39:04 [crit] 5408#0: *28 open() "/var/lib/nginx/tmp/fastcgi/3/00/0000000003" failed (13: Permission denied) while reading upstream .... referrer: "http://www.namhuy.net/phpmyadmin/

To give nginx or your user to have access to /var/lib/nginx directory, use this command (change the directory and user according to your error and your username)

# chmod 777 /var/lib/nginx/

or

# chown user:user /var/lib/nginx/
nginx redirect www to non-www

WordPress depends on .htaccess file to redirect www to non-www or another way. Since nginx does not support .htaccess, if you want to redirect www to non-www domain, you have to modify nginx conf file. Depends on your nginx setup, I will use default.conf for our sample

# nano /etc/nginx/conf.d

and add to the top of the file

server {
    listen       80;
    server_name  www.domain.com;
    return 301 $scheme://domain.com$request_uri;
}
or
server {

    listen       80;
    server_name  www.domain.com;
    rewrite ^(.*) http://domain.com$1 permanent;
}
nginx redirect non-www to www
server {
    listen       80;
    server_name  domain.com;
    return 301 $scheme://www.domain.com$request_uri;
}
or
server {
    listen       80;
    server_name  domain.com;
    rewrite ^(.*) http://www.domain.com$1 permanent;
}
Port 8080 url error with varnish and nginx

Varnish plays nice with Apache but not with nginx. If you are running nginx backend and varnish frontend, you will eventually get domain.com:8080 and your web browser won’t load it since port 8080 is backend for varnish and nginx to communicate with each other. The problem occurs if the URL without a tailing slash “/”, the URL will redirect to port 8080 instead of regular port 80 for http. To solve that problem, you will have to add “port_in_redirect off” to the directives which cause the problem. By default nginx set port_in_redirect value is on. We will turn if off.

For example, every time i login to wordpress, wp-admin WordPress Admin Panel will redirect the url to port 80. If you only have one nginx config file in /etc/nginx/conf.d , for example default.conf, edit your nginx website config file

# nano /etc/nginx/conf.d/default.conf

and add

port_in_redirect off;

to the main nginx directive

Your default wordpress nginx config file should look like

     location / {
        root   /home/user/public_html/domain.com;
        index  index.html index.htm index.php;
        try_files $uri $uri/ /index.php?q=$uri&$args;
        port_in_redirect off;
    }
W3 Total Cache and nginx

W3 Total Cache or w3tc is a great WordPress caching plugin, there are several caching plugins for WordPress out there but W3TC is still my favorite all time. Anyway, back to our business, w3tc plays nicely with Apache since Apache supports .htaccess file. The story is quite different with nginx which does no support .htaccess file. As if you are reading this you might have run into some sort of problem with w3tc and nginx. In order to use w3tc with nginx, w3tc requires you to create nginx.conf file under your website root directory. You can find the content of w3tc nginx.conf file from your WordPress Admin Panel, Performance, and Install on the left tab.

This is the sample nginx.conf file from w3tc

# BEGIN W3TC Page Cache cache
location ~ /wp-content/cache/page_enhanced.*html$ {
    expires modified 3600s;
    add_header X-Powered-By "W3 Total Cache/0.9.4";
    add_header Vary "Accept-Encoding, Cookie";
    add_header Pragma "public";
    add_header Cache-Control "max-age=3600, public";
}
location ~ /wp-content/cache/page_enhanced.*gzip$ {
    gzip off;
    types {}
    default_type text/html;
    expires modified 3600s;
    add_header X-Powered-By "W3 Total Cache/0.9.4";
    add_header Vary "Accept-Encoding, Cookie";
    add_header Pragma "public";
    add_header Cache-Control "max-age=3600, public";
    add_header Content-Encoding gzip;
}
# END W3TC Page Cache cache
# BEGIN W3TC Browser Cache
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;
location ~ \.(css|htc|less|js|js2|js3|js4)$ {
    expires 31536000s;
    add_header Pragma "public";
    add_header Cache-Control "max-age=31536000, public";
    add_header X-Powered-By "W3 Total Cache/0.9.4";
}
location ~ \.(htm|rtf|rtx|svg|svgz|txt|xsd|xsl|xml)$ {
    expires 3600s;
    add_header Pragma "public";
    add_header Cache-Control "max-age=3600, public";
    add_header X-Powered-By "W3 Total Cache/0.9.4";
}
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 "; rel=\"canonical\"";
    add_header X-Powered-By "W3 Total Cache/0.9.4";
}
# END W3TC Browser Cache
# BEGIN W3TC CDN
location ~ \.(ttf|ttc|otf|eot|woff|font.css)$ {
   add_header Access-Control-Allow-Origin "*";
}
# END W3TC CDN
# BEGIN W3TC Minify core
rewrite ^/wp-content/cache/minify.*/w3tc_rewrite_test$ /wp-content/plugins/w3-total-cache/pub/minify.php?w3tc_rewrite_test=1 last;
rewrite ^/wp-content/cache/minify/(.+/[X]+\.css)$ /wp-content/plugins/w3-total-cache/pub/minify.php?test_file=$1 last;
rewrite ^/wp-content/cache/minify/(.+\.(css|js))$ /wp-content/plugins/w3-total-cache/pub/minify.php?file=$1 last;
# END W3TC Minify core
# BEGIN W3TC Page Cache core
set $w3tc_rewrite 1;
if ($request_method = POST) {
    set $w3tc_rewrite 0;
}
if ($query_string != "") {
    set $w3tc_rewrite 0;
}
if ($http_cookie ~* "(comment_author|wp\-postpass|w3tc_logged_out|wordpress_logged_in|wptouch_switch_toggle)") {
    set $w3tc_rewrite 0;
}
if ($http_cookie ~* "(w3tc_preview)") {
    set $w3tc_rewrite _preview;
}
set $w3tc_enc "";
if ($http_accept_encoding ~ gzip) {
    set $w3tc_enc _gzip;
}
set $w3tc_ext "";
if (-f "$document_root/wp-content/cache/page_enhanced/$http_host/$request_uri/_index$w3tc_rewrite.html$w3tc_enc") {
    set $w3tc_ext .html;
}
if (-f "$document_root/wp-content/cache/page_enhanced/$http_host/$request_uri/_index$w3tc_rewrite.xml$w3tc_enc") {
    set $w3tc_ext .xml;
}
if ($w3tc_ext = "") {
  set $w3tc_rewrite 0;
}
if ($w3tc_rewrite = 1) {
    rewrite .* "/wp-content/cache/page_enhanced/$http_host/$request_uri/_index$w3tc_rewrite$w3tc_ext$w3tc_enc" last;
}
# END W3TC Page Cache core

You are supported to create nginx.conf file under your website root directory. From How to install LEMP web server with Nginx, PHP-FPM 5.5, MySQL 5.5 on Centos Linux nginx default root document is /usr/share/nginx/html/ . Depends on how you setup your nginx document_root may be different.

w3tc wants you to create nginx.conf under your website root directory, but nginx itself does not read that nginx.conf file from w3tc by default. There are two ways to make nginx read the w3tc nginx.conf file, the first way is to use “include” to link w3tc nginx.conf file to the main nginx configure file. Depends on how you configure your nginx, edit the .conf file for your website/domain

# nano /etc/nginx/conf.d/default.conf

or

# nano /etc/nginx/conf.d/domain.com.conf

add the link to w3tc nginx.conf file wherever you store it in server { your website/domain config here }

server {
    listen       80;
    server_name  namhuy.net;
    root /var/www/namhuy.net;
    index index.php;
# your other nginx config, add include link before you close server loop
#
include /var/www/namhuy.net/nginx.conf;
       }
Another way to make w3tc nginx.conf file to work is to add w3tc nginx rules directly to your nginx domain/website .conf file. By doing this way, you do not have to create new nginx.conf under your website root directory.
# nano /etc/nginx/conf.d/default.conf
or
# nano /etc/nginx/conf.d/domain.com.conf
and add full w3tc nginx rules
server {
    listen       80;
    server_name  namhuy.net;
    root /var/www/namhuy.net;
    index index.php;
# your other nginx config, add full w3tc nginx.conf content before you close server loop
#
full w3tc nginx.conf's content goes here
       }

If you are using shared hosting and you don’t have access to nginx configure files, ask your hosting provider to use “include” to link to the nginx.conf under your website/domain root directory.

Disable Nginx access log

Generally you don’t need nginx access log, if you have a busy website, nginx access log will be easily increased in GB daily which will waste your hosting disk space. By default nginx access log is on, you can find and adjust nginx access log in nginx.conf file

# nano /etc/nginx/nginx.conf

You should see something like this

access_log /var/log/nginx/access.log;

You can’t just comment that line out with hash sign #, that won’t turn access_log off. You have to change nginx access_log to off to turn it off

access_log off;

 

Leave a Comment

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