Skip to main content

WordPress 5.x Hardening Guide for CentOS 7.6

·3654 words·18 mins
Eyal Estrin
Author
Eyal Estrin
Author of Cloud Security Handbook & Security for Cloud Native Applications. Cloud Adoption & Cybersecurity expert.

This document explains the process of installation, configuration and hardening of Apache server from source files, based on CentOS 7.6 default installation (Linux Firewall and SELinux enabled by default), including support for TLS v1.2 and PHP 7.3

Pre-Requirements

    • Linux server installed with CentOS 7.6 (64bit)
    • policycoreutils-python-* package installed
    • setools-libs-* package installed
    • libcgroup-* package installed
    • audit-libs-python-* package installed
    • libsemanage-python-* package installed
    • gcc* package installed
    • gcc-c++* package installed
    • autoconf* package installed
    • automake* package installed
    • libtool* package installed
    • perl-core package installed
    • zlib-devel package installed
    • expat-devel package installed
    • yum-utils package installed

OpenSSL upgrade phase

  1. Login using privileged account
  2. Run the commands below to download the latest build of OpenSSL: cd /usr/local/src wget https://www.openssl.org/source/openssl-1.1.1.tar.gz tar -xvzf openssl-1.1.1.tar.gz
  3. Run the commands below to compile the latest build of OpenSSL: cd openssl-1.1.1 ./config --prefix=/usr/local/ssl --openssldir=/usr/local/ssl shared zlib make make test make install
  4. Edit using VI the file /etc/ld.so.conf.d/openssl-1.1.1.conf and add the following string to the file: /usr/local/ssl/lib
  5. Run the command below to reload the dynamic link: ldconfig -v
  6. Backup the original OpenSSL binary: mv /usr/bin/openssl /usr/bin/openssl.BEKUP
  7. Create using VI the file /etc/profile.d/openssl.sh and add the following content: #Set OPENSSL_PATH OPENSSL_PATH=/usr/local/ssl/bin export OPENSSL_PATH PATH=$PATH:$OPENSSL_PATH export PATH
  8. Run the commands below to complete the configuration of the OpenSSL: chmod +x /etc/profile.d/openssl.sh source /etc/profile.d/openssl.sh echo $PATH which openssl

