web analytics

Posts Tagged ‘ssl’

WordPress 5.x Hardening Guide for CentOS 7.6

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

    1. Login using privileged account.
    2. 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.
    3. 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.
    4. 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
    5. 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
    6. 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
    7. 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/
    8. 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/
    9. 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
    10. 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
    11. 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
    12. 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
    13. 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
    14. 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
    15. 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
    16. 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
    17. 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
    18. 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
    19. 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
    20. 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
    21. 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
    22. 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
    23. 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
    24. Restart the Apache service:
      systemctl restart httpd.service
    25. 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
    26. Select language and click Continue
    27. Specify the following information:
        Site Title
        Username – replace the default “admin”
        Password
        E-mail
    28. Click on “Install WordPress” button, and close the web browser.
    29. 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
    30. 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
    31. Download “WordPress Firewall” plugin from:
      http://www.seoegghead.com/software/wordpress-firewall.seo
    32. 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
    33. Copy the “WordPress Firewall” plugin file “wordpress-firewall.php” using PSCP (or SCP) into /www/WebSiteB/wordpress/wp-content/plugins
    34. 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
    35. 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”.
    36. 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
    37. From the list of installed plugins, locate and activate the Firewall plugin
    38. From the upper pane, click on “Log Out”.
    39. 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
      • https://www.ssllabs.com/ssltest/
      • https://dnsflagday.net/
      • https://securityheaders.com/
      • https://search.google.com/test/mobile-friendly