laurenceshaw.net technical documents

Use of these resources represents your agreement to Australian © Copyright Laws and the general guidelines in our Terms of Use & Privacy Policy

These articles are not easy to follow and need IT skills to work through, but they show what must be done to use an EC2 instance with WordPress. No liability at all for use of this information.

Installing and maintaining an end-to-end solution with WordPress EC2 Linux2 instances is involved – an ongoing learning curve and strong problem solving skills. This platform offers benefits but is built with several systems.

It is recommended to use a t3amicro instance (a nano is okay for development.) YOu may like the idea of halving the price with a nano instance, but you will run into problems with editing longer web pages, possible site freeze ups, and inability to deal with larger numbers of photographs.

This is not a tutorial. The steps given below will install an EC2 instance for an individual or sole trader, even a small business if appropriate. Once you create a stable instance, you need to add a database and user via phpMyAdmin, then edit the wp-config.php file to point to these setups. It is assumed you are familiar with these details and various other aspects of AWS services, such as the complexities for handling email and DNS etc.

Documents
IDCommentsCommands
Notes: I use the Unix vi editor in these examples.
We assume you will install SSL certificates and https://
You will have already set up the SSH login and quite possibly FileZilla. Your EC2 instance will show these "connect" details.
The instance will need to have been configured without extra CPU bursts in order to stop bill shock as they say, and will need a security group that has HTTPS, SSH, and memcached configured.
See further notes on the attached PDF screen images.
If some of the configs below are not working with the cut and paste in your mouse, refer to this text document:

INSTALL EC2 LINUX PHP7.4

For some screen shots relevant to the EC2 instance see this document:

ec2_install.pdf
1Disk swap spaceecho "vm.swappiness=10" >> /etc/sysctl.conf
echo "vm.vfs_cache_pressure=200" >> /etc/sysctl.conf
sysctl -w vm.swappiness=10
sysctl -w vm.vfs_cache_pressure=200
dd if=/dev/zero of=/swapfile bs=1024 count=1048576
mkswap /swapfile
chmod 600 /swapfile
swapon /swapfile
echo "/swapfile swap swap defaults 0 0" >> /etc/fstab
free -m
2Modify /etc/bashrcCOMMENT OUT THE STANDARD LINE:
# [ "$PS1" = "\\s-\\v\\\$ " ] && PS1="[\u@\h \W]\\$ "

ADD YOUR OWN LINE, where NAME is any string you like:
[ "$PS1" = "\\s-\\v\\\$ " ] && PS1="[\u@NAME: \w]\\$ "

For example:

[ "$PS1" = "\\s-\\v\\\$ " ] && PS1="[\u@shawlw.au: \w]\\$ "

Then exit the SHELL and log back in with sudo su after logging in.
3Timezone - use your own locationa="Australia/Brisbane";export a;echo $a
ln -sf /usr/share/zoneinfo/$a /etc/localtime
date
4yum packagesyum update -y
yum install -y httpd httpd-tools mod_ssl
yum install amazon-linux-extras -y
yum clean metadata
yum install -y php php-common php-pear
amazon-linux-extras enable php7.4
yum install -y php php-common php-pear (we do it again)
yum clean metadata
yum install -y php-cli php-pdo php-fpm php-json php-mysqlnd
yum install -y php-{cgi,curl,mbstring,gd,mysqlnd,gettext,json,xml,fpm,intl,zip}
echo "<?php phpinfo(); ?>" > /var/www/html/phpinfo.php
php -v

5Fix /etc/my.cnf
You should not need to provide the PATH to the mysql socket.
vi /etc/my.cnf

[mysqld]
symbolic-links=0
ignore-db-dir=.rocksdb
key_buffer_size = 220M
innodb_buffer_pool_size=1M
local-infile=0 (if you get errors it could be something in these lines you could remove from the file.)

Note: if you have socket issues, you can add these lines in the [mysqld] section, but it should be okay.
datadir = /var/lib/mysql/
socket = /var/lib/mysql/mysql.sock
6Verify sendmail subsystem is not installed or workingsystemctl stop sendmail
systemctl disable sendmail
7yum packagesyum install -y gd ImageMagick ImageMagick-devel mariadb-server memcached mod_ssl php-devel gcc libzip-devel zlib-devel httpd-devel kernel-devel gcc gcc-c++