Apache 2.4.6 installation phase

  1. Login using privileged account

  2. Run the command below to install Apache 2.4.6: yum install httpd -y

  3. Updating Ownership and Permissions on Apache folders: chown root:root /usr/sbin/apachectl chown root:root /usr/sbin/httpd chmod 770 /usr/sbin/apachectl chmod 770 /usr/sbin/httpd chown -R root:root /etc/httpd chmod -R go-r /etc/httpd chown -R root:root /etc/httpd/logs chmod -R 700 /etc/httpd/logs

  4. Create folder for the web content: mkdir -p /www

  5. Updating Ownership and Permissions on the web content folder: chown -R root /www chmod -R 775 /www

  6. Fix the SELinux security context on the new web folder: semanage fcontext -a -t httpd_sys_content_t "/www(/.*)?" restorecon -F -R -v /www chcon -R -t httpd_sys_content_t /www

  7. Create folder for the first WordPress site: mkdir /www/WebSiteA Note: Replace WebSiteA with the relevant name

  8. Create folder for the secondWordPress site: mkdir /www/WebSiteB Note: Replace WebSiteB with the relevant name

  9. Create logs folder for the first WordPress site: mkdir /www/WebSiteA/logs Note: Replace WebSiteA with the relevant name

  10. Create logs folder for the second WordPress site: mkdir /www/WebSiteB/logs Note: Replace WebSiteB with the relevant name

  11. Configure permissions on the logs folder for the first WordPress site: chown -R apache:apache /www/WebSiteA/logs chmod -R 700 /www/WebSiteA/logs Note: Replace WebSiteA with the relevant name

  12. Configure permissions on the logs folder for the second WordPress site: chown -R apache:apache /www/WebSiteB/logs chmod -R 700 /www/WebSiteB/logs Note: Replace WebSiteB with the relevant name

  13. Fix the SELinux security context on the new web folder for the first WordPress site: semanage fcontext -a -t httpd_log_t "/www/WebSiteA/logs(/.*)?" restorecon -F -R -v /www/WebSiteA/logs chcon -R -t httpd_log_t /www/WebSiteA/logs Note: Replace WebSiteA with the relevant name

  14. Fix the SELinux security context on the new web folder for the second WordPress site: semanage fcontext -a -t httpd_log_t "/www/WebSiteB/logs(/.*)?" restorecon -F -R -v /www/WebSiteB/logs chcon -R -t httpd_log_t /www/WebSiteB/logs Note: Replace WebSiteB with the relevant name

  15. Create the following folders: mkdir /etc/httpd/sites-available mkdir /etc/httpd/sites-enabled

  16. Edit using VI the file /etc/httpd/conf/httpd.conf and change the following strings: From: LogLevel warnTo: LogLevel notice

    From: DocumentRoot "/var/www/html"

    To: # DocumentRoot "/var/www/html"

    From: ScriptAlias /cgi-bin/ "/var/www/cgi-bin/"

    To: # ScriptAlias /cgi-bin/ "/var/www/cgi-bin/"

  17. Comment out the entire sections below inside the /etc/httpd/conf/httpd.conf <Directory /> <Directory "/var/www"> <Directory "/var/www/html"> <Directory "/var/www/cgi-bin">

  18. Add the following sections to the end of the /etc/httpd/conf/httpd.conf file: IncludeOptional sites-enabled/*.conf # Configure custom error message: ErrorDocument 400 "The requested URL was not found on this server." ErrorDocument 401 "The requested URL was not found on this server." ErrorDocument 403 "The requested URL was not found on this server." ErrorDocument 404 "The requested URL was not found on this server." ErrorDocument 405 "The requested URL was not found on this server." ErrorDocument 408 "The requested URL was not found on this server." ErrorDocument 410 "The requested URL was not found on this server." ErrorDocument 411 "The requested URL was not found on this server." ErrorDocument 412 "The requested URL was not found on this server." ErrorDocument 413 "The requested URL was not found on this server." ErrorDocument 414 "The requested URL was not found on this server." ErrorDocument 415 "The requested URL was not found on this server." ErrorDocument 500 "The requested URL was not found on this server." # Configure Server Tokens ServerTokens Prod # Disable Server Signature ServerSignature Off # Disable Tracing TraceEnable Off # Maximum size of the request body. LimitRequestBody 4000000 # Maximum number of request headers in a request. LimitRequestFields 40 # Maximum size of request header lines. LimitRequestFieldSize 4000 # Maximum size of the request line. LimitRequestLine 4000 MaxRequestsPerChild 10000 # Configure clickjacking protection Header always append X-Frame-Options SAMEORIGIN

  19. Remove the files below: mv /etc/httpd/conf.d/autoindex.conf /etc/httpd/conf.d/autoindex.conf.bak mv /etc/httpd/conf.d/userdir.conf /etc/httpd/conf.d/userdir.conf.bak

  20. Comment out the lines inside the /etc/httpd/conf.modules.d/00-base.conf file below to disable default modules: LoadModule status_module modules/mod_status.so LoadModule info_module modules/mod_info.so LoadModule autoindex_module modules/mod_autoindex.so LoadModule include_module modules/mod_include.so LoadModule userdir_module modules/mod_userdir.so LoadModule env_module modules/mod_env.so LoadModule negotiation_module modules/mod_negotiation.so LoadModule actions_module modules/mod_actions.so

  21. Comment out the lines inside the /etc/httpd/conf.modules.d/01-cgi.conf file below to disable default modules: LoadModule cgi_module modules/mod_cgi.so

  22. Using VI, create configuration file for the first WordPress site called /etc/httpd/sites-available/websitea.com.conf with the following content: <VirtualHost *:80> ServerAdmin admin@websitea.com ServerName www.websitea.com ServerAlias websitea.com DocumentRoot /www/WebSiteA <Directory /> Options FollowSymLinks AllowOverride None </Directory> <Directory /www/WebSiteA> Options Indexes FollowSymLinks MultiViews AllowOverride all Require all granted Order allow,deny Allow from all <LimitExcept GET POST> deny from all </limitexcept> </Directory> ErrorLog /www/WebSiteA/logs/error.log CustomLog /www/WebSiteA/logs/access.log combined </VirtualHost> Note: Replace WebSiteA with the relevant name

  23. Using VI, create configuration file for the first WordPress site called /etc/httpd/sites-available/websiteb.com.conf with the following content: <VirtualHost *:80> ServerAdmin admin@websiteb.com ServerName www.websiteb.com ServerAlias websiteb.com DocumentRoot /www/WebSiteB <Directory /> Options FollowSymLinks AllowOverride None </Directory> <Directory /www/WebSiteB> Options Indexes FollowSymLinks MultiViews AllowOverride all Require all granted Order allow,deny Allow from all <LimitExcept GET POST> deny from all </limitexcept> </Directory> ErrorLog /www/WebSiteB/logs/error.log CustomLog /www/WebSiteB/logs/access.log combined </VirtualHost> Note: Replace WebSiteB with the relevant name

  24. Run the commands below to enable the new virtual host files: ln -s /etc/httpd/sites-available/websitea.com.conf /etc/httpd/sites-enabled/websitea.com.conf ln -s /etc/httpd/sites-available/websiteb.com.conf /etc/httpd/sites-enabled/websiteb.com.conf Note 1: Replace WebSiteA with the relevant name Note 2: Replace WebSiteB with the relevant name

  25. Run the command below to configure Apache to load at startup: systemctl enable httpd

  26. To start the Apace service, run the command below: systemctl start httpd

  27. Run the commands below to enable HTTPD rule on the firewall: firewall-cmd --zone=public --add-service=http --permanent systemctl restart firewalld

MariaDB installation phase

  1. Login using privileged account
  2. Install MariaDB: yum install -y mariadb-server mariadb-client
  3. Enable the MariaDB service: systemctl enable mariadb.service
  4. Start the MariaDB service: systemctl start mariadb.service
  5. Run the command bellow to set ownership and permissions for /etc/my.cnf file: chown root /etc/my.cnf chmod 644 /etc/my.cnf
  6. Edit using VI, the file /etc/my.cnf and add the string bellow under the \[mysqld\] section bind-address = 127.0.0.1
  7. Run the command below to secure the MySQL: mysql_secure_installation
  8. Specify the MySQL root account password (leave blank) -> Press Y to set the Root password -> specify new complex password (at least 14 characters, upper case, lower case, number, special characters) and document it -> Press Y to remove anonymous users -> Press Y to disallow root login remotely -> Press Y to remove test database -> Press Y to reload privilege tables and exit the script.
  9. Restart the MariaDB service: systemctl restart mariadb.service

PHP 7.3 installation phase

  1. Login using privileged account

  2. Run the commands below to install PHP 7.3: yum install http://rpms.remirepo.net/enterprise/remi-release-7.rpm -y yum-config-manager --enable remi-php73 yum install php php-mcrypt php-cli php-gd php-curl php-mysql php-ldap php-zip php-fileinfo -y

  3. Change the permissions on the php.ini file: chmod 640 /etc/php.ini

  4. Edit using VI, the file /etc/php.ini From: mysqli.default_host = To: mysqli.default_host = 127.0.0.1:3306From: allow_url_fopen = On

    To: allow_url_fopen = Off

From: expose_php = On

To: expose_php = Off

From: memory_limit = 128M

To: memory_limit = 8M

From: post_max_size = 8M

To: post_max_size = 2M

From: upload_max_filesize = 2M

To: upload_max_filesize = 1M

From: disable_functions =

To: disable_functions = fpassthru,crack_check,crack_closedict,crack_getlastmessage,crack_opendict, psockopen,php_ini_scanned_files,shell_exec,chown,hell-exec,dl,ctrl_dir,phpini,tmp,safe_mode,systemroot,server_software, get_current_user,HTTP_HOST,ini_restore,popen,pclose,exec,suExec,passthru,proc_open,proc_nice,proc_terminate, proc_get_status,proc_close,pfsockopen,leak,apache_child_terminate,posix_kill,posix_mkfifo,posix_setpgid, posix_setsid,posix_setuid,escapeshellcmd,escapeshellarg,posix_ctermid,posix_getcwd,posix_getegid,posix_geteuid,posix_getgid,posix_getgrgid, posix_getgrnam,posix_getgroups,posix_getlogin,posix_getpgid,posix_getpgrp,posix_getpid, posix_getppid,posix_getpwnam,posix_getpwuid,posix_getrlimit,system,posix_getsid,posix_getuid,posix_isatty, posix_setegid,posix_seteuid,posix_setgid,posix_times,posix_ttyname,posix_uname,posix_access,posix_get_last_error,posix_mknod, posix_strerror,posix_initgroups,posix_setsidposix_setuid

  • Restart the Apache service: systemctl restart httpd.service

**

WordPress 5.x installation phase

**3. Login using privileged account. 4. Run the command bellow to login to the MariaDB: /usr/bin/mysql -uroot -p Note: When prompted, specify the password for the MariaDB root account. 5. Run the following commands from the MariaDB prompt: CREATE USER 'blgusr'@'localhost' IDENTIFIED BY 'A3fg1j7x!s2gEq'; CREATE USER 'hswjm'@'localhost' IDENTIFIED BY 'hj5fa1fnu@zw0p'; CREATE DATABASE m6gf42s; CREATE DATABASE b7mf3aq; GRANT ALL PRIVILEGES ON m6gf42s.* TO "blgusr"@"localhost" IDENTIFIED BY "A3fg1j7x!s2gEq"; GRANT ALL PRIVILEGES ON b7mf3aq.* TO "hswjm"@"localhost" IDENTIFIED BY "hj5fa1fnu@zw0p"; FLUSH PRIVILEGES; quit Note 1: Replace “blgusr” with a username to access first the database. Note 2: Replace “A3fg1j7x!s2gEq” with complex password for the account who will access the first database (at least 14 characters, upper case, lower case, number, special characters). Note 3: Replace “hswjm” with a username to access second the database. Note 4: Replace “hj5fa1fnu@zw0p” with complex password for the account who will access the second database (at least 14 characters, upper case, lower case, number, special characters). Note 5: Replace “m6gf42s” with the first WordPress database name. Note 6: Replace “b7mf3aq” with the second WordPress database name. 6. Run the commands below to download the latest build of WordPress: cd /usr/local/src wget https://wordpress.org/latest.zip unzip latest.zip -d /www/WebSiteA unzip latest.zip -d /www/WebSiteB Note 1: Replace WebSiteA with the relevant name Note 2: Replace WebSiteB with the relevant name 7. Fix the SELinux security context on the new web folder for the first WordPress site: semanage fcontext -a -t httpd_sys_content_t "/www/WebSiteA(/.*)?" restorecon -F -R -v /www/WebSiteA chcon -R -t httpd_sys_content_t /www/WebSiteA semanage fcontext -a -t httpd_sys_rw_content_t "/www/WebSiteA/wp-content(/.*)?" restorecon -F -R -v /www/WebSiteA/wp-content chcon -R -t httpd_sys_rw_content_t /www/WebSiteA/wp-content Note: Replace WebSiteA with the relevant name 8. Fix the SELinux security context on the new web folder for the second WordPress site: semanage fcontext -a -t httpd_sys_content_t "/www/WebSiteB(/.*)?" restorecon -F -R -v /www/WebSiteB chcon -R -t httpd_sys_content_t /www/WebSiteB semanage fcontext -a -t httpd_sys_rw_content_t "/www/WebSiteB/wp-content(/.*)?" restorecon -F -R -v /www/WebSiteB/wp-content chcon -R -t httpd_sys_rw_content_t /www/WebSiteB/wp-content Note: Replace WebSiteB with the relevant name 9. Create using VI the file /www/WebSiteA/config.php with the following content: <?php define('DB_NAME', 'm6gf42s'); define('DB_USER', 'blgusr'); define('DB_PASSWORD', 'A3fg1j7x!s2gEq'); define('DB_HOST', 'localhost'); $table_prefix = 'm6gf42s_'; define('AUTH_KEY', 'put your unique phrase here'); define('SECURE_AUTH_KEY', 'put your unique phrase here'); define('LOGGED_IN_KEY', 'put your unique phrase here'); define('NONCE_KEY', 'put your unique phrase here'); define('AUTH_SALT', 'put your unique phrase here'); define('SECURE_AUTH_SALT', 'put your unique phrase here'); define('LOGGED_IN_SALT', 'put your unique phrase here'); define('NONCE_SALT', 'put your unique phrase here'); define('FS_METHOD', 'direct'); ?> Note 1: Make sure there are no spaces, newlines, or other strings before an opening ‘< ?php’ tag or after a closing ‘?>’ tag. Note 2: Replace “blgusr” with MariaDB account to access the first database. Note 3: Replace “A3fg1j7x!s2gEq” with complex password (at least 14 characters). Note 4: Replace “m6gf42s” with the first WordPress database name. Note 5: In-order to generate random values for the AUTH_KEY, SECURE_AUTH_KEY, LOGGED_IN_KEY and NONCE_KEY, use the web site bellow: http://api.wordpress.org/secret-key/1.1/ 10. Create using VI the file /www/WebSiteB/config.php with the following content: <?php define('DB_NAME', 'b7mf3aq'); define('DB_USER', 'hswjm'); define('DB_PASSWORD', 'hj5fa1fnu@zw0p'); define('DB_HOST', 'localhost'); $table_prefix = 'b7mf3aq_'; define('AUTH_KEY', 'put your unique phrase here'); define('SECURE_AUTH_KEY', 'put your unique phrase here'); define('LOGGED_IN_KEY', 'put your unique phrase here'); define('NONCE_KEY', 'put your unique phrase here'); define('AUTH_SALT', 'put your unique phrase here'); define('SECURE_AUTH_SALT', 'put your unique phrase here'); define('LOGGED_IN_SALT', 'put your unique phrase here'); define('NONCE_SALT', 'put your unique phrase here'); define('FS_METHOD', 'direct'); ?> Note 1: Make sure there are no spaces, newlines, or other strings before an opening ‘< ?php’ tag or after a closing ‘?>’ tag. Note 2: Replace “hswjm” with MariaDB account to access the second database. Note 3: Replace “hj5fa1fnu@zw0p” with complex password (at least 14 characters). Note 4: Replace “b7mf3aq” with the second WordPress database name. Note 5: In-order to generate random values for the AUTH_KEY, SECURE_AUTH_KEY, LOGGED_IN_KEY and NONCE_KEY, use the web site bellow: http://api.wordpress.org/secret-key/1.1/ 11. Copy the wp-config.php file: cp /www/WebSiteA/wordpress/wp-config-sample.php /www/WebSiteA/wordpress/wp-config.php cp /www/WebSiteB/wordpress/wp-config-sample.php /www/WebSiteB/wordpress/wp-config.php Note 1: Replace WebSiteA with the relevant name Note 2: Replace WebSiteB with the relevant name 12. Edit using VI, the file /www/WebSiteA/wordpress/wp-config.php Add the following lines before the string “That’s all, stop editing! Happy blogging”: /* Multisite */ define('WP_ALLOW_MULTISITE', true); include('/www/WebSiteA/config.php'); Remove or comment the following sections: define('DB_NAME', 'putyourdbnamehere'); define('DB_USER', 'usernamehere'); define('DB_PASSWORD', 'yourpasswordhere'); define('DB_HOST', 'localhost'); $table_prefix = 'wp_'; define('AUTH_KEY', 'put your unique phrase here'); define('SECURE_AUTH_KEY', 'put your unique phrase here'); define('LOGGED_IN_KEY', 'put your unique phrase here'); define('NONCE_KEY', 'put your unique phrase here'); define('AUTH_SALT', 'put your unique phrase here'); define('SECURE_AUTH_SALT', 'put your unique phrase here'); define('LOGGED_IN_SALT', 'put your unique phrase here'); define('NONCE_SALT', 'put your unique phrase here'); Note: Replace WebSiteA with the relevant name 13. Edit using VI, the file /www/WebSiteB/wordpress/wp-config.php Add the following lines before the string “That’s all, stop editing! Happy blogging”: /* Multisite */ define('WP_ALLOW_MULTISITE', true); include('/www/WebSiteB/config.php'); Remove or comment the following sections: define('DB_NAME', 'putyourdbnamehere'); define('DB_USER', 'usernamehere'); define('DB_PASSWORD', 'yourpasswordhere'); define('DB_HOST', 'localhost'); $table_prefix = 'wp_'; define('AUTH_KEY', 'put your unique phrase here'); define('SECURE_AUTH_KEY', 'put your unique phrase here'); define('LOGGED_IN_KEY', 'put your unique phrase here'); define('NONCE_KEY', 'put your unique phrase here'); define('AUTH_SALT', 'put your unique phrase here'); define('SECURE_AUTH_SALT', 'put your unique phrase here'); define('LOGGED_IN_SALT', 'put your unique phrase here'); define('NONCE_SALT', 'put your unique phrase here'); Note: Replace WebSiteB with the relevant name 14. Create using VI the file /www/WebSiteA/wordpress/.htaccess and add the following content: # BEGIN WordPress <IfModule mod_rewrite.c> RewriteEngine On RewriteBase / RewriteRule ^index\.php$ - [L] RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule . /index.php [L] </IfModule> # END WordPress Header set X-XSS-Protection "1; mode=block" Header set X-Content-Type-Options nosniff Header set Content-Security-Policy "default-src 'self' 'unsafe-inline' 'unsafe-eval' https: data:" Note: Replace WebSiteA with the relevant name 15. Create using VI the file /www/WebSiteA/wordpress/wp-content/.htaccess and add the following content: # BEGIN WordPress <IfModule mod_rewrite.c> RewriteEngine On RewriteBase / RewriteRule ^index\.php$ - [L] RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule . /index.php [L] </IfModule> # END WordPress Note: Replace WebSiteA with the relevant name 16. Create using VI the file /www/WebSiteA/wordpress/wp-includes/.htaccess and add the following content: # BEGIN WordPress <IfModule mod_rewrite.c> RewriteEngine On RewriteBase / RewriteRule ^index\.php$ - [L] RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule . /index.php [L] </IfModule> # END WordPress Note: Replace WebSiteA with the relevant name 17. Set ownership and permissions on the .htaccess files below: chown apache:apache /www/WebSiteA/wordpress/.htaccess chown apache:apache /www/WebSiteA/wordpress/wp-content/.htaccess chown apache:apache /www/WebSiteA/wordpress/wp-includes/.htaccess chmod 644 /www/WebSiteA/wordpress/.htaccess chmod 644 /www/WebSiteA/wordpress/wp-content/.htaccess chmod 644 /www/WebSiteA/wordpress/wp-includes/.htaccess Note: Replace WebSiteA with the relevant name 18. Create using VI the file /www/WebSiteB/wordpress/.htaccess and add the following content: # BEGIN WordPress <IfModule mod_rewrite.c> RewriteEngine On RewriteBase / RewriteRule ^index\.php$ - [L] RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule . /index.php [L] </IfModule> # END WordPress Header set X-XSS-Protection "1; mode=block" Header set X-Content-Type-Options nosniff Header set Content-Security-Policy "default-src 'self' 'unsafe-inline' 'unsafe-eval' https: data:" Note: Replace WebSiteB with the relevant name 19. Create using VI the file /www/WebSiteB/wordpress/wp-content/.htaccess and add the following content: # BEGIN WordPress <IfModule mod_rewrite.c> RewriteEngine On RewriteBase / RewriteRule ^index\.php$ - [L] RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule . /index.php [L] </IfModule> # END WordPress Note: Replace WebSiteB with the relevant name 20. Create using VI the file /www/WebSiteB/wordpress/wp-includes/.htaccess and add the following content: # BEGIN WordPress <IfModule mod_rewrite.c> RewriteEngine On RewriteBase / RewriteRule ^index\.php$ - [L] RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule . /index.php [L] </IfModule> # END WordPress Note: Replace WebSiteB with the relevant name 21. Set ownership and permissions on the .htaccess files below: chown apache:apache /www/WebSiteB/wordpress/.htaccess chown apache:apache /www/WebSiteB/wordpress/wp-content/.htaccess chown apache:apache /www/WebSiteB/wordpress/wp-includes/.htaccess chmod 644 /www/WebSiteB/wordpress/.htaccess chmod 644 /www/WebSiteB/wordpress/wp-content/.htaccess chmod 644 /www/WebSiteB/wordpress/wp-includes/.htaccess Note: Replace WebSiteB with the relevant name 22. Remove default content from the first WordPress site: rm -f /www/WebSiteA/wordpress/license.txt rm -f /www/WebSiteA/wordpress/readme.html rm -f /www/WebSiteA/wordpress/wp-config-sample.php rm -f /www/WebSiteA/wordpress/wp-content/plugins/hello.php 23. Remove default content from the second WordPress site: rm -f /www/WebSiteB/wordpress/license.txt rm -f /www/WebSiteB/wordpress/readme.html rm -f /www/WebSiteB/wordpress/wp-config-sample.php rm -f /www/WebSiteB/wordpress/wp-content/plugins/hello.php 24. Edit using VI the file /etc/httpd/sites-available/websitea.com.conf Replace the value of the string, from: DocumentRoot /www/WebSiteA To: DocumentRoot /www/WebSiteA/wordpress Replace the value of the string, from: <Directory /www/WebSiteA> To: <Directory /www/WebSiteA/wordpress> Note: Replace WebSiteA with the relevant name 25. Edit using VI the file /etc/httpd/sites-available/websiteb.com.conf Replace the value of the string, from: DocumentRoot /www/WebSiteB To: DocumentRoot /www/WebSiteB/wordpress Replace the value of the string, from: <Directory /www/WebSiteB> To: <Directory /www/WebSiteB/wordpress> Note: Replace WebSiteB with the relevant name 26. Restart the Apache service: systemctl restart httpd.service 27. Open a web browser from a client machine, and enter the URL bellow: http://Server_FQDN/wp-admin/install.php Note: Replace Server_FQDN with the relevant DNS name 28. Select language and click Continue 29. Specify the following information:

 Site Title
 
 Username - replace the default "admin"
 
 Password
 
 E-mail
  1. Click on “Install WordPress” button, and close the web browser.

  2. Change ownership and permissions on the files and folders below: chown -R apache:apache /www/WebSiteA/wordpress find /www/WebSiteA/wordpress/ -type d -exec chmod -R 755 {} \; find /www/WebSiteA/wordpress/ -type f -exec chmod -R 644 {} \; chmod 400 /www/WebSiteA/wordpress/wp-config.php chown apache:apache /www/WebSiteA/config.php chmod 644 /www/WebSiteA/config.php Note: Replace WebSiteA with the relevant name

  3. Change ownership and permissions on the files and folders below: chown -R apache:apache /www/WebSiteB/wordpress find /www/WebSiteB/wordpress/ -type d -exec chmod -R 755 {} \; find /www/WebSiteB/wordpress/ -type f -exec chmod -R 644 {} \; chmod 400 /www/WebSiteB/wordpress/wp-config.php chown apache:apache /www/WebSiteB/config.php chmod 644 /www/WebSiteB/config.php Note: Replace WebSiteB with the relevant name

  4. Download “WordPress Firewall” plugin from: http://www.seoegghead.com/software/wordpress-firewall.seo

  5. Copy the “WordPress Firewall” plugin file “wordpress-firewall.php” using PSCP (or SCP) into /www/WebSiteA/wordpress/wp-content/plugins Note: Replace WebSiteA with the relevant name

  6. Copy the “WordPress Firewall” plugin file “wordpress-firewall.php” using PSCP (or SCP) into /www/WebSiteB/wordpress/wp-content/plugins

  7. Open a web browser from a client machine, and enter the URL bellow: http://Server_FQDN/wp-login.php Note: Replace Server_FQDN with the relevant DNS name

  8. From WordPress dashboard, click on “settings” -> make sure that “Anyone can register” is left unchecked -> put a new value inside the “Tagline” field -> click on “Save changes”.

  9. From the left pane, click on Plugins -> Add New -> search, install and activate the following plugins:

    Acunetix WP Security

    Antispam Bee

    WP Limit Login Attempts

    Login LockDown

    WP Security Audit Log

  10. From the list of installed plugins, locate and activate the Firewall plugin

  11. From the upper pane, click on “Log Out”.

  12. Delete the file /wp-admin/install.php

