In this post, I’ll detail a step by step process to set up WordPress on a fresh install of CentOS 7. SELinux will be enabled and in a virtual host.

After changing providers, I had to migrate my site and couldn’t find a guide that I was happy with. Some were not complete, some directly disabled SELinux, … so I chose to write my own. Also, disabling SELinux is a big NO-NO in my book.

The steps to follow are:

  1. Add users
  2. Install Apache
  3. Check and configure the firewall
  4. Install MySQL and PHP
  5. Create virtual hosts
  6. Configure SELinux
  7. Install WordPress

ADD USERS

First things first, we’ll add a user and add him to the sudoers. This way, we won’t need to be root.

As root user:

# adduser dummyuser
# passwd dummyuser

Add dummyuser to sudoers:

visudo

Find the following part:

## Allow root to run any commands anywhere
root ALL=(ALL) ALL

Add the following line after that:

dummyuser ALL=(ALL) ALL

Log off and log in again as dummyuser, and go on.

INSTALL APACHE

sudo yum install httpd

After the installation is complete, start Apache and check if it’s working or not.

sudo systemctl start httpd.service

Launch a browser and visit the root page of the server. You should see a welcome page.

SETTING UP THE FIREWALL

Whether it worked or not, it’s time to check firewall status:

firewall-cmd --state

If the result is running and you can see apache’s test site, you can skip the following steps up to the next section. Otherwise, we’ll have to configure and enable it.

A little safeguard in case we do something wrong and end up locked out of our server (can be safely skipped when working locally)

sudo shutdown -r 30

This will reboot the server in 30 minutes, losing every change that wasn’t permanent. In case you mess up and get locked out, go grab a coffe and carry on later. To cancel the reboot:

sudo shutdown -c

This safeguard is not strictly necessary, but I prefer to be safe when working remotely, and a reboot is allowed. You should be careful with timing. When it runs out, the server will reboot losing not saved changes. Adjust the timing to your needs or refresh the timing by cancelling the reboot and programming a new one.
I’ve taken up this practice when working with remote equipment (not your typical server room) Being looked out means someone commutes for 2 hours to work revert changes. Better safe than sorry.

If the firewall service was not running, we’ll check again with it running:

sudo systemctl start firewalld.service
firewall-cmd --state

Now we should have it in a running state.

firewall-cmd --get-default-zone

Returns public which is fine, as it’s the least trustworthy zone that actually allows some connections from the outside.

firewall-cmd --list-all

Returns the services allowed, that on a fresh install shoudl be few.

Now we’ll add http service:

sudo firewall-cmd --zone=public --add-service=http

This command should return success

Just to recheck, if we repeat firewall-cmd --list-all, it should have added http service.

As a bonus, firewall-cmd --get-services lists currently predefined services

Once tested that the configuration is correct, make all changes permanent so they’ll remain after a reboot:

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

This command should return success

Finally, enable the firewall so it starts on boot:

sudo systemctl enable firewalld

ENABLE APACHE ON BOOT

Now that apache is finaly working and accesible from the outside, enable it so it starts on boot:

sudo systemctl enable httpd.service

INSTALL MYSQL AND PHP

Now we’ll install the database and PHP.

sudo yum install mariadb-server mariadb
sudo systemctl start mariadb
mysql_secure_installation

This last step takes care of securing some defaults.
As it’s freshly installled, mysql will probably not have a password for it’s user root.

Let’s enable mysql on system start:

sudo systemctl enable mariadb.service

Now we’ll install PHP;

sudo yum install php php-cli php-common php-gd php-intl php-mbstring php-mysql php-pear php-pdo php-pecl-memcache php-xml

And restart apache:

systemctl restart httpd.service

CHECK IF PHP IS WORKING

Time to check if PHP is working correctly. Create a simple page with your editor of choice:

vi /var/www/html/info.php

And the actual content:

<?php
  phpinfo();
?>

Browse test page, and check whether mod_rewrite is enabled or not (it will come handy later)

After checking everythings working, remove the test file:

rm /var/www/html/info.php

CREATE APACHE VIRTUAL HOSTS

Create directory structure for Virtual Hosts:

sudo mkdir -p /var/www/vhosts/itanddevelopment.com/public_html
sudo mkdir -p /var/www/vhosts/example.com/public_html
sudo mkdir -p /var/www/vhosts/example2.com/public_html

Set up permissions:

sudo chown -R $USER:$USER /var/www/vhosts/itanddevelopment.com/public_html
sudo chown -R $USER:$USER /var/www/vhosts/example.com/public_html
sudo chown -R $USER:$USER /var/www/vhosts/example2.com/public_html

$USER will take the currently logged user value (no need to change it)

sudo chmod -R 755 /var/www

TEST VIRTUAL HOSTS

Time to test Virtual Hosts:
Create a demo page for each virtual host

vi /var/www/vhosts/itanddevelopment.com/public_html/index.html

A simple demo page:

<html>
  <head>
    <title>Virtual Host for itanddevelopment.com!</title>
  </head>
  <body>
    <h1>The itanddevelopment.com virtual host is working!</h1>
  </body>
</html>

Create a different file for each virtualhost you want to create, replace the name accordingly.

sudo mkdir /etc/httpd/sites-available
sudo mkdir /etc/httpd/sites-enabled
sudo vi /etc/httpd/sites-available/itanddevelopment.com.conf

As a simple example, this .conf could look like:

