NIXVERSE

How to Install WordPress with LEMP Stack on CentOS 7

Jan 6, 2020
  1. Prerequisites
  2. Configuring Firewall with Firewalld
  3. Installing Nginx
  4. Setting up SSL Certificate
  5. Installing and Configuring MariaDB
  6. Installing and Configuring PHP
  7. Downloading and Setting up Wordpress
  8. Configure Nginx

1. Prerequisites

Before starting to install, you should have:
- user account with root privileges,
- domain that pointing to your server.

Start installation with updating the system:

$ sudo yum -y update

2. Configuring Firewall with Firewalld

Install firewalld:

$ sudo yum -y install firewalld

Start firewalld:

$ sudo systemctl start firewalld

Check if firewalld is running:

$ sudo firewall-cmd --state

Enable firewalld to start automatically after reboot:

$ sudo systemctl enable firewalld

Open http/80 and https/443 ports:

$ sudo firewall-cmd --permanent --zone=public --add-service=http
$ sudo firewall-cmd --permanent --zone=public --add-service=https

Reload changes:

$ sudo firewall-cmd --reload

List all firewall rules:

$ sudo firewall-cmd --list-all

3. Installing Nginx

Nginx is a high performance web server. EPEL package needs to be installed for the nginx.

Install EPEL repository:

$ sudo yum -y install epel-release

Install nginx:

$ sudo yum -y install nginx

Start nginx:

$ sudo systemctl start nginx

Enable nginx to start automatically after reboot:

$ sudo systemctl enable nginx

Check if nginx is active and running:

$ sudo systemctl status nginx

Delete the server{...} block from the /etc/nginx/nginx.conf file or use this command:

$ echo "# For more information on configuration, see:
#   * Official English Documentation: http://nginx.org/en/docs/
#   * Official Russian Documentation: http://nginx.org/ru/docs/

user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;

