Install and configure Nginx, MariaDB & PHP-FPM in CentOS 7 (RHEL7)

https://stavrovski.net/blog/install-and-configure-nginx-mariadb-php-fpm-in-centos-7-rhel7

 

The following is a quick-N-dirty write-up on how to install and configure the LEMP stack (Nginx, MariaDB and PHP-FPM) in CentOS 7. I use this as a reference/guide whenever I need to deploy the LEMP stack on RHEL based machines.


TABLE OF CONTENTS

ENABLE EPEL REPOSITORY

Install wget and vim using yum if they’re not present on the CentOS 7 system:

if ! type -path "wget" > /dev/null 2>&1; then yum install wget -y; fi
if ! type -path "vim" > /dev/null 2>&1; then yum install vim -y; fi

Next, download the rpm package and install it using yum as in:

wget -P /tmp http://dl.fedoraproject.org/pub/epel/beta/7/x86_64/epel-release-7-0.2.noarch.rpm
yum install /tmp/epel-release-7-0.2.noarch.rpm
rm -f /tmp/epel-release-7-0.2.noarch.rpm

UPDATE THE SYSTEM

Ok, first thing to do before installing LEMP, is to make sure the CentOS 7 system is fully up-to-date by running the following command in your terminal:

yum update

if there is a kernel update, make sure you’re booted into it before proceeding further.

INSTALL AND CONFIGURE MARIADB DATABASE SERVER

Default database server in CentOS 7 (RHEL 7) is MariaDB now. It is a drop in replacement for MySQL and can be installed using yum, so install MariaDB using:

yum install mariadb mariadb-server

once installed, restart MariaDB using systemctl:

systemctl restart mariadb
systemctl status mariadb

optionally, set-up MariaDB server using the mysql_secure_installation post-installation script:

mysql_secure_installation

answer the questions when prompted, for example in my case:

  • 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

next, edit /etc/my.cnf.d/server.cnf and add bind-address = 127.0.0.1 within the [mysqld] block:

