Install LEMP Stack (Nginx, MariaDB, PHP7.2) on RHEL 8/CentOS 8

This tutorial is going to show you how to install LEMP stack on RHEL 8 and CentOS 8.

What’s LEMP Stack?

A software stack is a set of software tools bundled together. LEMP stands for Linux, Nginx (pronounced engine X), MariaDB/MySQL and PHP, all of which are open source. It is the most common software stack that powers dynamic websites and web applications. Linux is the operating system; Nginx is the web server; MariaDB/MySQL is the database server and PHP is the server-side scripting language responsible for generating dynamic web pages.

Prerequisites

You can download and install RHEL 8 by following the tutorial below.

If you are looking for a VPS (Virtual Private Server), then you can register an account at Vultr via my referral link to get $50 free credit for use over 30 days.

This tutorial uses root account to manage administration tasks. To switch to root, run the following command and enter root password.

su -

Step 1: Install Nginx Web Server on RHEL 8/CentOS 8

Nginx is a high performance web server and very popular these days. It also can be used as a reverse proxy and caching server. Enter this command to install Nginx Web server.

yum install nginx -y

After it’s installed, we can start Nginx with this command:

systemctl start nginx

Enable Nginx to auto start at system boot time by running the following command.

systemctl enable nginx

Now check its status.

systemctl status nginx

Output:

 nginx.service - The nginx HTTP and reverse proxy server
   Loaded: loaded (/usr/lib/systemd/system/nginx.service; enabled; vendor preset: disabled)
   Active: active (running) since Wed 2018-12-05 02:04:00 EST; 7s ago
 Main PID: 5032 (nginx)
    Tasks: 2 (limit: 11512)
   Memory: 8.4M
   CGroup: /system.slice/nginx.service
           ├─5032 nginx: master process /usr/sbin/nginx
           └─5034 nginx: worker process

Enabled” indicates that auto start at boot time is enabled and we can see that Nginx is running. Notice that the above command will not immediately quit after running. You need to press “q” to make it quit.

Check Nginx version.

nginx -v

Output:

nginx version: nginx/1.14.1

If you are installing LEMP on your local RHEL 8/CentOS 8 computer, then type 127.0.0.1 or localhost in the browser address bar. You should see the “Welcome to Nginx” Web page, which means Nginx Web server is running properly.

install Nginx on CentOS 8 RHEL 8

By default, RHEL 8/CentOS 8 forbids public access to port 80. To allow other computers to access the web page, we need to open port 80 in firewalld, the dynamic firewall manager on RHEL/CentOS. Run the following command to open port 80.

firewall-cmd --permanent --zone=public --add-service=http

If you want to enable HTTPS on Nginx later, then you also need to open port 443.

firewall-cmd --permanent --zone=public --add-service=https

The --permanent option will make this firewall rule persistent across system reboots. Next, reload the firewall daemon for the change to take effect.

systemctl reload firewalld

Now the Nginx web page is accessible publicly.

Finally, we need to make user nginx as the owner of web directory. By default it’s owned by the root user.

chown nginx:nginx /usr/share/nginx/html -R

Step 2: Install MariaDB Database Server on RHEL 8/CentOS 8

MariaDB is a drop-in replacement for MySQL. It is developed by former members of MySQL team who are concerned that Oracle might turn MySQL into a closed-source product. Enter the following command to install MariaDB on RHEL 8/CentOS 8.

yum install mariadb-server mariadb -y

After it’s installed, we need to start it.

systemctl start mariadb

Enable auto start at system boot time.

systemctl enable mariadb

Check status:

systemctl status mariadb