# Load dynamic modules. See /usr/share/doc/nginx/README.dynamic.
include /usr/share/nginx/modules/*.conf;

events {
    worker_connections 1024;
}

http {
    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;
    tcp_nodelay         on;
    keepalive_timeout   65;
    types_hash_max_size 2048;

    include             /etc/nginx/mime.types;
    default_type        application/octet-stream;

    # 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;
}" | sudo tee /etc/nginx/nginx.conf

4. Setting up SSL Certificate

Install certbot:

$ sudo yum -y install certbot python2-certbot-nginx

Get a certificate:

$ domain="example.com"
$ email="your@email.com"
$ sudo certbot certonly --nginx \
-n --agree-tos -m $email -d $domain -d www.$domain

Set up automatic renewal:

$ echo "0 0,12 * * * root python -c 'import random; import time; \
time.sleep(random.random() * 3600)' && certbot renew" | \
sudo tee -a /etc/crontab > /dev/null

5. Installing and Configuring MariaDB

MariaDB is an enhanced fork of the MySQL relational database management system.

Finding the latest MariaDB version:

$ sudo yum -y install curl
$ mariadb_version="$(curl -s yum.mariadb.org | grep Directory | \
awk -v RS='<[^>]+>' -v ORS= '1' | grep '^[0-9]' | \
awk -F '/' '{print $1}' | sort -n | tail -n1)"

If echo $mariadb_version fails to return "10.4.11" or a new version, type:

$ mariadb_version="10.4.11"

Create a yum repository file:

$ echo "[mariadb]
name = MariaDB
baseurl = http://yum.mariadb.org/$mariadb_version/centos7-amd64/
gpgkey=https://yum.mariadb.org/RPM-GPG-KEY-MariaDB
gpgcheck=1" | sudo tee -a /etc/yum.repos.d/MariaDB.repo

Install MariaDB server:

$ sudo yum -y install MariaDB-server

Start MariaDB:

$ sudo systemctl start mariadb

Enable MariaDB to start automatically after reboot:

$ sudo systemctl enable mariadb

Mysql secure installation:

$ sudo mysql_secure_installation
Enter current password for root (enter for none):
Switch to unix_socket authentication [Y/n] n
Change the 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
All done!  If you've completed all of the above steps, your MariaDB
installation should now be secure.

Login mysql database as root:

$ mysql -u root -p

Create a new database for Wordpress:

MariaDB > CREATE DATABASE wordpress DEFAULT CHARACTER SET utf8
COLLATE utf8_unicode_ci;

Create user for Wordpress database (change username and password as you like):

MariaDB > CREATE USER 'myuser'@'localhost' IDENTIFIED BY 'mypassword';

Give all access to the new user for wordpress database:

MariaDB > GRANT ALL ON wordpress.* TO 'myuser'@'localhost';

Reload changes:

MariaDB > FLUSH PRIVILEGES;

Exit from mariadb:

MariaDB > exit

6. Installing and Configuring PHP

Finding the latest php version from remi repository:

$ php_version="$(curl -s http://rpms.remirepo.net/enterprise/7/ | \
grep remi-php | awk -v RS='<[^>]+>' -v ORS= '1' | \
awk '$1 ~ /^ *remi/' | sort -n | tail -n1 | awk '{print $1}')"

If echo $php_version fails to return "remi-php74" or a new version, type:

$ php_version="remi-php74"

The Remi repository depends on the EPEL repository.

Enable EPEL and Remi repositories:

$ sudo yum -y install epel-release yum-utils
$ sudo yum -y install http://rpms.remirepo.net/enterprise/remi-release-7.rpm
$ sudo yum-config-manager --enable $php_version

Install php-fpm (FastCGI Process Manager) and common php modules:

$ sudo yum -y install php-fpm php-mysql php-mbstring php-xml php-gd \
php-cli php-json php-opcache php-curl

Verify php installation:

$ php -v

Start php-fpm:

$ sudo systemctl start php-fpm

Enable php-fpm to start automatically after reboot:

$ sudo systemctl enable php-fpm

Check if php-fpm is active and running:

$ sudo systemctl status php-fpm

Change php directory ownership:

$ sudo chown -R root:nginx /var/lib/php

Change user = apache line to user = nginx from /etc/php-fpm.d/www.conf file:

$ sudo sed -i "s/user = apache/user = nginx/g" /etc/php-fpm.d/www.conf

Change group = apache line to group = nginx from /etc/php-fpm.d/www.conf file:

$ sudo sed -i "s/group = apache/group = nginx/g" /etc/php-fpm.d/www.conf

Change listen = 127.0.0.1:9000 line to listen = /run/php-fpm/www.sock from /etc/php-fpm.d/www.conf file:

$ sudo sed -i "s|listen = 127.0.0.1:9000|listen = /run/php-fpm/www.sock|g" \
/etc/php-fpm.d/www.conf

Update /etc/php-fpm.d/www.conf file:

$ echo "listen.owner = nginx
listen.group = nginx
listen.mode = 0660" | sudo tee -a /etc/php-fpm.d/www.conf

Restart php-fpm:

$ sudo systemctl restart php-fpm

7. Downloading and Setting up Wordpress

Install wget to download Wordpress:

$ sudo yum -y install wget

Download Wordpress:

$ wget https://wordpress.org/latest.tar.gz

Extract Wordpress files:

$ tar xzvf latest.tar.gz
$ cp wordpress/wp-config-sample.php wordpress/wp-config.php

Create directories for website:

$ domain="example.com"
$ sudo mkdir /var/www
$ sudo mkdir /var/www/$domain

Copy extracted files where to serve website:

$ sudo cp -a wordpress/. /var/www/$domain

Delete downloaded Wordpress files:

$ rm -rf wordpress/

Give website directory ownership to nginx:

$ sudo chown -R nginx:nginx /var/www/$domain

Create and configure Wordpress authentication keys:

$ sudo sed -i '/put your unique phrase/d' /var/www/$domain/wp-config.php
$ curl -s https://api.wordpress.org/secret-key/1.1/salt/ | \
sudo tee -a /var/www/$domain/wp-config.php

Updating Wordpress without using FTP:

$ echo "define('FS_METHOD', 'direct');" | \
sudo tee -a /var/www/$domain/wp-config.php

Update mysql database name from Wordpress config file:

$ mysql_database_name="wordpress"
$ sudo sed -i "s/database_name_here/$mysql_database_name/g" \
/var/www/$domain/wp-config.php

Update mysql username from Wordpress config file:

$ mysql_username="myuser"
$ sudo sed -i "s/username_here/$mysql_username/g" \
/var/www/$domain/wp-config.php

Update mysql user password from Wordpress config file:

$ mysql_password="mypassword"
$ sudo sed -i "s/password_here/$mysql_password/g" \
/var/www/$domain/wp-config.php

8. Configure Nginx

Configure web server:

$ domain="example.com"
$ echo "# Redirect HTTP -> HTTPS
server {
    listen 80;
    server_name www.$domain $domain;

    include snippets/letsencrypt.conf;
    return 301 https://$domain\$request_uri;
}

# Redirect WWW -> NON WWW
server {
    listen 443 ssl http2;
    server_name www.$domain;

    ssl_certificate /etc/letsencrypt/live/$domain/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/$domain/privkey.pem;
    ssl_trusted_certificate /etc/letsencrypt/live/$domain/chain.pem;
    include snippets/ssl.conf;

    return 301 https://$domain\$request_uri;
}

server {
    listen 443 ssl http2;
    server_name $domain;

    root /var/www/$domain;
    index index.php;

    # SSL parameters
    ssl_certificate /etc/letsencrypt/live/$domain/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/$domain/privkey.pem;
    ssl_trusted_certificate /etc/letsencrypt/live/$domain/chain.pem;
    include snippets/ssl.conf;
    include snippets/letsencrypt.conf;

    # log files
    access_log /var/log/nginx/$domain.access.log;
    error_log /var/log/nginx/$domain.error.log;

    location = /favicon.ico {
        log_not_found off;
        access_log off;
    }

    location = /robots.txt {
        allow all;
        log_not_found off;
        access_log off;
    }

    location / {
        try_files \$uri \$uri/ /index.php?\$args;
    }

    location ~ \.php$ {
        try_files \$uri =404;
        fastcgi_pass unix:/run/php-fpm/www.sock;
        fastcgi_index   index.php;
        fastcgi_param SCRIPT_FILENAME \$document_root\$fastcgi_script_name;
        include fastcgi_params;
    }

    location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
        expires max;
        log_not_found off;
    }

}" | sudo tee /etc/nginx/conf.d/$domain.conf

Generate strong DH (Diffie-Hellman) group for exchanging cryptographic keys over an unsecured communication channel:

$ sudo openssl dhparam -out /etc/ssl/certs/dhparam.pem 2048

Create ssl snippet files:

$ sudo mkdir /etc/nginx/snippets
$ sudo chmod 644 /etc/nginx/snippets

$ echo "location ^~ /.well-known/acme-challenge/ {
  allow all;
  root /var/lib/letsencrypt/;
  default_type "text/plain";
  try_files \$uri =404;
}
" | sudo tee /etc/nginx/snippets/letsencrypt.conf

$ echo "ssl_dhparam /etc/ssl/certs/dhparam.pem;

ssl_session_timeout 1d;
ssl_session_cache shared:SSL:50m;
ssl_session_tickets off;

ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers 'ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS';
ssl_prefer_server_ciphers on;

ssl_stapling on;
ssl_stapling_verify on;
resolver 8.8.8.8 8.8.4.4 valid=300s;
resolver_timeout 30s;

add_header Strict-Transport-Security \"max-age=15768000; includeSubdomains; preload\";
add_header X-Frame-Options SAMEORIGIN;
add_header X-Content-Type-Options nosniff;" | \
sudo tee /etc/nginx/snippets/ssl.conf

Fix nginx pid file error:

$ printf "[Service]\nExecStartPost=/bin/sleep 0.1\n" | \
sudo tee /etc/systemd/system/nginx.service.d/override.conf
$ sudo systemctl daemon-reload

Update server path:

$ sudo sed -i "s|root         /usr/share/nginx/html|root         /var/www/$domain|g" \
/etc/nginx/nginx.conf

SELinux nginx permission:

$ sudo chcon -Rt httpd_sys_content_t /var/www

Restart php-fpm:

$ sudo systemctl restart php-fpm

Restart nginx:

$ sudo systemctl restart nginx

Now when you enter your domain, you should be able to see Wordpress Installation page.