SSL Configuration Phase

  1. Login using privileged account
  2. To add support for SSL certificates, run the command below: yum install mod_ssl -y
  3. Run the command below to change the permissions on the certificates folder: chmod 700 /etc/pki/CA/private
  4. Run the command bellow to generate a key pair for the first WordPress site: openssl genrsa -des3 -out /etc/pki/CA/private/websitea-server.key 2048 Note 1: Specify a complex pass phrase for the private key (and document it) Note 2: Replace websitea with the relevant name
  5. Run the command bellow to generate a key pair for the second WordPress site: openssl genrsa -des3 -out /etc/pki/CA/private/websiteb-server.key 2048 Note 1: Specify a complex pass phrase for the private key (and document it) Note 2: Replace websiteb with the relevant name
  6. Run the command bellow to generate the CSR for the first WordPress site: openssl req -new -newkey rsa:2048 -nodes -sha256 -keyout /etc/pki/CA/private/websitea-server.key -out /tmp/websitea-apache.csr Note 1: The command above should be written as one line. Note 2: Replace websitea with the relevant name
  7. Run the command bellow to generate the CSR for the second WordPress site: openssl req -new -newkey rsa:2048 -nodes -sha256 -keyout /etc/pki/CA/private/websiteb-server.key -out /tmp/websiteb-apache.csr Note 1: The command above should be written as one line. Note 2: Replace websiteb with the relevant name
  8. Edit using VI the file /etc/httpd/sites-available/websitea.com.conf and add the following: <VirtualHost *:443> ServerAdmin admin@websitea.com ServerName www.websitea.com ServerAlias websitea.com DocumentRoot /www/WebSiteA/wordpress <Directory /> Options FollowSymLinks AllowOverride None </Directory> <Directory /www/WebSiteA/wordpress> Options Indexes FollowSymLinks MultiViews AllowOverride all Require all granted Order allow,deny Allow from all <LimitExcept GET POST> deny from all </limitexcept> </Directory> SSLCertificateFile /etc/ssl/certs/websitea.crt SSLCertificateKeyFile /etc/pki/CA/private/websitea-server.key SSLCipherSuite EECDH+ECDSA+AESGCM:EECDH+aRSA+AESGCM:EECDH+ECDSA+SHA384:EECDH+ECDSA+SHA256:EECDH+aRSA+SHA384:EECDH+aRSA+SHA256:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES128-SHA256:AES128-GCM-SHA256:ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:DH+AES:ECDH+3DES:DH+3DES:RSA+AES:RSA+3DES:!ADH:!AECDH:!MD5:!DSS:!aNULL:!EDH:!eNULL:!LOW:!3DES:!MD5:!EXP:!PSK:!SRP:!DSS SSLHonorCipherOrder On # Disable SSLv2 and SSLv3 SSLProtocol ALL -SSLv2 –SSLv3 +TLSv1 +TLSv1.1 +TLSv1.2 # Disable SSL Compression SSLCompression Off SSLEngine on ErrorLog /www/WebSiteA/logs/ssl_error.log CustomLog /www/WebSiteA/logs/ssl_access.log combined </VirtualHost> Note: Replace WebSiteA with the relevant name
  9. Edit using VI the file /etc/httpd/sites-available/websiteb.com.conf and add the following: <VirtualHost *:443> ServerAdmin admin@websiteb.com ServerName www.websiteb.com ServerAlias websiteb.com DocumentRoot /www/WebSiteB/wordpress <Directory /> Options FollowSymLinks AllowOverride None </Directory> <Directory /www/WebSiteB/wordpress> Options Indexes FollowSymLinks MultiViews AllowOverride all Require all granted Order allow,deny Allow from all <LimitExcept GET POST> deny from all </limitexcept> </Directory> SSLCertificateFile /etc/ssl/certs/websiteb.crt SSLCertificateKeyFile /etc/pki/CA/private/websiteb-server.key SSLCipherSuite EECDH+ECDSA+AESGCM:EECDH+aRSA+AESGCM:EECDH+ECDSA+SHA384:EECDH+ECDSA+SHA256:EECDH+aRSA+SHA384:EECDH+aRSA+SHA256:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES128-SHA256:AES128-GCM-SHA256:ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:DH+AES:ECDH+3DES:DH+3DES:RSA+AES:RSA+3DES:!ADH:!AECDH:!MD5:!DSS:!aNULL:!EDH:!eNULL:!LOW:!3DES:!MD5:!EXP:!PSK:!SRP:!DSS SSLHonorCipherOrder On # Disable SSLv2 and SSLv3 SSLProtocol ALL -SSLv2 –SSLv3 +TLSv1 +TLSv1.1 +TLSv1.2 # Disable SSL Compression SSLCompression Off SSLEngine on ErrorLog /www/WebSiteB/logs/ssl_error.log CustomLog /www/WebSiteB/logs/ssl_access.log combined </VirtualHost> Note: Replace WebSiteB with the relevant name
  10. Edit using VI the file /etc/httpd/conf.d/ssl.conf and comment the following commands: <VirtualHost _default_:443> ErrorLog logs/ssl_error_log TransferLog logs/ssl_access_log LogLevel warn SSLEngine on SSLProtocol all -SSLv2 -SSLv3 SSLCipherSuite HIGH:3DES:!aNULL:!MD5:!SEED:!IDEA SSLCertificateFile SSLCertificateKeyFile
  11. Restart the Apace service, run the command below: systemctl restart httpd
  12. Run the commands below to enable HTTPD rule on the firewall: firewall-cmd --zone=public --add-service=https --permanent systemctl restart firewalld
  13. Run the command below to change the permissions on the certificates folder: chmod 600 /etc/pki/CA/private
  14. In-case the server was configured with SSL certificate, add the following line to the /www/WebSiteA/config.php file: define('FORCE_SSL_LOGIN', true); Note: Replace WebSiteA with the relevant name
  15. In-case the server was configured with SSL certificate, add the following line to the /www/WebSiteB/config.php file: define('FORCE_SSL_LOGIN', true); Note: Replace WebSiteB with the relevant name