pecl install zip
pecl channel-update pecl.php.net
pecl install imagick (Just press ENTER key when prompted for [autodetect])

yum install -y php-memcached php-opcache php-apcu



8Apache settingusermod -a -G apache ec2-user

(exit the shell and log back in as sudo su)

chown -R ec2-user:apache /var/www
chmod 2775 /var/www && find /var/www -type d -exec sudo chmod 2775 {} \;
find /var/www -type f -exec sudo chmod 0664 {} \;

9Test the basic webpage is workingsystemctl start httpd
systemctl enable httpd


http://mydomain.com (your own domain name)

systemctl stop httpd. (let's only start HTTPD when we need to use it until such time as we have https:// SSL installed.
We do need it for using phpMyAdmin interface of course.

10Configure mysqlsystemctl start mariadb
mysql_secure_installation
NOTES:
This will have no root password to begin, so we press ENTER, and on the line requesting a root password we say y for yes, and this is the password we keep forever as the database root user - not the WordPress administrator, but it could be the same later if you wish.
After you create the root user password, record it somewhere safe, and we use that password later to create a hash code for phpMyAdmin (see further below).
After creating the root password, we enter y for yes to all the other prompts.

# at the end of msql installation, do these commands manualy:
systemctl stop mariadb --> this will stop the process that was used for the secure installation above
systemctl enable mariadb --> we will need to do the same for httpd, memcached, php-fpm later on.
systemctl start mariadb --> this will start mysqld properly, after the secure installation setups above
11Apache configurationscd /etc/httpd/conf.modules.d
vi 00-mpm.conf

ADD these lines to the end for performance:

<IfModule mpm_prefork_module>
StartServers 2
MinSpareServers 2
MaxSpareServers 5
MaxRequestWorkers 125
ServerLimit 125
MaxConnectionsPerChild 0
</IfModule>

NOTES: make sure the line "LoadModule mpm_prefork_module modules/mod_mpm_prefork.so" is uncommented as we do not want to run httpd/2 on the smaller EC2 instance. And, therefore make sure the last line is commented:
# LoadModule mpm_event_module modules/mod_mpm_event.so

vi 00-proxy.conf
# comment out the line "LoadModule lbmethod_heartbeat_module modules/mod_lbmethod_heartbeat.so" as it causes continual error log errors

CONFIGURE httpd.conf:

cd /etc/httpd/conf
vi httpd.conf

AFTER Listen 80 add these lines for performance: ( note: we do not add a Timeout option)

KeepAlive On
MaxKeepAliveRequests 50
KeepAliveTimeout 5

CONFIGURE - In the lines after Directory "/var/www/html", change AllowOverride ... to AllowOverride All
This allows WordPress permalinks to work.

CONFIGURE - Just below these lines, change the <IfModule dir_module> section's "DirectoryIndex index.html" to DirectoryIndex index.php index.html

OPTIONAL - If you intend to use IP2Location to block countries, append to the file these lines:

<IfModule mod_ip2location.c>
IP2LocationEnable On
IP2LocationDetectProxy On
IP2LocationSetmode ALL
IP2LocationDBFile /home/ec2-user/ip2location/IP2LOCATION-LITE-DB1.BIN
</IfModule>

(See separate notes on installing IP2location)

12memcachedcd /etc/sysconfig
vi memcached

MODIFY the last line to read: (again, these are general configurations from various Internet forums)

OPTIONS="-l 127.0.0.1 -U 0,::1"
13Configure /etc/php.inicd /etc
vi php.ini

max_execution_time = 300
max_input_time = 300
memory_limit = 256M
max_input_vars = 2500.

NOTE: It is unusual for max_input_vars to go higher but your WP theme statistics will show if you are running out of memory needed to display all your menus. Really large megamenus and number of navigation menus use this value.)

NOTE: some larger sites need more memory if WordPress keeps refusing to save a page from the editor. You could then try another 128 Megabytes, but note, the php-fpm package needs to be edited as well, and the /var/www/html/wp-config.php file. You can check the values in https://mydomain.com/phpinfo.php (or http). And note that when you are finished with phpinfo.php rename it so the world does not see it, e.g. mv phpinfo.php phpinfo.php.o

post_max_size = 100M
upload_max_filesize = 100M

