Install Nginx, PHP-FPM, MySQL and WordPress on CentOS 6 Linux

NginxNginx is an alternative web server that is fast becoming popular. Nginx is famed for its ability to handle thousands of concurrent connections while using very little memory. In this post I look at how to install Nginx, PHP-FPM, MySQL and WordPress on a brand new CentOS 6.x Linux installation.

Installing Servers

The default CentOS repositories do not have Nginx so we need to add the Atomic Corp. repository. Adding this repository is easy. As root type:

wget -qO - http://www.atomicorp.com/installers/atomic | sh

Accept the license that shows up on-screen and it will install the repo for you.

To begin installing Nginx, PHP-FPM and MySQL you need to type the following as root:

yum install nginx php-fpm php-gd php-mysqlnd php-mbstring php-xmlrpc mysql mysql-server

After the above has been installed it’s time to begin configuring stuff.

vultr

Configuring MySQL

Let’s begin with MySQL. Start up the MySQL service and set it to run at boot:

service mysqld start
chkconfig mysqld on

Then do a secure installation to set the root password:

mysql_secure_installation

Login into the mysql shell using the root password:

mysql -p -uroot

And add a database and user for WordPress:

CREATE DATABASE wp;
GRANT ALL privileges ON wp.* TO wpdbuser@localhost IDENTIFIED BY 'enter_password_here';

Adding a user

Next let’s add a user to our system. This user will own the WordPress installation. As root:

useradd wpuser

Also create directories for website files:

su wpuser
cd ~
mkdir www
mkdir www/example.com

All websites owned by this user will be stored in sub-directories under the /home/wpuser/www directory.

You also need to add nginx to the user’s group so that Nginx can access files in the user’s directory. As root:

gpasswd -a nginx wpuser
cd /home
chmod 750 wpuser

Configuring PHP-FPM

PHP-FPM processes can run in separate process pools. The processes of a single pool all run as a single user on your system. This allows you to isolate PHP processes of different users.

The first step is to disable the default www pool. As root:

cd /etc/php-fpm.d
mv www.conf www.disabled

Then create a new pool configuration file named wpuser.conf in the /etc/php-fpm.d directory and add the following in it:

[wpuser]
listen = /var/run/php-fpm/wpuser.sock
listen.owner = nginx
listen.group = nginx
listen.mode = 0660
user = wpuser
group = wpuser
pm = dynamic
pm.max_children = 10
pm.start_servers = 1
pm.min_spare_servers = 1
pm.max_spare_servers = 3
pm.max_requests = 500
chdir = /home/wpuser/www/
php_admin_value[open_basedir] = /home/wpuser/www:/tmp

A few things are going on here:

  • First up you have the pool name wpuser
  • Next there is the definition of the unix socket to listen on. PHP-FPM processes can listen on TCP ports or unix sockets. Unix sockets tend to be faster so we are defining a socket and giving it the same permissions as the nginx user so that Nginx can access it.
  • Then we are defining the user that the PHP-FPM processes will have. This is the same user we added to the system before. This restricts the PHP-FPM processes to only accessing files that the wpuser has permission to access.
  • The pm.* options define how many processes are started and how they are spawned. Fine tuning these is a topic for another article.
  • Finally we are specifying a directory to change to when starting up and also limiting access to the wpuser’s www directory.

The directory for the PHP-FPM socket will have to be created:

mkdir /var/run/php-fpm

Before you can start up PHP-FPM you also have to fine tune some settings in /etc/php.ini:

cgi.fix_pathinfo=0
upload_max_filesize = 64M

Now you can start up the php-fpm daemon and set it to run at boot up:

service php-fpm start
chkconfig php-fpm on

Nginx Configuration

As root edit the file /etc/nginx/conf.d/default.conf and make sure the following line contains default_server:

listen       80 default_server;

The above ensures that requests to your server’s IP address don’t end up serving any real website. We want people to use your domain name to access your site.

Next create a new file name example.com.conf in the /etc/nginx/conf.d directory:

server {
        listen       80;
        server_name  example.com www.example.com;
        root /home/wpuser/www/example.com ;
 
	client_max_body_size 64M;
 
	# Deny access to any files with a .php extension in the uploads directory
        location ~* /(?:uploads|files)/.*\.php$ {
                deny all;
        }
 
        location / {
                index index.php index.html index.htm;
                try_files $uri $uri/ /index.php?$args;
        }
 
        location ~* \.(gif|jpg|jpeg|png|css|js)$ {
                expires max;
        }
 
        location ~ \.php$ {
                try_files $uri =404;
                fastcgi_split_path_info ^(.+\.php)(/.+)$;
                fastcgi_index index.php;
                fastcgi_pass  unix:/var/run/php-fpm/wpuser.sock;
                fastcgi_param   SCRIPT_FILENAME
                                $document_root$fastcgi_script_name;
                include       fastcgi_params;
        }
}

Let’s see what’s going on here:

  • First we have Nginx listen on port 80 for requests for files from the domain name www.example.com and example.com. We are also defining the document root as /home/wpuser/www/example.com.
  • Then you have a setting that increases the default max request size to 64MB. This is required so that we can upload large image files in WordPress.
  • Next we have a location block that blocks access to php files in the uploads directory. This is a security setting.
  • In the two location blocks that follow you have the default index file specified and a block for static files.
  • In the last block you are passing .php file requests to PHP-FPM via the unix socket we configured earlier.

