How to Setup LEMP (Linux NGINX MySQL PHP) on CentOS 7

Try it in our public cloud & Get $5 Credit
CLAIM NOW

The Linux, Nginx, MySQL, PHP (LEMP) stack is a popular set of technologies for running commodity web applications and sites. This variation of the stack replaces Apache with Nginx, a lighter web server that is a better fit for smaller-footprint servers, or with anyone who needs more performance. Unlike the venerable LAMP stack, LEMP runs PHP scripts in a separate process, which has different implications for securing and scaling PHP-based web applications.

Getting Started

Confirm that you have the following before you follow this guide:
• 1 Node (Cloud Server or Dedicated Server) running CentOS 7.
• Root access to the node.

Tutorial

Start by applying all available updates. This critical step should be performed regularly. It will apply all outstanding security patches and bugfixes for everything installed on your server.

yum update -y
reboot

Now we’ll add the CentOS 7 EPEL repository. This grants access to some packages we’ll need to install later.

yum install epel-release

For this tutorial, we’ll use MariaDB instead of MySQL. MariaDB is a backwards-compatible community MySQL fork with various enhancements that make it a better fit for modern web applications. In general, MySQL and MariaDB are interchangeable, but MariaDB is a better choice if it is available to you.

yum install mariadb-server mariadb

Next we start the server so it will begin accepting connections.

systemctl start mariadb

MariaDB must now be secured. Here we set the root password, which is needed to create databases and grant permissions. Keep this password secure, and don’t use your server’s root password. Use something unique, memorable, and difficult to guess.

mysql_secure_installation

Set root password? [Y/n]
New password:
Re-enter new password:
Password updated successfully!
Reloading privilege tables..
... Success!

By default, a MariaDB installation has an anonymous user, allowing anyone to log into MariaDB without having to have a user account created for them. This is intended only for testing, and to make the installation go a bit smoother. You should remove them before moving into a production environment.

Remove anonymous users? [Y/n] y
... Success!

Normally, root should only be allowed to connect from ‘localhost’. This ensures that someone cannot guess at the root password from the network.

Disallow root login remotely? [Y/n] y
... Success!

By default, MariaDB comes with a database named ‘test’ that anyone can access. This is also intended only for testing, and should be removed before moving into a production environment.

Remove test database and access to it? [Y/n] y
- Dropping test database...
... Success!
- Removing privileges on test database...
... Success!
Reloading the privilege tables will ensure that all changes made so far
will take effect immediately.
Reload privilege tables now? [Y/n] y
... Success!
Cleaning up...
All done! If you've completed all of the above steps, your MariaDB
installation should now be secure.
Thanks for using MariaDB!

MariaDB is started, but it currently won’t start automatically when your server boots up. This next command tells CentOS to start MariaDB when your server comes up.

systemctl enable mariadb.service

It is now time to install the Nginx web server. Start by installing the package itself.

yum install nginx -y

As with MariaDB, we must now start the Nginx server so it accepts connections.

systemctl start nginx.service

Also, as with MariaDB, we need to configure the Nginx server to start on boot.

systemctl enable nginx.service

PHP runs in a separate process, managed and configured by the php-fpm package. Let’s install that now.

yum install php php-mysql php-fpm

Again, we start the PHP-FPM daemon.

systemctl start php-fpm

We also enable it to start on boot.

systemctl enable php-fpm

All necessary servers and processes are running. We need to tell Nginx where the PHP-FPM process expects to receive scripts that it will run. Do this by editing the default virtual host configuration.

nano /etc/nginx/nginx.conf

[...]
# Load modular configuration files from the /etc/nginx/conf.d directory.
# See http://nginx.org/en/docs/ngx_core_module.html#include
# for more information.
include /etc/nginx/conf.d/*.conf;
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name 173.209.44.190;
root /usr/share/nginx/html;
index index.php index.html index.htm;
# Load configuration files for the default server block.
include /etc/nginx/default.d/*.conf;
location ~ \.php$ {
try_files $uri =404;
fastcgi_pass unix:/var/run/php-fpm/php-fpm.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
error_page 404 /404.html;
location = /40x.html {
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
[...]

Save and exit. Reload Nginx so the new configuration takes effect.

systemctl reload nginx.service

We’ll next configure the PHP process, making changes to improve security.

nano /etc/php.ini

Find the “cgi.fix_pathinfo” line, and then remove the comment symbol “;”. Change “1” to “0”. After the modifications, it should look like this:

; cgi.fix_pathinfo provides *real* PATH_INFO/PATH_TRANSLATED support for CGI. PHP's
; previous behaviour was to set PATH_TRANSLATED to SCRIPT_FILENAME, and to not grok
; what PATH_INFO is. For more information on PATH_INFO, see the cgi specs. Setting
; this to 1 will cause PHP CGI to fix its paths to conform to the spec. A setting
; of zero causes PHP to behave as before. Default is 1. You should fix your scripts
; to use SCRIPT_FILENAME rather than PATH_TRANSLATED.
; http://php.net/cgi.fix-pathinfo
; cgi.fix_pathinfo=1

Change the last line to:

; cgi.fix_pathinfo provides *real* PATH_INFO/PATH_TRANSLATED support for CGI. PHP's
; previous behaviour was to set PATH_TRANSLATED to SCRIPT_FILENAME, and to not grok
; what PATH_INFO is. For more information on PATH_INFO, see the cgi specs. Setting
; this to 1 will cause PHP CGI to fix its paths to conform to the spec. A setting
; of zero causes PHP to behave as before. Default is 1. You should fix your scripts
; to use SCRIPT_FILENAME rather than PATH_TRANSLATED.
; http://php.net/cgi.fix-pathinfo
cgi.fix_pathinfo=0

Save and exit. Next we’ll edit the php-fpm configuration and make several changes there.

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

Find the following lines:

listen = 127.0.0.1

;listen.owner = nobody
;listen.group = nobody

; 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 them to:

listen = /var/run/php-fpm/php-fpm.sock

listen.owner = nobody
listen.group = nobody

; RPM: apache Choosed to be able to access some dir as httpd
user = nginx
; RPM: Keep a group allowed to write in log dir.
group = nginx

With these configuration changes in place, we need to restart php-fpm. We’ll do that here.

systemctl restart php-fpm

Let’s ensure that everything is working. We’ll create a phpinfo page, a simple page that calls a diagnostic function. If everything works, you’ll see lots of details about your newly-configured PHP environment.

In your server’s document root directory, edit the file as shown:

nano /usr/share/nginx/html/info.php

<?php
phpinfo();
?>

Now access the newly-created page from your browser. Visit http://your_ip/info.php. If everything works, you’ll see a report about the PHP installation you’ve just set up.

Conclusion

With this LEMP setup in place, your server can now run WordPress, MediaWiki, and any number of standardized PHP applications. Share this article with anyone who wants to get up and running quickly with PHP on CentOS 7.