vim +/^[mysqld /etc/my.cnf.d/server.cnf

[mysqld]
bind-address = 127.0.0.1

restart MariaDB for the changes to take effect:

systemctl restart mariadb
systemctl status mariadb

verify MariaDB is listening on localhost only using the ss command:

ss -tnlp | grep 3306
LISTEN  0  0   127.0.0.1:3306  *:* users:(("mysqld",1159,14))

INSTALL AND CONFIGURE NGINX

Install Nginx on the CentOS 7 system using yum:

yum install nginx

next, navigate to /etc/nginx and backup your original Nginx configuration file

cd /etc/nginx
cp nginx.conf{,.orig}

and edit /etc/nginx.conf to look like the one below:

cat > nginx.conf

## NGINX MAIN CONFIGURATION FILE ##
user nginx nginx;
worker_processes 2;
error_log  /var/log/nginx/error.log info;
events {
    worker_connections  1024;
    use epoll;
}
http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;
    log_format main
                '$remote_addr - $remote_user [$time_local] '
                '"$request" $status $bytes_sent '
                '"$http_referer" "$http_user_agent" '
                '"$gzip_ratio"';
    access_log  /var/log/nginx/access.log  main;
    sendfile        on;
    tcp_nopush on;
    tcp_nodelay on;
    ignore_invalid_headers on;
    keepalive_timeout  30;
    server_tokens off;
    connection_pool_size 256;
    client_header_buffer_size 1k;
    large_client_header_buffers 4 2k;
    request_pool_size 4k;
    output_buffers 1 32k;
    postpone_output 1460;
    client_header_timeout 10m;
    client_body_timeout 10m;
    send_timeout 10m;
    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;
    include /etc/nginx/sites-enabled/*.conf;
}
## NGINX MAIN CONFIGURATION FILE ##

of course, feel free to change anything you think should be changed in order to suit your needs. for example, you may want to change the user/group nginx runs under or you may want to set the worker_processes option, which is determined by the number of CPU’s the machine has.

you can use the following command to find what number to use there:

grep -c 'model name' /proc/cpuinfo

also as you may noticed, there is include /etc/nginx/sites-enabled/*.conf inside the Nginx main configuration file. This means, include all available configuration files in/etc/nginx/sites-enabled/ which end with .conf. The idea here is to store Nginx server-blocks that are going to be set-up later on, playing the Debian-way by having the files created in sites-available and then linking the ones I want enabled to sites-enabled

mkdir /etc/nginx/{sites-available,sites-enabled}

DEFAULT NGINX SERVER BLOCK (VHOST)

set-up default Nginx server block in /etc/nginx/sites-available/default.conf

cat > /etc/nginx/sites-available/default.conf

server {
    listen       80 default_server;
    server_name  _;
    root   /srv/www/default;
    location / {
        index  index.html index.htm;
    }
    error_page  404              /404.html;
    location = /404.html {
        root   /srv/www/default;
    }
    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /srv/www/default;
    }
}

create the document root for the default Nginx server-block and set-up the default html files:

mkdir -p /srv/www/default

CONTENT='<!DOCTYPE html>
<html lang="en">
<head>
        <title>ViruSzZ</title>
</head>
<body style="background:#000;color:#fff;">
        <div style="color:#fff;width:100%;">
                <h1 align="center">you feel the silence?</h1>
        </div>
</body>
</html>'

echo ${CONTENT} > /srv/www/default/index.html

#------#

CONTENT='<!DOCTYPE html>
<html lang="en">
<head>
        <title>404</title>
</head>
<body style="background:#000;color:#fff;">
        <div style="color:#fff;width:100%;">
                <h1 align="center">404 straight in your face</h1>
        </div>
</body>
</html>'

echo ${CONTENT} > /srv/www/default/404.html

#------#

CONTENT='<!DOCTYPE html>
<html lang="en">
<head>
        <title>Whoooopsssss</title>
</head>
<body style="background:#000;color:#fff;">
        <div style="color:#fff;width:100%;">
                <h1 align="center">Whoooopssssssy... Something wrong happend back here!</h1>
        </div>
</body>
</html>'

echo ${CONTENT} > /srv/www/default/50x.html
unset CONTENT

LARAVEL NGINX SERVER BLOCK (VHOST)

set-up Nginx server block for Laravel (PHP) based web application, served using d.stavrovski.net

cat > /etc/nginx/sites-available/d.stavrovski.net.conf

server {
    listen 80;
    server_name d.stavrovski.net www.d.stavrovski.net daniel.stavrovski.net;
    return 301 http://d.stavrovski.net$request_uri;

    access_log /var/log/nginx/d.stavrovski.net.log;
    error_log /var/log/nginx/d.stavrovski.net-error.log error;

    root /srv/www/d.stavrovski.net/public;
    index index.html index.php;

    ### ROOT DIRECTORY ###
    location / {
        try_files $uri $uri/ /index.php?$args;
    }

    ### SECURITY ###
    error_page 403 =404;
    error_page 404 /404-not-found.html;

    location  /404-not-found.html {
        internal;
    }

    location ~* ^/uploads/.*.(html|htm|shtml|php)$ {
        types { }
        default_type text/plain;
    }

    location ~* ^/cache/.* {
        return 404;
    }

    #  location ~* 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; }

    location /uploads/ {
        valid_referers none blocked d.stavrovski.net *.stavrovski.net;
        if ($invalid_referer) {
            return   403;
        }
    }

    fastcgi_buffers 256 16k;
    fastcgi_buffer_size 32k;
    fastcgi_connect_timeout 300;
    fastcgi_send_timeout 300;
    fastcgi_read_timeout 300;

    ### PHP BLOCK ###
    location ~ .php?$ {
        fastcgi_keep_conn on;
        try_files $uri =404;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_intercept_errors on;
        fastcgi_split_path_info ^(.+.php)(.*)$;
        fastcgi_hide_header X-Powered-By;
        # fastcgi_pass 127.0.0.1:9000;
        fastcgi_pass unix:/var/run/d.stavrovski.net.socket;
        # fastcgi_pass unix:/var/run/hhvm/hhvm.sock;
    }
}

WORDPRESS NGINX SERVER BLOCK (VHOST)

set-up Nginx server block for WordPress based web application, served using wordpress.stavrovski.net

cat > /etc/nginx/sites-available/wordpress.stavrovski.net.conf

server {
    listen 80;
    server_name wordpress.stavrovski.net www.wordpress.stavrovski.net;

    client_max_body_size 5m;
    client_body_timeout 60;

    access_log /var/log/nginx/wordpress.stavrovski.net.log;
    error_log /var/log/nginx/wordpress.stavrovski.net-error error;

    root /srv/www/wordpress.stavrovski.net;
    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_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_intercept_errors on;
        fastcgi_split_path_info ^(.+.php)(.*)$;
        fastcgi_hide_header X-Powered-By;
        #fastcgi_pass 127.0.0.1:9001;
        fastcgi_pass unix:/var/run/wordpress.stavrovski.net.socket;
    }
}

with all that in place, let’s proceed with enabling the server-blocks and starting Nginx up:

cd /etc/nginx/sites-enabled/
for d in ../sites-available/*; do ln -s /etc/nginx/sites-available/${d##*/}; done

nginx -t
systemctl restart nginx
systemctl status nginx

INSTALL AND CONFIGURE PHP-FPM