NOTE: You can have any value for post_max and upload_max but I like large values. You cannot upload files larger than these values.

FOR MEMCACHED ADD THESE LINES: (comment out the session.save_handler = files entry)

session.save_handler = memcached
session.save_path = "127.0.0.1:11211"

NOTE: you will need to update other entries as well. https://mydomain.com/phpinfo.php will show if memcached is running or if it is still using "files".

Do not worry about memcached WP plugins. Keep things simple.

APPEND to php.ini for opcache:

output_buffering = 8192

14Configure phpcd /etc/php.d
vi 10-opcache.ini

CHECK THAT at the top portion of the file we have opcache.enable=1 and opcache.memory_consumption=128
MODIFY to have opcache.interned_strings_buffer=16 instead of the default 8

vi 40-apcu.ini

CHECK that at the top portion of the file you should see apc.enabled=1
MODIFY a bit further down and uncomment to have 64 as the value instead of 32: apc.shm_size=64M

APPEND THESE LINES: (do not have duplicate lines in the file it it will fail to start.)

apc.shm_segments = 1
apc.optimization = 0
apc.num_files_hint = 4096
apc.ttl = 7200
apc.user_ttl = 7200
apc.gc_ttl = 0
apc.cache_by_default = 1
apc.filters = ""
apc.slam_defense = 0
apc.file_update_protection = 2
apc.enable_cli = 0
apc.max_file_size = 10M
apc.stat = 1
apc.write_lock = 1
apc.report_autofilter = 0
apc.include_once_override = 0
apc.localcache = 0
apc.localcache.size = 512
apc.coredump_unmap = 0
apc.stat_ctime = 0

15Configure php-fpmcd /etc/php-fpm.d
cp -p www.conf www.conf.o
vi www.conf

