Overview
Zen Astronave is a personal blog site.
In this guide, we will implement a Linux, Apache, MariaDB, and PHP (LAMP) system and install WordPress for zenastronave.com. Since we are interested in the Confidentiality, Integrity, and Availability (CIA) triad, we will also implement a firewall, Transport Layer Secuirty (TLS) certificates, and daily backups.
This example uses AlmaLinux but should also be useful for administrators of RedHat Linux and any other RedHat-style distribution including Fedora, CentOS, and Rocky Linux. Additionally, administrators can substitute MySQL for MariaDB with only minor adjustments.
Assumptions
This guide assumes you have a domain name (substitute your domain for zenastronave.com in the examples); root shell access to a public-facing AlmaLinux version >=9.0 system; and SELinux is in enforcing mode.
Environment
This section provides insight into the Zen Astronave infrastructure to demonstrate systems administration best practices. The detail here may not be applicable to your environment; however, the rest of the guide should be useful for any AlmaLinux system.
There are three systems involved in this implementation: (a) a Linux KVM hypervisor providing a bridge for guest networking and ZFS zvols for guest disks, (b) a ZFS backup system, and (c) an AlmaLinux virtual machine with Apache, MariaDB, Firewalld, and the EFF‘s Certbot (TLS certificates) to host zenastronave.com.
The zvol (disk) for the AlmaLinux virtual machine was created on the Linux KVM hypervisor system by configuring and executing OZO Znap and Zhip on the ZFS backup system. OZO Znap and Zhip remotely executed commands on the Linux KVM hypervisor to create the zvol, then created and shipped the origin snapshot and the first incremental snapshot. Every time OZO Znap and Zhip is executed on the ZFS backup system (daily), it creates and ships another incremental snapshot. So, before the virtual machine has even been created, we already have a mechanism in place to perform a daily backup of the VM’s entire system disk.
The virtual machine was defined on the Linux KVM hypervisor system using OZO Virt-Install and a kickstart. The OZO Virt-Install configuration file and kickstart files on the hypervisor (which is also backed up daily) can be used to easily recreate the virtual machine in the event it is damaged or deleted. The kickstart implements an AlmaLinux virtual machine (guest) with Firewalld enabled (permitting SSH) and SELinux in enforcing mode.
The rest of this guide details the process of configuring the AlmaLinux LAMP system and installing and configuring WordPress.
Implement the LAMP System
Install Packages
Here we use dnf
to install the packages required for this guide.
[root@localhost]# dnf -y install certbot git httpd mariadb mariadb-server mod_ssl php php php-gd php-intl php-mysqlnd php-pecl-imagick php-pecl-mailparse php-pecl-zip python3-certbot-apache
Set Permissions and Ownership for the Apache Document Root
In this step, we will set ownership and permissions for the Apache document root, /var/www/html/www.zenastronave.com
.
[root@localhost]# chown -R apache:apache /var/www/html/www.zenastronave.com
[root@localhost]# chmod 775 /var/www/html/www.zenastronave.com
Create Group and Apply Filesystem ACLs
In this step, we will create a group and apply filesystem ACLs that will allow the www
group to modify all files in the Apache document root. Adding your own user to this group allows you to modify the files in the document root without using sudo. Substitute your username for USERNAME.
We will also ensure that the apache user and group will have read and write access to the entire directory structure.
[root@localhost]# groupadd www
[root@localhost]# usermod -a -G www USERNAME
[root@localhost]# setfacl -m d:u:apache:rwx,d:g:apache:rwx,d:g:www:rwx,g:www:rwx /var/www/html/www.zenastronave.com
Log out and back in to make this group membership change effective.
Configure SELinux
We must enable some SELinux booleans to permit Apache to load modules (like the PHP module) and network connect (like when WordPress checks for updates). For more information, please see Security Enhanced Linux Policy for the httpd processes.
[root@localhost]# setsebool -P domain_kernel_load_modules 1
[root@localhost]# setsebool -P httpd_can_network_connect 1
We also need to create an SELinux fcontext for the wordpress
directory we will be creating later. Adding it now ensures it will be applied when the directory is created.
[root@localhost]# semanage fcontext -a -t httpd_sys_rw_content_t "/var/www/html/*/wordpress(/.*)?"
Start and Configure MariaDB
In this step, we will enable and start the MariaDB server and set a password for the root user. Substitute your own strong password for PASSWORD. Note: You may wish to run mysql_secure_installation for a more comprehensive process.
[root@localhost]# systemctl enable --now mariadb
[root@localhost]# mysqladmin -u root password 'PASSWORD'
Implement OZO MariaDB Backup
This is important to implement even if your environment includes something like the ZFS backup process detailed in “Environment”, above. Snapshots taken while certain daemons e.g., relational databases are active may result in inconsistencies in the backup set. OZO MariaDB Backup uses MariaDB methods to dump the database contents to a file on the system disk where it can be included in a snapshot (or other backup mechanism) with greater consistency. It also means that some database backup history is available on the local system disk which supports faster recovery time in certain circumstances.
Implement OZO MariaDB Backup to perform a daily dump of all databases to the system disk so we have a backup mechanism in place even before we’ve created our WordPress database. As detailed in the OZO MariaDB Backup readme.md, set a user and strong password in /etc/ozo-mariadb-backup.conf
and use that information in the MariaDB shell to create the backup user, substituting your strong password for PASSWORD.
[root@localhost]# mysql -u root -p
MariaDB [(none)]> GRANT SELECT, RELOAD, LOCK TABLES, SHOW VIEW ON *.* TO 'mysql-backup'@'localhost' IDENTIFIED BY 'PASSWORD';
MariaDB [(none)]> flush privileges;
MariaDB [(none)]> quit;
Configure Apache
We will create a directory for Virtual Host configurations and create a basic site configuration that we will use to obtain TLS certificates.
[root@localhost]# echo 'IncludeOptional vhost.d/*.conf' >> /etc/httpd/conf/httpd.conf
[root@localhost]# mkdir /etc/httpd/vhost.d
[root@localhost]# nano /etc/httpd/vhost.d/www.zenastronave.com.conf
Contents of /etc/httpd/vhost.d/www.zenastronave.com.conf
:
<Virtualhost *:80>
ServerAdmin noreply@zenastronave.com
ServerName zenastronave.com
ServerAlias www.zenastronave.com
DocumentRoot "/var/www/html/www.zenastronave.com"
CustomLog "logs/access_log" combined
ErrorLog "logs/error_log"
<Directory "/var/www/html/www.zenastronave.com">
Options +Indexes +FollowSymLinks -MultiViews
AllowOverride All
Require all granted
</Directory>
<IfModule dir_module>
DirectoryIndex index.php index.html
</IfModule>
<Files ".ht*">
Require all denied
</Files>
</VirtualHost>
Create Firewall Rules
These firewall rules will allow network requests to reach Apache on port 80 (HTTP) and 443 (HTTPS).
[root@localhost]# firewall-cmd --permanent --zone=public --add-service=http --add-service=https
[root@localhost]# firewall-cmd --reload
Enable and Start Apache
We will start Apache with the current configuration so Certbot to can validate domain ownership and generate certificates. Later, we will use Apache RewriteRules to force all traffic to HTTPS.
[root@localhost]# systemctl enable --now httpd
Obtain TLS Certificates
The Certbot implementation on AlmaLinux cannot automagically configure our VirtualHost, so we will use a command that simply generates and saves the certificates. This command also includes multiple hosts in a single certificate. In a later step, we will reconfigure Apache to use the certificates and rewrite www.zenastronave.com to zenastronave.com.
[root@localhost]# certbot certonly --webroot -w /var/www/html/www.zenastronave.com -d www.zenastronave.com -d zenastronave.com
The certbot command generated a certificate and private key at the following paths:
/etc/letsencrypt/live/www.zenastronave.com/fullchain.pem
/etc/letsencrypt/live/www.zenastronave.com/privkey.pem
Automate Certificate Renewal
To make sure our certificates are renewed before they expire, we can enable the certbot-renew timer:
# systemctl enable --now certbot-renew.timer
Install WordPress
Create a WordPress Database
Open the MariaDB shell and create a database + user + password for WordPress, substituting your own strong password for PASSWORD. Keep this information handy for the next steps.
[root@localhost]# mysql -u root -p
MariaDB [(none)]> create database wordpress;
MariaDB [(none)]> GRANT ALL PRIVILEGES ON wordpress.* TO 'wordpress'@'localhost' IDENTIFIED BY 'PASSWORD';
MariaDB [(none)]> flush privileges;
MariaDB [(none)]> quit;
Obtain and Extract WordPress
Download the latest version of WordPress to the root
user home directory and extract it to /var/www/html/www.zenatronave.com
. Once extracted, set the permissions and ownership for Apache.
[root@localhost]# cd ~
[root@localhost]# wget https://wordpress.org/latest.zip
[root@localhost]# cd /var/www/html/www.zenastronave.com
[root@localhost]# unzip ~/latest.zip
[root@localhost]# rm ~/latest.zip
[root@localhost]# chown -R apache:apache wordpress
[root@localhost]# find wordpress -type d -exec chmod 775 {} \;
[root@localhost]# find wordpress -type f -exec chmod 664 {} \;
Create the Default .htaccess
File
Create a default .htaccess
file in the wordpress
directory.
[root@localhost]# nano /var/www/html/www.zenastronave.com/wordpress/.htaccess
Copy-Paste this content into .htaccess
:
# BEGIN WordPress
RewriteEngine On
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
# END WordPress
Change the user and group ownership of .htaccess
:
[root@localhost]# chown apache:apache /var/www/html/www.zenastonave.com/wordpress/.htaccess
Verify Filesystem Permissions, Ownership, and ACLs
At this point we can use commands to verify that the SELinux fcontext is correct and the filesystem ownership, permissions, and www
ACL are correct.
[root@localhost]# restorecon -R /var/www/html/www.zenastronave.com
[root@localhost]# ls -hlZ /var/www/html/www.zenastronave.com/
drwxrwxr-x+ 5 apache apache unconfined_u:object_r:httpd_sys_rw_content_t:s0 wordpress
[root@localhost]# getfacl /var/www/html/www.zenastronave.com/wordpress
# file: wordpress
# owner: apache
# group: apache
user::rwx
group::rwx
group:www:rwx
mask::rwx
other::r-x
default:user::rwx
default:group::rwx
default:group:www:rwx
default:mask::rwx
default:other::r-x
Configure WordPress
Follow the steps in Editing wp-config.php using the database + user + password you created above.
[root@localhost]# mv /var/www/html/www.zenastronave.com/wordpress/wp-config-sample.php /var/www/html/www.zenastronave.com/wordpress/wp-config.php
[root@localhost]# nano /var/www/html/www.zenastronave.com/wordpress/wp-config.php
You will set values for DB_NAME
, DB_USER
, and DB_PASSWORD
; and will use the WordPress Secret Key Service to set unique values for AUTH_KEY
, SECURE_AUTH_KEY
, LOGGED_IN_KEY
, NONCE_KEY
, AUTH_SALT
, SECURE_AUTH_SALT
, LOGGED_IN_SALT
, and NONCE_SALT
(the output generated by the key service will completely replace the existing corresponding lines).
Reconfigure and Restart Apache
Since we have our TLS certificates, we can reconfigure Apache to rewrite all traffic to HTTPS and use the certificates to provide a secure session for our site visitors. Edit /etc/httpd/vhost.d/zenastronave.com.conf
as follows (changes in bold):
<Virtualhost *:80>
ServerAdmin noreply@zenastronave.com
ServerName zenastronave.com
ServerAlias www.zenastronave.com
DocumentRoot "/var/www/html/www.zenastronave.com/wordpress"
CustomLog "logs/access_log" combined
ErrorLog "logs/error_log"
# Rewrite all traffic to HTTPS
RewriteEngine On
RewriteCond %{HTTPS} off
# Prevent certbot verfication requests from being rewritten to HTTPS
RewriteCond %{REQUEST_URI} !^/.well-known($|/) [NC]
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} [R=301]
<Directory "/var/www/html/www.zenastronave.com/wordpress">
Options +Indexes +FollowSymLinks -MultiViews
AllowOverride All
Require all granted
</Directory>
<IfModule dir_module>
DirectoryIndex index.php index.html
</IfModule>
<Files ".ht*">
Require all denied
</Files>
</VirtualHost>
<Virtualhost *:443>
ServerAdmin noreply@zenastronave.com
ServerName zenastronave.com
ServerAlias www.zenastronave.com
DocumentRoot "/var/www/html/www.zenastronave.com/wordpress"
CustomLog logs/ssl_request_log "%t %h %{SSL_PROTOCOL}x %{SSL_CIPHER}x \"%r\" %b"
ErrorLog "logs/ssl_error_log"
RewriteEngine On
RewriteCond %{HTTP_HOST} ^www\.zenastronave\.com [NC]
RewriteRule ^(.*)$ http://zenastronave.com/$1 [L,R=301]
SSLEngine on
SSLHonorCipherOrder on
SSLCipherSuite PROFILE=SYSTEM
SSLProxyCipherSuite PROFILE=SYSTEM
SSLCertificateFile /etc/letsencrypt/live/www.zenastronave.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/www.zenastronave.com/privkey.pem
<Directory "/var/www/html/www.zenastronave.com/wordpress">
Options -Indexes +FollowSymLinks -MultiViews
AllowOverride All
Require all granted
</Directory>
<IfModule dir_module>
DirectoryIndex index.php index.html
</IfModule>
<Files ".ht*">
Require all denied
</Files>
<FilesMatch "\.(cgi|shtml|phtml|php)$">
SSLOptions +StdEnvVars
</FilesMatch>
<Directory "/var/www/cgi-bin">
SSLOptions +StdEnvVars
</Directory>
</VirtualHost>
Restart Apache
Restarting Apache will make the configuration changes effective.
[root@localhost]# systemctl restart httpd
Initialize WordPress
Finally, we visit https://zenastronave.com and provide an application login username and password to the WordPress setup wizard. It is now possible to install plugins, themes, and create pages and posts. Recommended plugins:
- Contact Form 7
- Embed Plus YouTube
- Envira Gallery
- Media Sync by Erol Živina
- W3 Total Cache
- WordPress Importer
Conclusion
Using a firewall, TLS certificates, and leveraging SELinux in enforcing mode provides strong confidentiality. Routine backups of the database to the system disk and a routine backup of the system disk to a geographically distinct backup system provides high data integrity. Running AlmaLinux in a Linux KVM hypervisor with a public IP address provides high availability.
Hopefully, some or all of this guide has been helpful for you. If you do not have the opportunity to leverage Linux KVM + ZFS for provisioning guest disks with backup, you can use OZO Rdiff-Backup to back up your AlmaLinux system from any internet-connected Linux system with SSH.
Happy WordPress-ing!
- Share:
One thought on “WordPress on LAMP with Session Encryption and Backup”
Comments are closed.