Let’s start Nginx now:

service nginx start
chkconfig nginx on

You’ll also want to poke a hole in the firewall to allow web traffic:

iptables -I INPUT -p tcp --dport=80 -j ACCEPT
/etc/init.d/iptables save

WordPress installation

Finally we get to the WordPress installation:

su wpuser
cd ~
wget wordpress.org/latest.zip
unzip -q latest.zip
mv wordpress/* www/example.com/
rm -rf wordpress latest.zip

Then just visit your site example.com in your browser and follow the on-screen prompts to install WordPress. You will need the MySQL database name, database username and password that you created earlier.

Two security tips to keep in mind when installing WordPress are:

  • Set a different database table prefix than the default wp_.
  • Set an administrator username that is not “admin”.
Enabling search engine friendly permalinks

To enable search engine friendly permalinks go to WordPress administration > Settings > Permalinks and choose Custom Structure. Then follow the guide here and add a permalink structure like this:

/%postname%/

Conclusion

WordPress plus Nginx and PHP-FPM can be a pretty powerful combination in a low memory footprint. It helps to do things right the first time and I’ve tried to show you how to do that in this guide.

7 thoughts on “Install Nginx, PHP-FPM, MySQL and WordPress on CentOS 6 Linux

  1. Hi, very great tutorial that I followed for using Sockets for my multiple websites.

    I managed to get everything up and running, but I would like to make a Request to you on how to install PhpMyAdmin?

    For example: 10.10.10.10/phpmyadmin

    I cannot find a solution achieving this using the Socket connection model.

    This is my phpmyadmin.conf

    server {
    listen 8080;
    server_name 10.10.10.10;
    access_log /var/log/nginx/phpmyadmin/access.log;
    error_log /var/log/nginx/phpmyadmin/error.log;
    root /usr/share/phpMyAdmin;

    location / {
    index index.php;
    }

    ## Images and static content is treated different
    location ~* ^.+.(jpg|jpeg|gif|css|png|js|ico|xml)$ {
    access_log off;
    expires 360d;
    }

    location ~ /\.ht {
    deny all;
    }

    location ~ /(libraries|setup/frames|setup/libs) {
    deny all;
    return 404;
    }

    location ~ ^/phpmyadmin/(.+\.php)$ {
    include /etc/nginx/fastcgi_params;
    fastcgi_index index.php;
    fastcgi_pass unix:/var/run/php-fpm/phpmyadmin.sock;
    fastcgi_param SCRIPT_FILENAME /usr/share/phpmyadmin$fastcgi_script_name;
    }
    }

    This is the new pool config file for phpmyadmin:

    [root]
    listen = /var/run/php-fpm/phpmyadmin.sock
    listen.owner = nginx
    listen.group = nginx
    listen.mode = 0660
    user = nginx
    group = nginx
    pm = dynamic
    pm.max_children = 20
    pm.start_servers = 1
    pm.min_spare_servers = 1
    pm.max_spare_servers = 5
    pm.max_requests = 2000
    chdir = /usr/share/phpMyAdmin/
    php_admin_value[open_basedir] = /usr/share/phpMyAdmin:/tmp

    Am I missing something?

    • What error are you getting? One thing you will want to correct is the port. It should be listen 80. Also there is a discrepancy between the document root and the setting for fastcgi_param SCRIPT_FILENAME. Better to do:

      fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;

      • Hey thanks. It works better now. I would like to ask you: How do you add a second website to the same server? I have to create another user + socket and duplicate the Nginx configuration settings + php-fpm settings ? I’ve done that, but DNS finished propagating and still can’t connect to my server. Can you do a little step-by-step please?

        • You’ve correctly described the process of adding another site.

          Actually you can even simplify it further by reusing the same PHP-FPM pool for multiple related sites. If all the sites belong to the same user there is no reason why they have to use different PHP-FPM pools.

          If DNS is an issue you can try editing your hosts file on your local machine to point your domain to your web server’s IP. I wrote a guide on how to do that:

          //abdussamad.com/archives/96-How-to-access-your-website-at-your-new-web-host-before-DNS-propagates.html

          • Hi, i’ve opted for the option of creating a 2nd user and different PHP-FPM pools. Now the thing for the new added website is that Nginx is throwing me a 502 bad gateway error.
            Php is running (checked) must be an issue with the fastcgi or Socket? I don’t know. I’ve created a new socket named “marketman.sock” as you can see:

            location ~ \.php$ {
            try_files $uri =404;
            expires off;
            fastcgi_read_timeout 900s;
            fastcgi_index index.php;
            fastcgi_pass unix:/var/run/php-fpm/marketman.sock;
            fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
            include /etc/nginx/fastcgi_params;
            }

            Any ideas for me ?

          • The Nginx config you’ve posted above looks good. Post your PHP-FPM config for the marketman pool.

            Another thing is that you can check whether PHP-FPM processes are running as username marketman using the ps Linux command.

  2. this is a great guide for anyone interested in nginx. some experience in linux required. saw a huge performance boost from our apache/php-mysql system.

    thanks abduss!

Leave a Reply

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