WordPress upgrade process

  1. Run the commands below to change the SELinux permissions: semanage fcontext -a -t httpd_sys_rw_content_t "/www/WebSiteA/wordpress(/.*)?" restorecon -F -R -v /www/WebSiteA/wordpress chcon -R -t httpd_sys_rw_content_t /www/WebSiteA/wordpress Note: Replace WebSiteA with the relevant name
  2. Login to the WordPress admin portal: http://Server_FQDN/wp-login.php Note: Replace Server_FQDN with the relevant DNS name
  3. When prompted, select to upgrade the Wordpress
  4. Once the upgrade process completes successfully, log off the WordPress admin portal
  5. Run the commands below to change the SELinux permissions: semanage fcontext -a -t httpd_sys_content_t "/www/WebSiteA/wordpress(/.*)?" restorecon -F -R -v /www/WebSiteA/wordpress chcon -R -t httpd_sys_content_t /www/WebSiteA/wordpress semanage fcontext -a -t httpd_sys_rw_content_t "/www/WebSiteA/wordpress/wp-content(/.*)?" restorecon -F -R -v /www/WebSiteA/wordpress/wp-content chcon -R -t httpd_sys_rw_content_t /www/WebSiteA/wordpress/wp-content Note: Replace WebSiteA with the relevant name
  6. Logoff the SSH console

Check your site on the following test sites

  1. https://www.ssllabs.com/ssltest/
  2. https://dnsflagday.net/
  3. https://securityheaders.com/
  4. https://search.google.com/test/mobile-friendly