<VirtualHost *:80>
ServerName www.itanddevelopment.com
ServerAlias itanddevelopment.com
DocumentRoot /var/www/vhosts/itanddevelopment.com/public_html
ErrorLog /var/www/vhosts/itanddevelopment.com/logs/error.log
CustomLog /var/www/vhosts/itanddevelopment.com/logs/requests.log combined
</VirtualHost>

For each virtual host, add the corresponding .conf file.

ENABLING VIRTUAL HOSTS

To enable virtual hosts:

sudo vi /etc/httpd/conf/httpd.conf

Add at the end:

# Include virtual hosts
IncludeOptional sites-enabled/*.conf

To make a site go live, make a link from sites-available to sites-enabled:

sudo ln -s /etc/httpd/sites-available/itanddevelopment.com.conf /etc/httpd/sites-enabled/itanddevelopment.com.conf

And restart Apache:

sudo systemctl restart httpd.service

For disabling a site, just remove the link and restart Apache.

SELINUX CONFIGURATION FOR VIRTUAL HOSTS

SELinux won’t allow httpd to write in our custom log location. Now we’ll configure it properly:

sudo yum install setools setroubleshoot

sudo semanage fcontext -a -t httpd_sys_content_t "itanddevelopment.com(/.*)?"
sudo semanage fcontext -a -t httpd_log_t "itanddevelopment.com/logs(/.*)?"
sudo restorecon -Rv itanddevelopment.com

sudo semanage fcontext -a -t httpd_sys_content_t "example.com(/.*)?"
sudo semanage fcontext -a -t httpd_log_t "example.com/logs(/.*)?"
sudo restorecon -Rv example.com

sudo semanage fcontext -a -t httpd_sys_content_t "example2(/.*)?"
sudo semanage fcontext -a -t httpd_log_t "example2/logs(/.*)?"
sudo restorecon -Rv example2.com

TROUBLESHOOTING SELINUX

If there’s any problem with SELinux policies

sealert -a /var/log/audit/audit.log

will parse the log and provide hints at problems and possible solutions.

If you are note sure whether the problem is SELinux related or not, the policy can be set to permissive, so the system will not enforce the SE policies but will log them.

sudo setenforce permissive

To check those logs:

sealert -a /var/log/audit/audit.log

will parse SELinux related problems and propose solutions.
Finally, remember to ALWAYS set to enforcing mode.

sudo setenforce enforcing

INSTALL WORDPRESS

Finally, it’s time to install WordPress. The first step will be to create the database:

mysql -u root -p
CREATE DATABASE wordpress;
CREATE USER wordpressuser@localhost IDENTIFIED BY 'wpuserpassword';
GRANT ALL PRIVILEGES ON wordpress.* TO wordpressuser@localhost IDENTIFIED BY 'wpuserpassword';
FLUSH PRIVILEGES;
EXIT;

This will ask for root password that was set up while securing the database. wordpress wordpressuser wpuserpassword can should be changed to your needs.

Now, we’ll download the latest WordPress version:

cd
wget http://wordpress.org/latest.tar.gz
tar -zxvf latest.tar.gz

Next, create the final directory, copy WordPress and create Uploads directory:

sudo mkdir /var/www/vhosts/itanddevelopment.com/blog.itanddevelopment.com
sudo chown dummyuser:apache blog.itanddevelopment.com

sudo rsync -avP /home/dummyuser/wordpress/ /var/www/vhosts/itanddevelopment.com/blog.itanddevelopment.com/

mkdir /var/www/html/wp-content/uploads

FINAL TOUCHES TO CONFIGURATION

cd /var/www/vhosts/itanddevelopment.com/blog.itanddevelopment.com
cp wp-config-sample.php wp-config.php
vi wp-config.php

Change DB_NAME DB_USER DB_PASSWORD to your version of wordpress wordpressuser wpuserpassword
Change the authentication keys and salts to the values you get in: WordPress API Salt

Optionally, $table_prefix can be modified. It will usually not be neccesary, but if you intend on sharing the same database with multiple wordpress installations, this identifier must be unique and different for all of them.

Apache should be allowed to write on wp-content so SELinux context should be modified:

sudo semanage fcontext -a -t httpd_sys_rw_content_t "/var/www/vhosts/itanddevelopment.com/blog.itanddevelopment.com/wp-content(/.*)?"
sudo restorecon -Rv ./itanddevelopment.com

During the installation, Apache should be able to modify wp-config.php

sudo semanage fcontext -a -t httpd_sys_rw_content_t "/var/www/vhosts/itanddevelopment.com/blog.itanddevelopment.com/wp-config.php"
sudo restorecon -Rv ./itanddevelopment.com

Now, WordPress should be up and running, ready to configure from the web interface with your preferred theme, plugins, users, … Hint: If an error appears asking for FTP user / password credentials when installing new plugins or themes, modify wp-config.php and add the following:


/** Error installing plugins and themes. System asks for FTP user / password
*/
define('FS_METHOD', 'direct');

Optionally (but I would recommend it), after your changes have taken place, you should return wp-config.php to it’s previous context, so no writing will happen without your knowledge.

sudo semanage fcontext -a -t httpd_sys_content_t "/var/www/vhosts/itanddevelopment.com/blog.itanddevelopment.com/wp-config.php"
sudo restorecon -Rv ./itanddevelopment.com

Happy Blogging

Did you find the post useful? Would you invite me to a nice coffe or offer some help running the site ad-free?
1EpMM5szeNSSYxgDKBvksyCCizKHoAZmBs