A website is a mirror of his/her owner. If one’s website is too slow, maybe the owner does not care about pushing the limits in all his/her other endeavors.
The steps below outline the instructions how to set up the one of the fastest possible WordPress installations at the moment.
Disclaimers
- Neither AWS, nor RedHat does provide any support for these installation steps. If you require support, contact Jiri to discuss his availability.
- These instructions are a result of years of experience, extensive web research and countless conversations with various brilliant people. Their help is much appreciated.
- The packages discussed below are cutting-edge, and they are not yet part of RedHat Enterprise Linux (RHEL) or AWS Linux. If you prefer, you can download them already built from either Remi’s Repo or Webtatic provided you trust these repositories. For production environments, I strongly advise against that due to a chance of trojan horses etc. being included in the built versions.
Target Infrastructure
I build all my systems on AWS because I found their level of service unmatched by services of any other cloud provider.
I use RedHat Enterprise Linux because
- it’s well supported
- it’s a stabilized version of Fedora Linux and some time ahead of the default AWS Linux
- I can easily test the installation steps on a local dev machine with VMWare Workstation’s RHEL image with snapshots which I found to be the most effective ways of fine-tuning production systems
The below instructions should apply with minor modifications to other Linux versions.
Http/2
Http/2 is a performance boosting update to the 1999’s http 1.1 protocol used for all web traffic.
In a nutshell, it utilizes only a single multiplexed connection to the server (opening of a connection channel takes most of the web page loading time), it’s binary, it prioritizes the order of resources being delivered, and pushes to the client pro-actively the resources it may request in the future.
It’s already supported by majority of web browsers – at the time of writing this article in January 2017 it was 78%.
Thus, by your website not supporting the protocol, your audience spends unnecessarily more time on its loading, and in consequence being less satisfied.
OpenSSL, Apache, PHP Setup
0. Set Up RedHat
Enable RedHat Repositories:
sudo yum update -y sudo su cp /etc/yum.repos.d/redhat-rhui.repo /home/ec2-user vi /etc/yum.repos.d/redhat-rhui.repo
Change enabled=0 to enabled=1
Install the prerequisites:
yum install -y mc mlocate at wget links perl gcc yum groupinstall "Development Tools" -y yum install -y autoreconf automake autoconf pcre-devel openssl-devel git wget mlocate
1. Upgrade OpenSSL
cd /usr/local/src wget https://www.openssl.org/source/openssl-1.0.2-latest.tar.gz tar -zxvf openssl-1.0.2-latest.tar.gz cd openssl-1.0.2j ./config --prefix=/usr --openssldir=/usr/local/openssl shared make make test make install
2. Apache
# Install nghttp2 cd /usr/local/src git clone https://github.com/nghttp2/nghttp2 cd nghttp2 git submodule update --init autoreconf -i automake autoconf ./configure make make install # Install Apache cd /usr/local/src/ wget http://www-us.apache.org/dist//httpd/httpd-2.4.25.tar.gz tar -zxvf httpd-2.4.25.tar.gz cd httpd-2.4.25 cd srclib wget http://www-us.apache.org/dist//apr/apr-1.5.2.tar.gz tar xvf apr-1.5.2.tar.gz mv apr-1.5.2 apr wget http://www-us.apache.org/dist//apr/apr-util-1.5.4.tar.gz tar xvf apr-util-1.5.4.tar.gz mv apr-util-1.5.4 apr-util cd /usr/local/src/httpd-2.4.25 ./configure --prefix=/opt/httpd --enable-http2 --with-nghttp2=/usr/local/lib --enable-so make make install cp /opt/httpd/conf/httpd.conf /home/ec2-user vi /opt/httpd/conf/httpd.conf
Uncomment these lines
LoadModule http2_module modules/mod_http2.so LoadModule ssl_module modules/mod_ssl.so LoadModule rewrite_module modules/mod_rewrite.so LoadModule deflate_module modules/mod_deflate.so LoadModule socache_shmcb_module modules/mod_socache_shmcb.so Include conf/extra/httpd-ssl.conf
Add these lines
<IfModule http2_module> LogLevel http2:info </IfModule> Protocols http/1.1 h2 h2c H2MaxSessionStreams 10 H2MaxWorkerIdleSeconds 15 H2MaxWorkers 15 H2MinWorkers 5
Change Override None to Override All
Backup SSL settings
cp /opt/httpd/conf/extra/httpd-ssl.conf /home/ec2-user vi /opt/httpd/conf/extra/httpd-ssl.conf
Change these values for these parameters:
ServerName
ServerAdmin
Uncomment the parameter SSLCertificateChainFile
.
Upload the SSL certificates to the appropriate locations
SSLCertificateFile "/opt/httpd/conf/server.crt" SSLCertificateKeyFile "/opt/httpd/conf/server.key" SSLCertificateChainFile "/opt/httpd/conf/server-ca.crt"
Restore permissions
restorecon -RvF /opt/httpd/conf
Reboot, log back in and check all apache configs are fine
/opt/httpd/bin/apachectl configtest
Set up auto-start of Apache
touch /etc/init.d/apache2 chmod 755 /etc/init.d/apache2 vi /etc/init.d/apache2
Paste there this text:
#!/bin/bash # # apache2 Startup script for the Apache HTTP Server # # chkconfig: 3 85 15 # description: Apache is a World Wide Web server. It is used to serve \ # HTML files and CGI. /opt/httpd/bin/apachectl $@
Run
chkconfig --add apache2 chkconfig --list apache2
Set up permissions for www
sudo groupadd www sudo usermod -a -G www ec2-user sudo chown -R root:www /opt/httpd/htdocs sudo chmod 2777 -R /opt/httpd/htdocs
Reboot to see if the Apache was started automatically
3. PHP
sudo su yum install -y perl libxml2-devel curl-devel libpng-devel cd /usr/local/src wget http://php.net/get/php-7.1.0.tar.gz/from/this/mirror mv mirror php-7.1.0.tar.gz tar -zxvf php-7.1.0.tar.gz cd php-7.1.0 ./configure --enable-bcmath --enable-mbstring --with-gd --with-config-file-path=/etc --with-config-file-scan-dir=/etc/php.d --bindir=/usr/bin --sbindir=/usr/sbin --sysconfdir=/etc --includedir=/usr/include --prefix=/opt/php71 --with-apxs2=/opt/httpd/bin/apxs --with-mysqli=mysqlnd --with-pdo-mysql=mysqlnd --with-curl --with-zlib --enable-zip make make test make install vi /opt/httpd/conf/httpd.conf
Uncomment
LoadModule php7_module modules/libphp7.so
Add
<FilesMatch \.php$> SetHandler application/x-httpd-php </FilesMatch> <FilesMatch "\.phps$"> SetHandler application/x-httpd-php-source </FilesMatch>
Set up PHP’s settings
vi /etc/php.ini
Paste there this text
; Maximum amount of memory a script may consume (128MB) ; http://php.net/memory-limit memory_limit = 2048M ; Maximum allowed size for uploaded files. ; http://php.net/upload-max-filesize upload_max_filesize = 200M post_max_size = 200M log_errors=true error_log=/opt/httpd/logs/php-errors.log
Install ImageMagick
sudo yum install ImageMagick cp /etc/ImageMagick/policy.xml /home/ec2-user vi /etc/ImageMagick/policy.xml
Add there these policies, if they are not already present
<policy domain="coder" rights="none" pattern="EPHEMERAL" /> <policy domain="coder" rights="none" pattern="URL" /> <policy domain="coder" rights="none" pattern="HTTPS" /> <policy domain="coder" rights="none" pattern="MVG" /> <policy domain="coder" rights="none" pattern="MSL" /> <policy domain="coder" rights="none" pattern="TEXT" /> <policy domain="coder" rights="none" pattern="SHOW" /> <policy domain="coder" rights="none" pattern="WIN" /> <policy domain="coder" rights="none" pattern="PLT" />
Reboot and restore the original WordPress site from BackupBuddy.
4. Final Check
Go to https://tools.keycdn.com/http2-test and check your website does run on Http/2 with ALPN:
WordPress Setup
I highly recommend the below two WordPress plugins for enhanced WordPress performance.
In addition, I strongly recommend manual running of the WordPress’s Cron.
sudo crontab -e * * * * * /usr/bin/php /nas/content/live/jiripikcom/wp-cron.php >/dev/null 2>&1
1. WP-Offload
WP-Offload is a WordPress Plugin uploading all media (images, videos and others) into an AWS S3 bucket which is then mapped onto an AWS CloudFront distribution serving as a super-fast CDN.
Recommendation: Do enable Http/2 on the AWS CloudFront Distribution.
2. WP-Rocket
WP-Rocket is one of the best page caching / pre-loading plugins available.
It minifies CSS, JS files, offers lazy loading of images or video, and stores pre-generated html pages in a cache so that whenever the web server receives a page request, it can be served without the server having to build it from its MySQL representation.
And above all, it’s exceptionally well supported.