Install PHP support on the CentOS 7 system using yum as in

yum install php-fpm php-mysql php-mcrypt

also, install any other PHP module that your application requires. the list is shown below or you can use yum search php- in the command line to get the list of available PHP modules on your CentOS 7 system:

  • php-bcmath – A module for PHP applications for using the bcmath library
  • php-cli – Command-line interface for PHP
  • php-common – Common files for PHP
  • php-dba – A database abstraction layer module for PHP applications
  • php-devel – Files needed for building PHP extensions
  • php-embedded – PHP library for embedding in applications
  • php-enchant – Enchant spelling extension for PHP applications
  • php-fpm – PHP FastCGI Process Manager
  • php-gd – A module for PHP applications for using the gd graphics library
  • php-imap – A module for PHP applications that use IMAP
  • php-intl – Internationalization extension for PHP applications
  • php-ldap – A module for PHP applications that use LDAP
  • php-mbstring – A module for PHP applications which need multi-byte string handling
  • php-mcrypt – Standard PHP module provides mcrypt library support
  • php-mysql – A module for PHP applications that use MySQL databases
  • php-mysqlnd – A module for PHP applications that use MySQL databases
  • php-odbc – A module for PHP applications that use ODBC databases
  • php-pdo – A database access abstraction module for PHP applications
  • php-pear.noarch – PHP Extension and Application Repository framework
  • php-pecl-memcache – Extension to work with the Memcached caching daemon
  • php-pgsql – A PostgreSQL database module for PHP
  • php-process – Modules for PHP script using system process interfaces
  • php-pspell – A module for PHP applications for using pspell interfaces
  • php-recode – A module for PHP applications for using the recode library
  • php-snmp – A module for PHP applications that query SNMP-managed devices
  • php-soap – A module for PHP applications that use the SOAP protocol
  • php-xml – A module for PHP applications which use XML
  • php-xmlrpc – A module for PHP applications which use the XML-RPC protocol

SET-UP PHP CONFIGURATION FILE

next, set-up PHP’s main configuration file /etc/php.ini

vim /etc/php.ini

:%s#;cgi.fix_pathinfo=1#cgi.fix_pathinfo=0#
:%s#;date.timezone =#date.timezone = Europe/Skopje#
:%s#memory_limit = 128M#memory_limit = 64M#
:%s#expose_php = On#expose_php = Off#

SET-UP PHP-FPM CONFIGURATION FILE

and edit PHP-FPM’s main configuration file /etc/php-fpm.conf

vim /etc/php-fpm.conf

:%s#;emergency_restart_threshold = 0#emergency_restart_threshold = 10#
:%s#;emergency_restart_interval = 0#emergency_restart_interval = 1m#
:%s#;process_control_timeout = 0#process_control_timeout = 10#

SET-UP PHP-FPM POOLS

OK, now I’m going to create PHP-FPM’s pools in /etc/php-fpm.d/ that I used in the server-blocks before. feel free to tune these to suit your needs.

cd /etc/php-fpm.d/
cp www.conf{,.orig}

FPM pool for d.stavrovski.net which serves a Laravel based web application:

cat > www.conf

[LARAVEL]
;listen = 127.0.0.1:9000
listen = /var/run/d.stavrovski.net.socket
;listen.mode = 0660
user = nginx
group = nginx
request_slowlog_timeout = 5s
slowlog = /var/log/php-fpm/slowlog.log
listen.allowed_clients = 127.0.0.1
pm = dynamic
pm.max_children = 15
pm.start_servers = 7
pm.min_spare_servers = 7
pm.max_spare_servers = 15
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/error.log
php_admin_flag[log_errors] = on

FPM pool for wordpress.stavrovski.net which serves a WordPress based web application:

cat > wordpress.conf

[WORDPRESS]
;listen = 127.0.0.1:9000
listen = /var/run/wordpress.stavrovski.net.socket
;listen.mode = 0660
user = nginx
group = nginx
request_slowlog_timeout = 5s
slowlog = /var/log/php-fpm/slowlog.log
listen.allowed_clients = 127.0.0.1
pm = dynamic
pm.max_children = 8
pm.start_servers = 5
pm.min_spare_servers = 5
pm.max_spare_servers = 8
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/error.log
php_admin_flag[log_errors] = on

ENABLE AND RESTART SERVICES

check Nginx’s configuration file and restart the server by running

nginx -t
systemctl restart nginx
systemctl status nginx

restart MariaDB (MySQL)

systemctl restart mariadb
systemctl status mariadb

restart PHP-FPM

systemctl restart php-fpm
systemctl status php-fpm

enable the services on system startup

systemctl enable nginx mariadb php-fpm

enjoy and take care