CHANGE pm = dynamic to read, pm = ondemand. (we don't have a large enough system to use dynamic)
VERIFY these lines are uncommented:
pm.max_children = 50
pm.max_spare_servers = 35
pm.process_idle_timeout = 10s; (yes, it has the semicolon)
pm.max_requests = 500

NOTE: We want WordPress to use 256 MB so change the line php_admin_value[memory_limit] = 128M to read php_admin_value[memory_limit] = 256M

NOTE: Some larger sites may have issues saving a post or a page if very large, so you can bump this value up, eg to 384M if that ever arises - I only have one site with 384M
Various forums say to edit wp-config..php or /etc/php.ini but with php-fpm installed, we edit this particular file. We can check with https://mydomain.com/phpinfo.php

CONFIGURE this file for memcached and ensure the line "; php_value[session.save_handler] = files" is commented out with the semicolon as the comment character, and add these lines:

php_value[session.save_handler] = memcached
php_value[session.save_path] = 127.0.0.1:11211

NOTE: you can use systemctl to restart php-fpm and httpd to then check phpinfo.php shows the changes. If it is not there, you may need to configure /etc/httpd/conf.d/php.conf as well. phpinfo.php will also show the enablment of apcu and opcache.
If having issues, edit php.conf with these lines:

php_value session.save_handler "memcached"
php_value session.save_path "127.0.0.1:11211"
16SSL CONFIGURATIONS
I use a Positive SSL certificate from comodosslstore.com.
Their "cPanel" lets you manage the certificates.
Installing SSL is a topic in itself, but the Linux files need those certificates, and /etc/httpd/conf.d/ssl.conf needs particular setups.
cd /etc/httpd/conf.d
cp -p ssl.conf ssl.conf.bak
vi ssl.conf
# Add these lines, where DOMAIN is your domain name. The SSL certificates will be in the format of DOMAIN_com_au, for example, laurenceshaw_net.key and laurenceshaw_net.crt.

# At the top of the file, add these lines:
<VirtualHost *:80>
ServerName DOMAIN
Redirect permanent / https://DOMAIN/
</VirtualHost>

# uncomment and add the ServerName line:

ServerName DOMAIN:443

# For example:
# ServerName laurenceshaw.net:443

# Comment out some existing SSL lines and uncomment or add new ones, so that you end up with the following exactly:
# Note: no lines to accidentally have carriage returns or line breaks in them:

SSLEngine on

# SSLProtocol all -SSLv3
SSLProtocol -SSLv2 -SSLv3 -TLSv1 -TLSv1.1 +TLSv1.2
SSLProxyProtocol -SSLv2 -SSLv3 -TLSv1 -TLSv1.1 +TLSv1.2

# SSLCipherSuite HIGH:MEDIUM:!aNULL:!MD5:!SEED:!IDEA

SSLCipherSuite ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-

SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256

#SSLCipherSuite RC4-SHA:AES128-SHA:HIGH:MEDIUM:!aNULL:!MD5
SSLHonorCipherOrder on

SSLCertificateFile /etc/pki/tls/certs/DOMAIN_com_au.crt
SSLCertificateKeyFile /etc/pki/tls/private/DOMAIN_com_au.key



I also add these lines:

SSLCompression off
SSLInsecureRenegotiation Off
SSLSessionTickets Off
SSLOpenSSLConfCmd ECDHParameters secp384r1
SSLOpenSSLConfCmd Curves secp384r1

You can verify SSL starts when you do systemctl restart httpd and check for an A rating with sslabs.com

Until ready to install WordPress or to use SSL you can move ssl.conf to ssl.conf.o

17phpMyAdminIt is interesting that the Cento8 Litespeed configurations do not need this file, as https://mydomain.com/phpMyAdmin/index.php will work fine.
Here we add the phpMyAdmin.conf file to Linux2 and restrict access to your Static IP address for security reasons.

STATIC_IP is your own ip address. If it is dynamic you have to edit this file every time you want to use phpMyAdmin, and the same with the Security Group inbound rules in the EC2 instance. (!!) Good to have a static IP.

cd /etc/httpd/conf.d
vi phpMyAdmin.conf

Alias /phpMyAdmin /usr/share/phpMyAdmin
Alias /phpmyadmin /usr/share/phpMyAdmin

<Directory /usr/share/phpMyAdmin/>
AddDefaultCharset UTF-8

<IfModule mod_authz_core.c>
# Apache 2.4
<RequireAny>
Require ip STATIC_IP
Require ip ::1
</RequireAny>
</IfModule>
<IfModule !mod_authz_core.c>
# Apache 2.2
Order Deny,Allow
Deny from All
Allow from STATIC_IP
Allow from ::1
</IfModule>
</Directory>

<Directory /usr/share/phpMyAdmin/setup/>
<IfModule mod_authz_core.c>
# Apache 2.4
<RequireAny>
Require ip STATIC_IP
Require ip ::1
<</RequireAny>
</IfModule>
<IfModule !mod_authz_core.c>
# Apache 2.2
Order Deny,Allow
Deny from All
Allow from STATIC_IP
Allow from ::1
</IfModule>
</Directory>

<Directory /usr/share/phpMyAdmin/libraries/>
Order Deny,Allow
Deny from All
Allow from None
</Directory>

<Directory /usr/share/phpMyAdmin/setup/lib/>
Order Deny,Allow
Deny from All
Allow from None
</Directory>

<Directory /usr/share/phpMyAdmin/setup/frames/>
Order Deny,Allow
Deny from All
Allow from None
</Directory>
18Install phpMyAdmincd /usr/share
wget https://www.phpmyadmin.net/downloads/phpMyAdmin-latest-all-languages.tar.gz
ls

NOTE: cut and paste the filename, e.g. FILENAME: (for example, phpMyAdmin-latest-all-languages.tar.gz)

tar xvf FILENAME
rm FILENAME
ls

NOTE: now move the expanded file, perhaps FILENAME_VERSION to be phpMyAdmin

mv FILENAME_VERSION phpMyAdmin (for example, mv phpMyAdmin-5.1.0-all-languages phpMyAdmin)
cd phpMyAdmin
mkdir tmp
chmod 777 tmp
cp -p config.sample.inc.php config.inc.php
vi config.inc.php

NOTE: We need to create a "blowfish" entry as part of phpMyAdmin cookies, e.g., in the config.inc.php we will end up with something like this:
$cfg['blowfish_secret'] = 'YOUR_KEY';

NOTE: there are various key generators. For example:
https://phpsolved.com/phpmyadmin-blowfish-secret-generator/

Now login with your database root user and password from https://mydomain.com/phpMyAdmin
You will see an error at the bottom of the page, so fix that to create a database.
You should not see the TMP dir error. If you do, you can edit config.inc.php and add after SaveDir as follows:

$cfg['SaveDir'] = '';
$cfg['TEMPDir'] = '/tmp';

19A convenient file to restart services and some other scripts:First, check you have all your services enabled:

systemctl enable httpd
systemctl enable mariadb
systemctl enable memcached
systemctl enable php-fpm



cd /home/ec2-user

vi restart.sh
ADD THESE LINES:

#!/bin/sh
sudo /usr/bin/systemctl stop httpd
sudo /usr/bin/systemctl stop mariadb
sudo /usr/bin/systemctl stop php-fpm
sudo /usr/bin/systemctl stop memcached
sudo /usr/bin/systemctl start memcached
sudo /usr/bin/systemctl start php-fpm
sudo /usr/bin/systemctl start mariadb
sudo /usr/bin/systemctl start httpd
exit

Then fix the permissions:

chmod 2775 restart.sh

Then test it:

sh -x ./restart.sh


This is a handy file to reboot your system:
vi reboot.sh
ADD THESE LINES:

#!/bin/sh
/usr/bin/sync
/usr/bin/sync
sudo /usr/bin/systemctl stop httpd
sudo /usr/bin/systemctl stop mariadb
sudo /usr/bin/systemctl stop php-fpm
sudo /usr/bin/systemctl stop memcached
/usr/bin/sync
/usr/bin/sync
shutdown -r +1 "Server is rebooting for scheduled maintenance in 1 minutes. Please save your work now."
exit


This is a useful script to ensure your wordpress files under /var/www/html have the correct permissions:

vi chdir.sh
ADD THESE LINES:

#!/bin/sh
cd /var/www/hmtl
chown -R apache *
chgrp -R apache *
find . -type d -exec chmod 2775 {} \;
find . -type f -exec chmod 0664 {} \;
if [ -f "./.htaccess" ] ; then
chown apache .htaccess
chgrp apache .htaccess
chmod 664 .htaccess
fi
chmod 777 *.sh
chown root chdir.sh
chgrp root chdir.sh
chmod 770 chdir.sh
exit





20Configure Postfix emailJust make sure sendmail is not running:
systemctl stop sendmail, and systemctl disable sendmail
ps -ef|grep sendmail

postfix should be installed. If not, use yum install postfix.

After the testing (see below), I disable postfix for security and only use it with shell scripts to send me messages about the system.
If you are not doing this, no need to configure:
systemctl stop postfix
systemctl disable postfix

Use your Amazon region:

postconf -e "relayhost = [email-smtp.us-west-2.amazonaws.com]:587" \
"smtp_sasl_auth_enable = yes" \
"smtp_sasl_security_options = noanonymous" \
"smtp_sasl_password_maps = hash:/etc/postfix/sasl_passwd" \
"smtp_use_tls = yes" \
"smtp_tls_security_level = encrypt" \
"smtp_tls_note_starttls_offer = yes"


In /etc/postfix/master.cf check the line (if it exists) is commented out: -o smtp_fallback_relay=

cd /etc/postfix
vi sasl_passwd

# insert this one line: (using the keys - these keys will be usedin the SMTP plugin in WordPress and wp-config.php)
[email-smtp.us-west-2.amazonaws.com]:587 SMTPUSERNAME:SMTPPASSWORD

These values would have previously been set up in AWS SES where you verify your domain name and deal with email setups.
These values are needed for WordPress to send emails from your contact form as well.

postmap hash:/etc/postfix/sasl_passwd
chmod 0600 /etc/postfix/sasl_passwd /etc/postfix/sasl_passwd.db
postfix start; sudo postfix reload; postfix flush
mailq

We will test postfix and then stop the service.
Use your own email as already verified in SES emails. It can be anything:

sendmail -f admin@mydomain.com admin@mydomain.com
From: ADMIN
Subject: Postfix Test
This is a test message from AWS Postfix and SES
.
<-- we press the ENTER key after the fullstop. If we create any shell scripts using postfix, we add a blank line after the fullstop.


21crontabIf you want to reboot the system once a week:

crontab -e

0 1 * * 1 /home/ec2-user/reboot.sh >/dev/null 2>&1
5 1 * * 1 /home/ec2-user/restart.sh
0 0 * * * /home/ec2-user/restart.sh

(SHIFT ZZ will save the file if your default is vi editor)

Then you can check contents with crontab -l