output:

 mariadb.service - MariaDB 10.3 database server
   Loaded: loaded (/usr/lib/systemd/system/mariadb.service; enabled; vendor preset: disable>
   Active: active (running) since Wed 2018-12-05 02:40:44 EST; 8s ago
     Docs: man:mysqld(8)
           https://mariadb.com/kb/en/library/systemd/
 Main PID: 17582 (mysqld)
   Status: "Taking your SQL requests now..."
    Tasks: 30 (limit: 11512)
   Memory: 75.2M
   CGroup: /system.slice/mariadb.service
           └─17582 /usr/libexec/mysqld --basedir=/usr

Enabled” indicates that auto start at boot time is enabled and we can see that MariaDB server is running. Now we need to run the security script.

mysql_secure_installation

When it asks you to enter MariaDB root password, press Enter key as the root password isn’t set yet. Then enter y to set the root password for MariaDB server.

install mariadb on redhat 8 centos 8

Next, you can press Enter to answer all remaining questions, which will remove anonymous user, disable remote root login and remove test database. This step is a basic requirement for MariaDB database security. (Note that the letter Y is capitalized, which means it’s the default answer.)

mysql_secure_installation rhel8 centos8

Now you can run the following command and enter MariaDB root password to log into MariaDB shell.

mysql -u root -p

mariadb shell login

To exit, run

exit;

Step 3: Install PHP-FPM on RHEL 8/CentOS 8

Install PHP and related modules using the following command:

yum install php php-mysqlnd php-fpm php-opcache php-gd php-xml php-mbstring -y

After it’s installed, we need to start it.

systemctl start php-fpm

Enable auto start at system boot time.

systemctl enable php-fpm

Check status:

systemctl status php-fpm

output:

 php-fpm.service - The PHP FastCGI Process Manager
   Loaded: loaded (/usr/lib/systemd/system/php-fpm.service; enabled; vendor preset: disable>
   Active: active (running) since Wed 2018-12-05 03:06:01 EST; 22s ago
 Main PID: 18631 (php-fpm)
   Status: "Processes active: 0, idle: 5, Requests: 0, slow: 0, Traffic: 0req/sec"
    Tasks: 6 (limit: 11512)
   Memory: 29.6M
   CGroup: /system.slice/php-fpm.service
           ├─18631 php-fpm: master process (/etc/php-fpm.conf)
           ├─18632 php-fpm: pool www

Enabled” indicates that auto start at boot time is enabled and we can see that PHP-FPM is running. Now edit the PHP-FPM config file:

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

By default, PHP-FPM runs as the apache user. Since we are using Nginx web server, we need to change it. Find the following two lines.

user = apache
group = apache

Change them to

user = nginx
group = nginx

In this file you can find the following line.

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

This indicates that PHP-FPM is listening on a Unix socket instead of a TCP/IP socket, which is good. Save and close the file. Reload PHP-FPM for the changes to take effect.

systemctl reload php-fpm

Step 4: Test PHP

By default, the Nginx package on RHEL 8/CentOS 8 includes configurations for PHP-FPM (/etc/nginx/conf.d/php-fpm.conf and /etc/nginx/default.d/php.conf). To test PHP-FPM with Nginx Web server, we need to create a info.php file in the document root directory.

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

Paste the following PHP code into the file.

<?php phpinfo(); ?>

Save and close the file. If you installed LEMP stack on a local RHEL 8/CentOS 8 server, type in 127.0.0.1/info.php or localhost/info.php in the browser address bar. You should see your server’s PHP information. This means PHP scripts can run properly with Nginx web server.

If RHEL 8/CentOS is running on a remote server, then enter server-ip-address/info.php in browser address bar. Replace sever-ip-address with your actual IP address.

PHP-FPM RHEL 8 CentOS 8

If the browser fails to display the PHP info but prompt you to download the info.php file, simply restart Nginx and PHP-FPM.

sudo systemctl restart nginx php-fpm

Then you should be able to see the PHP info in the web browser.

Nginx Automatic Restart

If for any reason your Nginx process is killed, you need to run the following command to restart it.

sudo systemctl restart nginx

Instead of manually typing this command, we can make Nginx automatically restart by editing the nginx.service systemd service unit. To override the default systemd service configuration, we create a separate directory.

sudo mkdir -p /etc/systemd/system/nginx.service.d/

Then create a file under this directory.

sudo nano /etc/systemd/system/nginx.service.d/restart.conf

Add the following lines in the file, which will make Nginx automatically restart 5 seconds after a failure is detected.

[Service]
Restart=always
RestartSec=5s

Save and close the file. Then reload systemd.

sudo systemctl daemon-reload

To check if this would work, kill Nginx with:

sudo pkill nginx

Then check Nginx status. You will find Nginx automatically restarted.

systemctl status nginx

Wrapping Up

Congrats! You have successfully installed Nginx, MariaDB and PHP7.2 on Red Hat 8 or CentOS 8. For your server’s security, you should delete info.php file now to prevent hacker seeing it.

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

I hope this tutorial helped you. As always, if you found this post useful, then subscribe to our free newsletter to get more tips and tricks. Take care 🙂

Rate this tutorial
[Total: 4 Average: 4.5]

28 Responses to “Install LEMP Stack (Nginx, MariaDB, PHP7.2) on RHEL 8/CentOS 8

  • StarFerry
    5 years ago

    Thanks.

  • When I do this, the localhost/info.hp address just downloads a txt file named info.php.

    Everything up to this point worked perfectly. I believe that the server is not actually executing the .php code. Do you have any ideas on how to fix this?

    Thanks

    • Xiao Guo An (Admin)
      4 years ago

      If the browser fails to display the PHP info but prompt you to download the info.php file, simply restart Nginx and PHP-FPM.

      sudo systemctl restart nginx php-fpm

      Then you should be able to see the PHP info.

  • Add this section to your nginx.conf to execute php files:

            location ~ \.php$
            {
                try_files      $uri =404;
    
                include        fastcgi_params;
    
                fastcgi_pass   127.0.0.1:9000;
    
                fastcgi_connect_timeout 10s;     
                fastcgi_read_timeout 300s;      
    
                fastcgi_param HTTP_PROXY "";
    
                fastcgi_index  index.php;
    
                fastcgi_param  PATH_INFO $fastcgi_script_name;
    
                fastcgi_param  SCRIPT_FILENAME $document_root$fastcgi_script_name;
            }
    

    Then reload nginx:

    sudo service nginx reload
    • Xiao Guo An (Admin)
      4 years ago

      PHP-FPM by default listens on the /run/php-fpm/www.sock Unix socket, instead of the 127.0.0.1:9000 TCP socket.

      If the browser fails to display the PHP info but prompt you to download the info.php file, simply restart Nginx and PHP-FPM.

      sudo systemctl restart nginx php-fpm

      Then you should be able to see the PHP info in the web browser.

  • Following these instructions first I had issues with SELinux not letting me restart php-fpm, then I followed the instructions in the warning and it still fails to start php-fpm:

    failed to write the ACL of the socket ‘/run/php-fpm/www.sock’: Invalid argument

    • Xiao Guoan (Admin)
      4 years ago

      I think you need to run the following command:

      sudo setsebool -P httpd_execmem 1
      • After correcting the way I was changing the user and group from apache to nginx it just works. Don’t have to do any SELinux stuff.

  • Thanks for the article. I’m trying to make it easier to install Nextcloud on CentOS 8 and this is the first step. Using your article as a guide I’ve created an Ansible playbook that will get LEMP running on a CentOS 8 server. https://github.com/FlexibleToast/CentOS-8-LEMP. I’m still working on the Nextcloud playbook that will also include LEMP installation.

  • Gökay Eren
    4 years ago

    After this guide. I can not connect my Open VPN server from public ip. Also The php file not showing. Just download section. This guide need to update.

    • Xiao Guoan (Admin)
      4 years ago

      This guide is accurate and certainly won’t interfere with OpenVPN.

      • Gökay Eren
        4 years ago

        It was my mistake I think. But still php not working. When I try to go info.php, it show me download section.

  • Your guide was terrific, thank you so much! Just one question for you though..

    If I’m syncing a folder via the desktop app that has a bunch of large files, everything works fine. However, if I try to sync a folder with thousands of small files I start to get Serialization failure: 1213 Deadlock found when trying to get lock; try restarting transaction

    I’ve googled around and found people suggest:

    Add the following three lines in [mysqld] section.

    log-bin = /var/log/mysql/mariadb-bin
    log-bin-index = /var/log/mysql/mariadb-bin.index
    binlog_format = mixed

    But that has not fixed it. Are you aware of any database tweaking that would help? Do you have an example of your my.cnf that might help lead me in the right direction?

    • Xiao Guoan (Admin)
      4 years ago

      You are asking a question unrelated to this article. I don’t know what is the desktop app you are referring to.

      • Paul Toone
        4 years ago

        The nextcloud desktop app. Either way, related in that I’m just asking if you did any customizations in your my.cnf

    • Xiao Guoan (Admin)
      4 years ago

      I don’t have customization in my.cnf. This error is usually caused by the web app code. You should report this error to Nextcloud developers.

  • Thanks! Got me up and running on my first linode in 10 minutes 🙂

  • great guide, thanks!

  • The first tutorial that I successfully can install LEMP. Thank youuuu.

  • Roland Deschain
    4 years ago

    Just FYI, for step four I had to chown the info.php file to nginx:nginx (it was root:root) for it to work. Otherwise, web browsers just downloaded the info.php file rather than displaying it in the browser.

  • I am facing the localhost/info.hp address just downloads a txt file named info.php.
    But centos 8 update , Problem is solve.

    Thanks..

  • Joel M.
    3 years ago

    Hello! First of all, thank you for writing such a wonderful tutorial.

    I’m having a similar problem as mentioned by others regarding https://domain/info.php being downloaded instead of executed in browser.

    I have been following along with your tutorial, setting up an email server in centOS.

    I have double checked everything and I still can’t find where the problem might be.

    VPS: vultr

    OS:

        NAME="CentOS Linux"
    VERSION="8 (Core)"
    ID="centos"
    ID_LIKE="rhel fedora"
    VERSION_ID="8"
    PLATFORM_ID="platform:el8"
    PRETTY_NAME="CentOS Linux 8 (Core)"
    ANSI_COLOR="0;31"
    CPE_NAME="cpe:/o:centos:centos:8"
    HOME_URL="https://www.centos.org/"
    BUG_REPORT_URL="https://bugs.centos.org/"
    
    CENTOS_MANTISBT_PROJECT="CentOS-8"
    CENTOS_MANTISBT_PROJECT_VERSION="8"
    REDHAT_SUPPORT_PRODUCT="centos"
    REDHAT_SUPPORT_PRODUCT_VERSION="8"
    

    nginx -v:

        nginx version: nginx/1.14.1
    

    When I visit https://my-domain I see the Welcome to nginx page.

    firewall-cmd –list-services

    cockpit dhcpv6-client http https imap imaps smtp-submission smtps ssh

    systemctl status php-fpm: Active and running, no errors. Not sure if this is important but CGroup: /system.slice/php-fpm.servic is:

        ├─3395 php-fpm: master process (/etc/php-fpm.conf)
               ├─3406 php-fpm: pool www
               ├─3407 php-fpm: pool www
               ├─3408 php-fpm: pool www
               ├─3409 php-fpm: pool www
               └─3410 php-fpm: pool www
    

    Ownership of /usr/share/nginx/html is nginx:nginx:

    total 28
    -rw-r--r--. 1 nginx nginx 3971 Oct  7  2019 404.html
    -rw-r--r--. 1 nginx nginx 4020 Oct  7  2019 50x.html
    -rw-r--r--. 1 nginx nginx 4057 Oct  7  2019 index.html
    -rw-r--r--. 1 nginx nginx   20 Oct  5 13:23 info.php
    -rw-r--r--. 1 nginx nginx  368 Oct  7  2019 nginx-logo.png
    -rw-r--r--. 1 nginx nginx 4148 Oct  7  2019 poweredby.png
    

    Step 2: Install MariaDB
    I installed it as outlined in the tutorial

    Step 3: Install PHP-FPM on CentOS 8
    All php and related modules installed:

    # yum install php php-mysqlnd php-fpm php-opcache php-gd php-xml php-mbstring -y
    Last metadata expiration check: 2:25:22 ago on Mon 05 Oct 2020 11:29:32 AM UTC.
    Package php-7.2.24-1.module_el8.2.0+313+b04d0a66.x86_64 is already installed.
    Package php-mysqlnd-7.2.24-1.module_el8.2.0+313+b04d0a66.x86_64 is already installed.
    Package php-fpm-7.2.24-1.module_el8.2.0+313+b04d0a66.x86_64 is already installed.
    Package php-opcache-7.2.24-1.module_el8.2.0+313+b04d0a66.x86_64 is already installed.
    Package php-gd-7.2.24-1.module_el8.2.0+313+b04d0a66.x86_64 is already installed.
    Package php-xml-7.2.24-1.module_el8.2.0+313+b04d0a66.x86_64 is already installed.
    Package php-mbstring-7.2.24-1.module_el8.2.0+313+b04d0a66.x86_64 is already installed.
    Dependencies resolved.
    Nothing to do.
    Complete!
    

    systemctl shows php-fpm.service to be active and enabled, no erros. The PHP FastCGI Process Manager is running.

    The /etc/php-fpm.d/www.conf user & group edit:

        ; 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 user chosen to provide access to the same directories as httpd
        user = nginx
        ; RPM: Keep a group allowed to write in log dir.
        group = nginx
    

    Also,

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

    is uncomented just as it should be. I didn’t touch it.

    I created the info.php file and added

    
    

    to it.

        # ls -l
        total 28
        -rw-r--r--. 1 nginx nginx 3971 Oct  7  2019 404.html
        -rw-r--r--. 1 nginx nginx 4020 Oct  7  2019 50x.html
        -rw-r--r--. 1 nginx nginx 4057 Oct  7  2019 index.html
        -rw-r--r--. 1 nginx nginx   20 Oct  5 13:23 info.php
        -rw-r--r--. 1 nginx nginx  368 Oct  7  2019 nginx-logo.png
        -rw-r--r--. 1 nginx nginx 4148 Oct  7  2019 poweredby.png
    

    I changed the user:group from root:root to nginx:nginx. Even when I leave it as root:root it does not work.

    I restart nginx and php-fpm without a problem. The status for both service is error free.

    I vist https://my-domain/info.php and it wants to download the info.php file instead of showing it in browser.
    I visited the info.php page on my phone, same results.
    I visited the info.php page on firefox (the first time I visit it so not in cache), same result.

    I don’t know what is wrong…

    • Joel M.
      3 years ago

      Just wanted to clarify a details that got clipped out when I posted.

      I created the info.php file and added

      I added the php code:

       php phpinfo() 

      I entered it like the tutorial has it, when I post it here it clipped out for some reason so I’m posting it here without the tags.

      • it does not work and downloads info.php because probably if you followed these manuals, default website configuration in /etc/nginx/conf.d is made by certbot and it is missing php location.

        See my comment below

        Add:

        
         location = favicon.ico { access_log off; log_not_found off; }
              index  index.php;
              location / {
                   try_files $uri $uri/ =404;
              }
             location ~ \.php$ {
               fastcgi_pass php-fpm;
               fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
               include fastcgi_params;
             }
        
  • it does not work and downloads info.php because probably if you followed these manuals, default website configuration in /etc/nginx/conf.d is made by certbot and it is missing php location.

    So all you have to do is add:

    server {
          server_name domain-name.com;
    
          root /usr/share/nginx/html/;
    
          location ~ /.well-known/acme-challenge {
             allow all;
          }
    
          location = favicon.ico { access_log off; log_not_found off; }
          index  index.php;
          location / {
               try_files $uri $uri/ =404;
          }
         location ~ \.php$ {
           fastcgi_pass php-fpm;
           fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
           include fastcgi_params;
         }
    
    
    
    
  • thanks, work like a charm

  • Everyone, please be remind that comment upstream web and proxy_pass, add location ~ .php$

Leave a Comment

  • Comments with links are moderated by admin before published.
  • Your email address will not be published.
  • Use <pre> ... </pre> HTML tag to quote the output from your terminal/console.
  • Please use the community (https://community.linuxbabe.com) for questions unrelated to this article.
  • I don't have time to answer every question. Making a donation would incentivize me to spend more time answering questions.

The maximum upload file size: 2 MB. You can upload: image. Links to YouTube, Facebook, Twitter and other services inserted in the comment text will be automatically embedded. Drop file here