Nginx is a free, open-source, high-performance HTTP web-server which unlike some other web-servers, it does not rely on threaded handling of the requests but instead it uses a much more scalable event driven (asynchronous) architecture.
This uses a very small and predictable amount of memory under heavy load. Nginx in combination with the simple and very robust FastCGI Process Manager for PHP (PHP-FPM) and the world most popular database server MySQL can give you a lot of power and performance while still using a small memory footprint.
The following article is all about how to install and configure LEMP Stack on a CentOS 6 VPS and host blazing fast WordPress powered web applications.
The article is split in the following sections:
- Initial set-up
- Install and configure Nginx
- Install and configure MySQL
- Install and configure PHP-FPM
- Install and set-up WordPress
- Set-up caching for best performance
## screen -U -S lemp-stack
Once you’re in the screen session, make sure your CentOS 6 VPS is fully up-to-date by executing:
## yum update
if you have Apache installed on your VPS, stop it and remove it by executing:
## /etc/init.d/httpd stop ## yum remove httpd
enable the epel repository by running:
find your VPS architecture by running uname -m
– 32bit VPS:
## wget -P /tmp http://mirror.pnl.gov/epel/6/i386/epel-release-6-8.noarch.rpm ## rpm -Uvh /tmp/epel-release-6-8.noarch.rpm ## rm -f /tmp/epel-release-6-8.noarch.rpm
– 64bit VPS:
## wget -P /tmp http://mirror.itc.virginia.edu/fedora-epel/6/x86_64/epel-release-6-8.noarch.rpm ## rpm -Uvh /tmp/epel-release-6-8.noarch.rpm ## rm -f /tmp/epel-release-6-8.noarch.rpm
verify everything is up-to-date
## yum update
Install Nginx
via yum by running:
## yum install nginx
Navigate to Nginx’s config directory in /etc/nginx/
and edit nginx.conf
with your favorite editor:
## cd /etc/nginx/ ## vim nginx.conf
user nginx; worker_processes 2; error_log /var/log/nginx/error.log; #error_log /var/log/nginx/error.log notice; #error_log /var/log/nginx/error.log info; pid /var/run/nginx.pid; events { worker_connections 1024; } http { include /etc/nginx/mime.types; default_type application/octet-stream; log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; access_log /var/log/nginx/access.log main; sendfile on; #tcp_nopush on; #keepalive_timeout 0; keepalive_timeout 30; server_tokens off; gzip on; gzip_disable "MSIE [1-6]\.(?!.*SV1)"; gzip_http_version 1.1; gzip_vary on; gzip_proxied any; gzip_comp_level 6; gzip_buffers 16 8k; gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript application/javascript text/x-js; # enabled sites include /etc/nginx/sites-enabled/*; }
create sites-enabled
and sites-available
inside the /etc/nginx
directory:
## mkdir -p /etc/nginx/sites-available /etc/nginx/sites-enabled
set-up default Nginx virtual host directive by adding the following in /etc/nginx/sites-available/default.conf
server { listen 80 default_server; server_name _; location / { root /usr/share/nginx/html; index index.html index.htm; } error_page 404 /404.html; location = /404.html { root /usr/share/nginx/html; } error_page 500 502 503 504 /50x.html; location = /50x.html { root /usr/share/nginx/html; } }
enable the default Nginx virtual host directive by creating symbolic link to the default vhost configuration in /etc/nginx/sites-enabled/
## cd /etc/nginx/sites-enabled ## ln -s /etc/nginx/sites-available/default.conf
test Nginx’s configuration, add it to your system startup and finally fire it up by:
## nginx -t ## /etc/init.d/nginx restart ## chkconfig nginx on
install MySQL database server, start and add it to your system start-up by running the following commands:
## yum install mysql mysql-server ## service mysqld restart ## chkconfig mysqld on
next, run the command below in order to set-up MySQL
## mysql_secure_installation
Enter current password for root (enter for none): Set root password? [Y/n] y Remove anonymous users? [Y/n] y Disallow root login remotely? [Y/n] y Remove test database and access to it? [Y/n] y Reload privilege tables now? [Y/n] y
make sure your MySQL is not exposed to listen on your server’s public IP by adding the following to /etc/my.cnf
## vim /etc/my.cnf [mysqld] bind-address = 127.0.0.1 ...
restart the database server for the changes to take effect by:
## /etc/init.d/mysqld restart
install PHP-FPM
and some useful PHP extensions by executing the command below:
## yum install php-fpm php-mysql php-gd php-mcrypt
edit /etc/php.ini
and change/uncomment the following:
cgi.fix_pathinfo=0 date.timezone = America/New_York memory_limit = 64M expose_php = Off
next, edit /etc/php-fpm.conf
with your favorite editor and uncomment the following:
emergency_restart_threshold = 10 emergency_restart_interval = 1m process_control_timeout = 10
with all that in place, set-up a PHP-FPM pool in /etc/php-fpm.d/www.conf
:
## mv /etc/php-fpm.d/www.conf /root/ ## vim /etc/php-fpm.d/www.conf
[wordpress] ;listen = 127.0.0.1:9001 listen = /var/run/php-wordpress.socket user = nginx group = nginx request_slowlog_timeout = 5s slowlog = /var/log/php-fpm/blogcms.log listen.allowed_clients = 127.0.0.1 pm = dynamic pm.max_children = 10 pm.start_servers = 3 pm.min_spare_servers = 2 pm.max_spare_servers = 4 pm.max_requests = 400 listen.backlog = -1 pm.status_path = /status request_terminate_timeout = 120s rlimit_files = 131072 rlimit_core = unlimited catch_workers_output = yes php_value[session.save_handler] = files php_value[session.save_path] = /var/lib/php/session php_admin_value[error_log] = /var/log/php-fpm/wordpress-error.log php_admin_flag[log_errors] = on
restart PHP-FPM and add it to your system startup:
## /etc/init.d/php-fpm restart ## chkconfig php-fpm on
at this point you should have Nginx, MySQL and PHP-FPM up and running on your server. Proceed with creating a vhost directive for your WordPress application:
## vim /etc/nginx/sites-available/my-wordpress.tld.conf
server { listen 80; server_name my-wordpress.tld; rewrite ^(.*) http://www.my-wordpress.tld$1 permanent; } server { listen 80; server_name www.my-wordpress.tld; client_max_body_size 5m; client_body_timeout 60; access_log /var/log/nginx/my-wordpress.tld-access; error_log /var/log/nginx/my-wordpress.tld-error error; root /var/www/html/my-wordpress.tld/; index index.html index.php; ### root directory ### location / { try_files $uri $uri/ /index.php?$args; } ### security ### error_page 403 =404; location ~ /\. { access_log off; log_not_found off; deny all; } location ~ ~$ { access_log off; log_not_found off; deny all; } location ~* wp-admin/includes { deny all; } location ~* wp-includes/theme-compat/ { deny all; } location ~* wp-includes/js/tinymce/langs/.*\.php { deny all; } location /wp-includes/ { internal; } #location ~* wp-config.php { deny all; } location ~* ^/wp-content/uploads/.*.(html|htm|shtml|php)$ { types { } default_type text/plain; } # location ~* wp-admin { # allow <YOUR_IP>; # allow 127.0.0.1; # deny all; # } ### disable logging ### location = /robots.txt { access_log off; log_not_found off; } location = /favicon.ico { access_log off; log_not_found off; } ### caches ### location ~* \.(jpg|jpeg|gif|css|png|js|ico|html)$ { access_log off; expires max; } location ~* \.(woff|svg)$ { access_log off; log_not_found off; expires 30d; } location ~* \.(js)$ { access_log off; log_not_found off; expires 7d; } ### php block ### location ~ \.php?$ { try_files $uri =404; include fastcgi_params; #fastcgi_pass 127.0.0.1:9001; fastcgi_pass unix:/var/run/php-wordpress.socket; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_intercept_errors on; fastcgi_split_path_info ^(.+\.php)(.*)$; #Prevent version info leakage fastcgi_hide_header X-Powered-By; } }
enable the virtual host directive and restart nginx by running the following commands:
## cd /etc/nginx/sites-enabled ## ln -s /etc/nginx/sites-available/my-wordpress.tld.conf ## nginx -t ## /etc/init.d/nginx restart
test PHP-FPM by creating PHP info.php
script in your vhost document root in /var/www/html/my-wordpress.tld/
:
## mkdir -p /var/www/html/my-wordpress.tld/ ## cd /var/www/html/my-wordpress.tld/ ## echo -e "<?php\n\tphpinfo();\n" > info.php
access http://my-wordpress.tld/info.php
to test your PHP-FPM
Next step is to install WordPress inside your vhost document root in /var/www/html/my-wordpress.tld/
. Before installing WordPress, let’s first create a MySQL database by running:
## mysql -u root -p
mysql> create database wordpressDB; mysql> grant all on wordpressDB.* to wpUser@localhost identified by 'YOUR_PASS'; mysql> quit
## cd /var/www/html/my-wordpress.tld/ ## wget http://wordpress.org/latest.zip ## unzip latest.zip ## mv wordpress/* . ## rm -rf latest.zip wordpress/
next, copy WordPress sample config and set-up your MySQL database information:
## cp wp-config-sample.php wp-config.php ## vim wp-config.php
define('DB_NAME', 'wordpressDB'); define('DB_USER', 'wpUser'); define('DB_PASSWORD', 'YOUR_PASS');
## chown nginx: -R /var/www/html/my-wordpress.tld/
open http://my-wordpress.tld and complete your WordPress installation
Install PHP-APC (Alternative PHP Cache) by running:
## yum install php-pecl-apc
once APC is installed, add the following to /etc/php.d/apc.ini
## cat > /etc/php.d/apc.ini
extension = apc.so apc.enabled=1 apc.shm_segments=1 apc.shm_size=128M apc.num_files_hint=1024 apc.user_entries_hint=4096 apc.ttl=7200 apc.use_request_time=1 apc.user_ttl=7200 apc.gc_ttl=3600 apc.cache_by_default=1 apc.filters apc.mmap_file_mask=/tmp/apc.XXXXXX apc.file_update_protection=2 apc.enable_cli=0 apc.max_file_size=1M apc.stat=1 apc.stat_ctime=0 apc.canonicalize=0 apc.write_lock=1 apc.report_autofilter=0 apc.rfc1867=0 apc.rfc1867_prefix =upload_ apc.rfc1867_name=APC_UPLOAD_PROGRESS apc.rfc1867_freq=0 apc.rfc1867_ttl=3600 apc.include_once_override=0 apc.lazy_classes=0 apc.lazy_functions=0 apc.coredump_unmap=0 apc.file_md5=0 apc.preload_path
and restart PHP-FPM for the changes to take effect.
## /etc/init.d/php-fpm restart
check if APC is loaded by running:
## php -m | grep -w apc
or by opening the info.php
script in your document root.
Next thing to do is to login to your WordPress administration and install the W3 Total Cache Plugin. For W3 Total Cache Plugin to work you have to first enable Pretty URLs
in
Settings->Permalinks->Custom Structure
:
http://my-wordpress.tld/%postname%/
and then proceed with installing the W3 Total Cache
. Once installed, go to
Performance->General Settings
and enable/disable the following options:
Page cache: enabled Page cache method: Disk: Enhaced Minify: disabled Database Cache: enabled Database Cache Method: Opcode: Alternative PHP Cache (APC) Object Cache: enbabled Object Cache Method: Opcode: Alternative PHP Cache (APC) Browser Cache: disabled CDN: this is up to you.
Click Save all settings
to submit the changes.
Add the following in /var/www/html/my-wordpress.tld/nginx.conf
## cat > /var/www/html/my-wordpress.tld/nginx.conf
# BEGIN W3TC Page Cache cache location ~ /wp-content/cache/page_enhanced.*html$ { add_header Vary Cookie; } # END W3TC Page Cache cache # 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 ($request_uri !~ \/$) { 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 (!-f "$document_root/wp-content/cache/page_enhanced/$http_host/$request_uri/_index.html") { set $w3tc_rewrite 0; } if ($w3tc_rewrite = 1) { rewrite .* "/wp-content/cache/page_enhanced/$http_host/$request_uri/_index.html" last; } # END W3TC Page Cache core
make sure the ownership of the document root is ok by:
## chown nginx: -R /var/www/html/my-wordpress.tld/
The next step is to tell Nginx to use this configuration file. Edit /etc/nginx/sites-enabled/my-wordpress.tld.conf
and add/uncomment the following:
include /var/www/html/my-wordpress.tld/nginx.conf; ... location ~* wp-config.php { deny all; }
test Nginx’s configuration file and restart it for the changes to take effect by executing:
## nginx -t ## /etc/init.d/nginx restart
You can also edit your WordPress configuration file /var/www/html/my-wordpress.tld/wp-config.php
and define the following so WordPress will not have to query the database for the site url:
define('WP_HOME', 'http://my-wordpress.tld'); define('WP_SITEURL', 'http://my-wordpress.tld');
Of course, if you are one of our Linux VPS Hosting customers, you don’t have to do any of this, simply ask our admins, sit back and relax. Our admins will set this up for you immediately.
PS. If you liked this post please share it with your friends on the social networks using the buttons on the left or simply leave a reply below. Thanks.
One of the best tutorials that I have found at internet! Soon I have enough money I will move my VPS to yours.
Thanks!
nothing of your commands are working
Hi Haydrion,
can you be more specific and explain what commands are not working for you?
Hi, I had a few pre-sales questions. If I purchase a managed VPS from you, do you handle setting up all these programs for me (i.e. LEMP stack with APC and easy setup of multiple WordPress sites)? Also, what location(s) do you offer for hosting the VPS and what type of connection speed is available to the server? I am wanting to host my clients sites on a fast, reliable & robust VPS. Thanks for providing such a great tutorial.
Silas
We have sent you an email with answers to your questions a couple of minutes ago.
Thanks.
Hi,
I am getting stuck in step 3) unable to install PHP-FPM terminal output follows
mahinth@mahinthjoe.com [/etc/nginx]# sudo yum install php-fpm php-mysql php-gd php-mcrypt
Loaded plugins: fastestmirror
Loading mirror speeds from cached hostfile
* base: centos.host-engine.com
* epel: kdeforge2.unl.edu
* extras: mirrors.unifiedlayer.com
* remi: mirrors.mediatemple.net
* remi-php55: mirrors.mediatemple.net
* updates: mirror.hmc.edu
Setting up Install Process
No package php-fpm available.
No package php-mysql available.
No package php-gd available.
No package php-mcrypt available.
Error: Nothing to do
Simple remove php* from exclude= in /etc/yum.conf !