Posted on

Nginx and Letsencrypt SSL on Debian

It is a good idea to get PHP and MariaDB on Debian set up before Nginx (except the PhpMyAdmin which can come after).

Related Artices in Debian Services and Applications - Debian on AWS Lightsail - OpenVPN on Debian + UFW Firewall - Nginx and Letsencrypt on Debian - PHP & MariaDB on Debian

- Grav CMS on Debian

Install Nginx

Edit the /etc/apt/sources.list to add the Nginx repostitory

nano /etc/apt/sources.list

Add the following repository (currently for Debian 9/Stretch)

deb http://nginx.org/packages/mainline/debian/ stretch nginx

Download and install the key for the repository

wget https://nginx.org/keys/nginx_signing.key
sudo apt-key add nginx_signing.key

Remove nginx-common, update apt and install nginx

sudo apt-get remove -y nginx-common
sudo apt-get update -y
sudo apt-get install -y nginx

Systemd / Nginx Race Condition

There is a known race condition, with a workaround as follows:

mkdir /etc/systemd/system/nginx.service.d
printf "[Service]\nExecStartPost=/bin/sleep 0.1\n" > /etc/systemd/system/nginx.service.d/override.conf
systemctl daemon-reload

Edit /etc/nginx/sites-available/default

Note: these edits are not comprehensive, just to get certbot working. Uncomment the following lines:

listen 443 ssl default_server;
listen [::]:443 ssl default_server;
...
location / {
...
try_files $uri $uri/ =404;
}

Where it says server_name _; change _ to an appropriate fqdn that has an appropriate A record. Save and restart the nginx:

service nginx restart

Letsencrypt Certbot

sudo apt-get update
sudo apt-get install -y python-certbot-nginx certbot -t stretch-backports

Run letsencrypt (automatic)

certbot

Test access from a browser.

HSTS Preload

Browsers have a list of servers that require https/ssl. Add sites to the list. Two things are required: 80 to 443 redirect, and an hsts header. For the redirect, add this server configuration:

server {
        listen 80 default_server;
        listen [::]:80 default_server;
        server_name _;
        return 301 https://$host$request_uri;
}

For the HSTS header, this needs to be added to each server. Can simply be added after the listen 443 ssl; line:

add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;

Nginx Info

Nginx has become the standard for much of the web, for the basic standard reason it is not creaky old (though of course still lovable) Apache. However, before we get too far ahead of ourselves, let's recall exactly what we need to know about Nginx in order for it to work as well as Apache: - Installation - Configuration files - Support of SSL / LetsEncrypt - SFTP/SCP access to file system (and file rights + ownership) - Multiple virtual servers / directories - Mimetypes - Support for PHP - Threading - .htaccess and related

Nginx and Related Files and Directories

Standard or default files and directories as follows: - /etc/nginx - application directory - /etc/nginx/nginx.conf - main configuration file - /usr/share/nginx/html - default website root directory - noted as html in nginx.conf - /var/log/nginx/error.log - error log - /var/log/nginx/access.log - access log - /etc/nginx/mime.types - mime types - /etc/php.ini - php configuration file

Nginx / PHP-FPM Security Issues

There are significant issues with PHP-FPM in terms of keeping site caching partitioned when using multiple websites/virtual sites. Opcache should be turned off and individual users should be in charge of a different php-fpm process for each site. How to do this is not listed here (just yet).

Posted on

Amazon Canada Incompetence

By Amazon Canada, I am referring to the Amazon Advantage Canada operation. Pure, unadulterated incompetence. Support requests go something like this: - Me: Here is my problem, with detail - AC: Request for information (which is already in the detail) - Me: Submission of requested info, again - AC: Thank you, please wait - AC: We are working on this, thank you for your patience - AC: We are working on this, thank you for your patience - AC: It is fixed now, please try again - Me: No, it is still broken - AC: Thank you, please wait - AC: We are working on this, thank you for your patience - AC: We are working on this, thank you for your patience - AC: It is fixed now, please try again - Me: No, it is still broken - AC: We tried to call you, please provide a time to discuss this isse - Me: No, we don't need to talk, please fix the problem - AC: Thank you, please wait - AC: We are working on this, thank you for your patience - AC: We are working on this, thank you for your patience - AC: It is fixed now, please try again - Me: No, it is still broken - AC: Please send screenshots with dates (obviously they don't believe me) - Me: Submission of requested info, again - AC: We tried to call you, please provide a time to discuss this isse - Me: No, we don't need to talk, please fix the problem - AC: Thank you, please wait Repeat with various slight modifications. This has happened to me twice now, with different issues, and it is completely maddening. First, they cannot update an item in inventory. After three months of this nonsense, I just removed/discontinued the item. The second time, most recently, they can't update my bank information and my account is locked and I can't update it myself. This has been the situation now for over a month. Well, bye bye Amazon Canada, incompetence par excellence.

Posted on

Kindle Paperwhite 4th Gen

I've used a Kindle since the Kindle Keyboard (3rd gen), and since then purchased and used the DX for a while (the much larger model). On 06 September 2012 the Kindle Paperwhite was released and I registered mine on 10 September. I broke that model within six months by wedging it in a bag that had too many objects in it, but Amazon sent out a replacement free-of-charge (which included free shipping, and I live outside the United States). Well folks, the first generation Paperwhite has served me well, and I did not feel a need for an upgrade, at the prices that were available for fancy versions like the Voyage and Oasis, or non-Kindle devices such as what Kobo offers. However, at this point, on the eve of the release of the fourth generation of the paperwhite, that has changed, and I intend to upgrade.

Specifications of First and Fourth Generation Paperwhite

Generation Dimensions Weight Lighting Screen Storage Bluetooth Audible Waterproof
First Gen 117 x 169 x 9.1 mm 213 grams 4 led 212 ppi 2gb no no
Fourth Gen 116 x 167 x 8.2 mm 182 grams 5 led 300 ppi 8/32gb yes IPX8

Reasons to Upgrade

At 12% smaller (mainly due to thinness) and 15% lighter, less is more, and this is a significant motivator to upgrade. Storage is not an issue for me, and 8gb will be fine. The increased quality of the lighting 5 vs. 4 led) and screen resolution (300ppi vs. 212ppi) are nice, but not essential. Bluetooth audible is ok. I don't use audible now but might later. I certainly would not upgrade for that feature. The waterproof quality, combined with dimensions/weight and screen, is what puts this over the edge in terms of a desire to upgrade.

Open Source, Open Content

While I do use a Kindle, most of my content I have in PDF and Epub formats. PDF is not very readable on the Kindle and I rarely do it. However, Epubs are easy to convert using Calibre, an open source, cross platform library and ebook management tool. The DeDRM toolkit is very useful for stripping out the nasty DRM that comes with Kindle ebooks. I prefer unlocked files as my main library repository. Also, many ebooks are available at a variety of locations including Library Genesis, a resource of unparalleled breadth and depth. I prefer to use the Kindle device due to its quality hardware, and ease of access of their ebook offerings (I do regularly purchase content from Amazon). The DRM they use I simply work-around/ignore. In the past I've rooted both the Kindle Keyboard (3rd Gen), Kindle DX, and Kindle Paperwhite, though my current version is using stock Kindle software on the device. I'm not irrevocably mated to Kindle and Amazon, but it is my current preferred platform.

Posted on

Debian on AWS Lightsail

This is a setup of several items, starting with Debian 9 on Amazon AWS Lightsail. This has server basics and apt, and then follows with links to additional articles. In general, after several years of running CentOS on Linode, and then Amazon Linux AMI on EC2 and Lightsail, I find that Debian 9 is simply faster, just as secure, and at least slightly easier to use.

While there are many flavors of linux, clearly two particular lineages predominate: RHEL/CentOS/AMI and Debian/Ubuntu/Mint. Either are just as valid, though of course niche requirements may make one or the other more attractive. Android and ChromeOS are even more popular, but we are dealing with server OS here. For me, Debian on the desktop via LMDE3 (Linux Mint Debian Edition) is currently a favorite.

AWS Lightsail is a decently priced VPS package. Equivalents can be found in various first and second tier cloud providers such as Digital Ocean, Vultr, Linode, and perhaps even Azure and Google Cloud, who knows? Anyone with any experience with AWS can leverage this with Lightsail, though the main web interface is a bit different.


Related Artices in Debian Services and Applications - Debian on AWS Lightsail - OpenVPN on Debian + UFW Firewall - Nginx and Letsencrypt on Debian - PHP & MariaDB on Debian

- Grav CMS on Debian

Choose Debian Distribution

On Lightsail as of late 2018 Debian 9.5 is an option. - Install PHP from special repository sources (found in the Running PHP on Debian article) - Install special packages from Backports when needed (such as certbot) - Use apt install PACKAGE -y -t stretch-backports

Example:

sudo apt install -y python-certbot-nginx -t stretch-backports

Packages available from Distributions

Update Debian

sudo apt update -y
sudo apt update -y -t stretch-backports

Upgrade Debian

Do some checks and then execute upgrade and dist-upgrade: Note: accept the locally modified files for upgrading when asked.

sudo apt upgrade -y
sudo apt upgrade -y -t stretch-backports

Note: can have system service restarts be done automatically, when asked.

Upgrade Debian Distribution

This will change from one release to the next if there is a next one for the version being run (e.g., stable).

sudo apt dist-upgrade -y

Next, run the command to reload the terminal session:

hash -r

Steps in Configuration

Server Basics Steps

  • Configure servername, ip addresses
  • Apt, Configure repositories, Update, Upgrade, Clean, etc.

Servername, IP Addresses

For private IP Addresses

ip addr show eth0 | grep inet | awk '{ print $2; }' | sed 's/\/.*$//'

For a public IP address (esp. Amazon AWS Elastic IP)

curl -4 icanhazip.com

Apt Sources List

ls -la /etc/apt

and see what is in subdirectories

Installed packages

dpkg-query -l

apt-get commands

Note, this is largely obsolete with the apt command set -- need to UPDATE this section below

apt-get clean
apt-get autoclean
apt-get dist-upgrade
apt-get clean
apt-get check
apt-get autoremove
  • autoclean deletes .deb files from local cache
  • clean deletes .deb files from distribution installation
  • autoremove removes previous, but no longer needed dependencies
  • dist-upgrade deals with dependencies, not just applications, and will add/remove/upgrade them
  • apt-get check will check for dependencies missing

note: difference between apt-get remove xyz vs. apt-get purge xyz, as the first preserves configuration files (for possible later use)

Completely Remove Packages

sudo apt-get --purge remove package-name
Posted on

Amazon Linux First Steps

First steps after logging into an Amazon Linux box:

Set up the Name Services (DNS, Hostname) Properly

Note there are several places this needs to be set.

nano /etc/sysconfig/network-scripts/ifcfg-eth0

Make this look as follows:

DEVICE=eth0
BOOTPROTO=dhcp
ONBOOT=yes
TYPE=Ethernet
USERCTL=yes
PEERDNS=no
DNS1=84.200.69.80
DNS2=84.200.70.40
DHCPV6C=yes
DHCPV6C_OPTIONS=-nw
PERSISTENT_DHCLIENT=yes
RES_OPTIONS="timeout:2 attempts:5"
DHCP_ARP_CHECK=no

Note that this fixes the general VPC settings issue especially for Lightsail. Next, configure /etc/resolv.conf

nano /etc/resolv.conf

Use this file:

options timeout:2 attempts:5
; configured an override of dhcp-settings in
; /etc/sysconfig/network-scripts/ifcfg-eth0
nameserver 84.200.69.80
nameserver 84.200.70.40

Uninstall Amazon Crap

Get rid of the Amazon SSM Agent and HIB Agent

sudo yum erase amazon-ssm-agent –y
sudo yum erase hibagent -y

Uninstall other Stuff

sudo yum erase portreserve -y

Configure NTP

Time services as follows

sudo yum -y install ntp
sudo service ntpd start
sudo chkconfig ntpd on

Note that to run manually, it is important to turn off the service, as follows:

sudo service ntpd stop
sudo ntpd -gq
sudo service ntpd start

Install and Configure Chrontabs

yum -y install crontabs
chkconfig crond on
service crond start
service crond status

More detail on setting up chron jobs

Configure Sendmail

Sendmail is installed (and running) by default. This should be configured to limit its attack surface.

Install some Utilities

yum -y install htop
yum install -y psmisc
yum install -y iotop
yum install -y mlocate
yum install -y lsof
yum -y install ncdu
yum install -y s3cmd
Posted on

AWS DHCP Options and Resolv.conf

AWS DHCP options are set on a per-VPC (Virtual Private Cloud) basis. By default, things like the search scope and DNS servers used by a given AWS Instance are set by DHCP which also provides the private IP address (but not any Elastic IP Addresses). Indeed, the Amazon Virtual Private Cloud is a fundamental core service that makes AWS very useful when managing complex and distinct instances and networks. VPCs include addressing, subnets, security, routing, and offer things like VPNs-as-a-service.

Setting AWS DHCP Options

Go to the VPC console in AWS. Note that DHCP Options cannot be edited, they can only be created, assigned, and deleted. Create a new one without the search scope and with preferred DNS servers. Then Assign to given instances. After assigning them, any DHCP Options that are not assigned to any VPC can be deleted.

Amazon Lightsail and VPCs

There seems to be no evidence that Amazon Lightsail offers any kind of VPC ifrastructure that can be managed (including DHCP Options) and likely each Lightsail instance is its own VPC with default DHCP settings (that cannot be set as above). In which case: Edit the file /etc/sysconfig/network-scripts/ifcfg-eth0 or otherwise appropriate configuration files for a network interface.

nano /etc/sysconfig/network-scripts/ifcfg-eth0

Change contents as such:

PEERDNS=no
DNS1=8.8.8.8
DNS2=1.2.3.4

Change DNS entries to the desired.

Additional Resources and Implications, including a variety of DNS solutions

Posted on

cron and crontabs on Amazon Linux AMI

Two words time-based automation: cron and crontabs (and other apps such as anacron) are needed for so many things on a server. Here is how to use cron and crontabs on Amazon Linux AMI.

Install crontabs

This will in addition install several dependencies, including cron.

yum -y install crontabs
chkconfig crond on
service crond start
service crond status

Edit the crontabs

Remember to do this with su or root, otherwise there might be access issues with the actual items to run. vi is the default editor, but I like nano better, so:

export VISUAL=nano; crontab -e

Crontab syntax

Essentially there are numbers or asterisks for when things are run. From left to right: - Minute (0-59) - Hour of day (0-23) - Day of month (1-31) - Month (1-12) - Day of week (0-6, 0 = Sunday) An asterisk counts for every possible value, which means: > * * * * * = every minute > 0 1 * * * = 01:00 every day > 0 18 * * 0 = Every Sunday at 18:00 (6pm)

Crontab execution

Crontab executes from home directory of the user. It is best to use full paths for the location of scripts and the like

Example MySQL watchdog script

Crontab entry:

* * * * * /usr/local/bin/rsmy >> /var/log/mysqld.log

Script entry:

#!/bin/bash
UP=$(/etc/init.d/mysqld status | grep running | grep -v not | wc -l);
if [ "$UP" -ne 1 ];
then
    echo "$(date) - MySQL is down - restarting now";
    /sbin/service mysqld start
else
    echo "$(date) - MySQL is running";
    /usr/bin/free -m
fi

References

Posted on

WordPress Multisite on Amazon Linux

This assumes a current configuration of: - Amazon Linux (6.x RHEL series) - Apache 2.4 - PHP 5.6 + Opcache - Oracle MySQL 5.7 Installation up to this point is encompassed by: - OpenVPN on Amazon Linux EC2, basic configuration and securing an EC2 instance - Amazon Linux, Apache, MySQL, and PHP, installing and configuring

Install WordPress from Subversion

This is the standard quick install. It is advised to do the most recent stable version, and not the main branch, which can break (more) things. First, install subversion:

yum -y install svn

For Debian:

apt-get install -y subversion

Visit Installing WordPress with Subversion, and look for a command line that looks like the following.

svn co https://core.svn.wordpress.org/tags/5.0.2 .

The final number will change over time. Currently the options for GIT are a bit malnourished.

Create Database and User

Log into mysql

sudo mysql -u root -p

Create database

CREATE DATABASE database DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci;

Create user and grant access to the database (change username and password as appropriate).

CREATE USER 'user'@'localhost' IDENTIFIED BY 'password';
GRANT ALL on database.* to 'user'@'localhost';
flush privileges;
exit;

Create wp-config.php

First, copy the sample file into a config file

cp /var/www/html/wp-config-sample.php /var/www/html/wp-config.php

Next edit the four parts of the file:

nano /var/www/classic/wp-config.php

Change these: - Database Name - User Name - Password - Table prefix Also add the following at the end

/** to set update method, rather than changing file access */
define('FS_METHOD','direct');

Save and restart /index.php

Multisite

WordPress Multisite has advantages (and some disadvantages). The process to change a single site into multisite has several steps. - Disable all plugins - edit wp-config.php to include the following

sudo nano /var/www/html/wp-config.php

Add the following:

/* Multisite */
define( 'WP_ALLOW_MULTISITE', true );

Note that this will then allow you to take the next steps. - Administration > Tools > Network Setup - Configure for subdomains - Once completed, copy the text for .htaccess into httpd.conf (usually this redirection is safe for single site domains as well.

RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
# add a trailing slash to /wp-admin
RewriteRule ^wp-admin$ wp-admin/ [R=301,L]
RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^ - [L]
RewriteRule ^(wp-(content|admin|includes).*) $1 [L]
RewriteRule ^(.*\.php)$ $1 [L]
RewriteRule . index.php [L]
  • Comment out the above item entered into wp-config.php, and instead replace with:
define('MULTISITE', true);
define('SUBDOMAIN_INSTALL', true);
define('DOMAIN_CURRENT_SITE', 'host.domain.com');
define('PATH_CURRENT_SITE', '/');
define('SITE_ID_CURRENT_SITE', 1);
define('BLOG_ID_CURRENT_SITE', 1);
define( 'SUNRISE', 'on' );

Note: It is very important to place this where it indicates, just before stop editing below - copy the sunrise.php file to /wp-content/. - restart Apache - Install and enable WordPress MU Domain Mapping - change the settings in > Network Admin > Settings > Domain Mapping to 2,5 (the opposite of the default) - Add domains to the mapping as desired - Set redirections and site defaults to their desired domain name

Reset Filesystem Security Script

Filesystem security can get wonky especially with WordPress plugin and theme updates and manual file copying and editing. There are two things to do: - Make a script that backs up essential configuration files - Make a script that resets all the security in the file paths This is an example of the second:

chown -R username:apache /var/www
find /var/www/html -type d -exec chmod 2775 {} \;
find /var/www/html -type d -exec chmod g+s {} \;
find /var/www/html -type f -exec chmod 0664 {} \;
chown username:username /var/www/html/.b*
chmod 700 /var/www/html/.b*
chown username:username /var/www/html/.profile
chown username:username /var/www/html/.ssh
chmod 1700 /var/www/html/.ssh
chmod 600 /var/www/html/.ssh/authorized_keys
echo ' ';
echo '***************************************************';
echo 'changed ownership and security on wordpress install';
echo '***************************************************';
echo ' ';

PHP Session Handling

WordPress does not use PHP Sessions, and plugins need not, therefore: - Eradicate plugins which use @session_start(); which includes (as per latest scan): - wp-affiliate-platform, - wp-spamshield, - woocommerce-amazon-s3-storage, and - php-compatibility-checker (which is only needed for testing, in any case)

cd /var/www/html
grep -r 'session_start'

Caching Configuration in WordPress

W3 Total Cache

General Settings - Page Cache, Disk: Enhanced - Minify (disabled) - Database Cache, Disk - Object Cache (disabled) - Browser Cache (disabled, we do this manually in httpd.conf) - CDN (disabled) - Use single network configuration file - Purge Policy: Posts page, Post page Page Cache - Cache posts, SSL, Don't cache logged in - Prime page cache, 900, 10 - Preload post cache upon publish - Sitemaps regular expression [a-z0-9_\-]*sitemaps\/[a-z0-9_\-]*\.(xml|xsl|html?)(\.gz)? - Rejected Cookies:

wptouch_switch_toggle
ap_id
cart_in_use
eMember_in_use
  • Never Cache the Following Pages
wp-.*\.php
index\.php
[a-z0-9_\-]*sitemap[a-z0-9_\-]*\.(xml|xsl|html?)(\.gz)?
favorites\.php
cart
checkout
shop
/shop*
  • Note: must include any changes to permalinks and the pages above Database Cache
  • Don't cache for logged in
  • Ignore Query Stems
gdsr_
wp_rg_
_wp_session_
_wc_session_

Autoptimize

  • Optimize HTML, Keep HTML Comments
  • Optimize Javascript, aggregate inline JS
  • Optimize CSS, Remove Google Fonts
  • Save aggregated as static files = uncheck

Further Security and Performance Optimization

Exotic Performance Tuning

Testing Tools

Code Cleanup

A good part of speed issues is the actual site code (php/js/css/html) and when it comes to WordPress, especially WordPress plugins, there are a lot of potential conflicts. Blocking JS and CSS is a big part of the problem, as well as removing all the default crap that is not needed (such as various webfonts). - Clean up nonblocking Javascript and CSS - Too many CSS files and embedded CSS in HTML, and too many JS files - Google's Accelerated Mobile Pages - Cache-aware websites

Posted on

Amazon Linux (CentOS), Apache, MySQL, PHP

Note: Amazon Linux AMI is essentially CentOS 6.x. Everything below works on CentOS as well.

Preparation for Amazon LAMP

The OpenVPN on Amazon Linux AMI is a good place to start in preping the L for the AMP part of the lamp stack. Lots of good stuff there. A followup is WordPress Multisite on Amazon Linux AMI.

The Order of Things with Amazon Linux AMI

Amazon Linux AMI is a bit picky about the order of things. Otherwise there will be dependency conflicts, which is a rife problem. Also, make sure to disable (at least temporarily) other repositories, otherwise there can be even more dependency conflicts. Here is a handy script to ensure that an upgrade (or fresh install) will go well, starting with Apache httpd, php, and ssl:

service httpd stop
yum -y erase httpd httpd-tools apr apr-util
yum -y remove php*
yum -y install php56
yum -y install php56-xml php56-xmlrpc php56-soap php56-gd php56-mbstring
yum -y install php56-cli php56-common php56-pdo
yum -y install php56-mysqlnd
yum -y install php56-opcache
yum -y install mod24_ssl
sed -i -e 's/SSLMutex/Mutex/g' /etc/httpd/conf.d/ssl.conf
service httpd start
service httpd restart

Source: Gist Note that this is PHP 5.6, not the vaunted 7.x version. Version 5.6 is (as of July, 2017) the most popular PHP version, and (in a recent study) is installed on 22.4% of all servers whose server-side programming languages are known, compared with 5.4% of all 7.x versions.

Enable httpd Service and Check if Enabled

Enable httpd as a service to startup

chkconfig httpd on

Check the configuration status of httpd

chkconfig --list httpd

Set User and Group Rights

This is especially useful when using sftp.

usermod -a -G apache USERNAME
chown -R USERNAME:apache /var/www
chmod 2775 /var/www
find /var/www -type d -exec chmod 2775 {} \;
find /var/www -type f -exec chmod 0664 {} \;

Create and Test PHP Info Page

echo "" > /var/www/html/phpinfo.php

Note that there are at least three command-line ways of figuring out things such as which php.ini file am I using: - php --ini, - php -i | grep "Configuration File", and - apachectl -S

Copy opcache.php OpCache Status Page

cd /root/temp
wget https://raw.githubusercontent.com/rlerdorf/opcache-status/master/opcache.php
mv opcache.php /var/www/html/opcache.php

Test at:

https://host.server.tld/opcache.php

Apache Configuration

Spend time on the following files (shortcut scripts are shown after filename): - nano /etc/httpd/conf/httpd.conf - eap - nano /etc/httpd/conf.d/ssl.conf - essl - nano /etc/httpd/conf.modules.d/00-mpm.conf - empm - sudo nano /etc/httpd/conf.modules.d/00-base.conf - ebase

/etc/httpd/conf/httpd.conf Modifications

## Modifications at Top of File ##
RewriteEngine On
ServerTokens Prod
ServerSignature Off
TraceEnable off
Header edit Set-Cookie ^(.*)$ $1;HttpOnly;Secure
Header always append X-Frame-Options DENY
Header set X-XSS-Protection "1; mode=block"
Header unset ETag
Header set Cache-Control "max-age=604800, must-revalidate"
FileETag None
BrowserMatch ^Mozilla/4 gzip-only-text/html
BrowserMatch ^Mozilla/4\.0[678] no-gzip
BrowserMatch \bMSIE !no-gzip !gzip-only-text/html
Header append Vary User-Agent
RewriteCond %{REQUEST_METHOD} ^(TRACE|DELETE|TRACK) [NC]
RewriteRule ^.* - [F]
HostnameLookups Off
RequestHeader unset Proxy early
ServerTokens ProductOnly
## End Modifications ##
...
## Modifications inside directory ##
# Strip all subdomains not including status.
# NOTE: Disable this while subdomains help get to sites
#RewriteCond %{HTTP_HOST} !^status\.(.*)\.(.*) [NC]
#RewriteCond %{HTTP_HOST} ^(.*)\.(.*)\.(.*) [NC]
#RewriteRule ^(.*) https://%2.%3/$1 [R=301,L]
# Require SSL (site-wide)
RewriteCond %{HTTPS} !=on
RewriteRule ^/?(.*) https://%{HTTP_HOST}/$1 [R=301,L]
# Redirect Alias Domains (after SSL rewrite)
RewriteCond %{HTTP_HOST} ^domain.tld$ [NC]
RewriteRule ^(.*)$ https://domain2.tld2/$1 [R=301,L]
# WordPress
RewriteBase /
RewriteRule ^index\.php$ - [L]
# Obfuscate the /admin/ and wp-login.php stuff
RewriteRule ^(/)?SoMeWeIrDsHiT/?$ /wp-login.php [QSA,L]
RewriteRule ^(/)?wp-register-php/?$ /wplogin?action=register [QSA,L]
# Add a trailing slash to /wp-admin
RewriteRule ^wp-admin$ wp-admin/ [R=301,L]
# More WordPress Multisite
RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^ - [L]
RewriteRule ^(wp-(content|admin|includes).*) $1 [L]
RewriteRule ^(.*\.php)$ $1 [L]
RewriteRule . index.php [L]
## End Modifications ##
...
## Modification after files section ##
# Disable XML-RPC


        Require all denied


        Order allow,deny
        Deny from all


## End Modifications ##
...
## Modification inside mime_module ##
AddType text/plain .txt
AddType text/html .html
AddType text/xml .xml
AddType text/css .css
AddType application/x-javascript .js
AddType image/x-icon .ico
AddOutputFilterByType DEFLATE text/plain
AddOutputFilterByType DEFLATE text/html
AddOutputFilterByType DEFLATE text/xml
AddOutputFilterByType DEFLATE text/css
AddOutputFilterByType DEFLATE application/x-javascript
AddOutputFilterByType DEFLATE image/x-icon
## End Modification ##
...
## Modification at End of File ##
#ErrorDocument 500 "The server made a boo boo."
#ErrorDocument 404 /missing.html

  StartServers            2
  MinSpareServers         4
  MaxSpareServers         8
  MaxClients             64
  MaxRequestsPerChild  2560

## End Modification ##

MPM Prefork rule of thumb is ram/15 for max clients, but test that out. The above is for a server with 1gb ram, though with a database on the same server, may need to throttle this back. From another server (with Apache installed), test with Apache Bench (ab), for example:

ab -n 2000 -c 200 https://host.domain.tld:443/info.php

/etc/httpd/conf.d/ssl.conf Modifications

## Modifications at Top ##
SSLStrictSNIVHostCheck  off
SSLUseStapling                   on
SSLStaplingResponderTimeout  5
SSLStaplingReturnResponderErrors off
SSLStaplingCache                 shmcb:/run/ocsp(128000)
## End of Modifications ##
...
## VirtualHost Modifications ##
SSLCipherSuite         ALL:+HIGH:+TLSv1:!ADH:!EXP:!SSLv2:!MEDIUM:!LOW:!NULL:!aNULL
SSLCompression off
Header always set Strict-Transport-Security "max-age=63072000; includeSubdomains; preload"
SSLVerifyClient none
## End of Modifications ##

Install apachetop for Amazon Linux

Because Amazon Linux AMI is still basically a CentOS 6.x base, and most repositories have a CentOS 7.x version of apachetop, it is important to download and install locally as follows:

mkdir /root/temp
cd /root/temp
wget http://dl.fedoraproject.org/pub/epel/6/i386//apachetop-0.15.6-1.el6.i686.rpm
yum -y localinstall apachetop-0.15.6-1.el6.i686.rpm

OpCache Configuration

First, comment out the opcache from /etc/php.ini

nano /etc/php.ini

As follows:

;declared in opcache.ini
;zend_extension = opcache.so

Next, configure the opcache.ini file:

nano /etc/php-5.6.d/10-opcache.ini

Configure as follows:

zend_extension=opcache.so
opcache.enable=1
opcache.enable_cli=1
opcache.memory_consumption=128
;128 is for 1gb ram
opcache.interned_strings_buffer=16
opcache.max_accelerated_files=6400
;opcache.max_wasted_percentage=5
opcache.use_cwd=1
opcache.validate_timestamps=0
opcache.revalidate_freq=60
;opcache.revalidate_path=0
;opcache.save_comments=1
;opcache.load_comments=1
opcache.fast_shutdown=1
;opcache.enable_file_override=0
;opcache.optimization_level=0xffffffff
;opcache.inherited_hack=1
;opcache.dups_fix=0
opcache.blacklist_filename=/etc/php-5.6.d/opcache*.blacklist
;opcache.max_file_size=0
;opcache.consistency_checks=0
;opcache.force_restart_timeout=180
;opcache.error_log=
;opcache.log_verbosity_level=1
;opcache.preferred_memory_model=
;opcache.protect_memory=0

PHP.INI Configuration

[PHP]
;already declared in opcache.ini
;zend_extension = opcache.so
engine = On
;for piwik
always_populate_raw_post_data=-1
short_open_tag = Off
asp_tags = Off
precision = 14
output_buffering = 4096
zlib.output_compression = Off
implicit_flush = Off
;unserialize_callback_func =
serialize_precision = 17
;open_basedir =
;disable_functions =
;disable_classes =
zend.enable_gc = On
;zend.multibyte = Off
;zend.script_encoding =
expose_php = Off
max_execution_time = 30
max_input_time = 60
memory_limit = 256M
error_reporting = E_ALL & ~E_DEPRECATED & ~E_STRICT
display_errors = Off
display_startup_errors = Off
log_errors = On
log_errors_max_len = 1024
ignore_repeated_errors = Off
ignore_repeated_source = Off
report_memleaks = On
track_errors = Off
html_errors = On
variables_order = "GPCS"
request_order = "GP"
register_argc_argv = Off
auto_globals_jit = On
post_max_size = 8M
;auto_prepend_file =
;auto_append_file =
default_mimetype = "text/html"
;default_charset = "UTF-8"
;doc_root =
;user_dir =
enable_dl = Off
file_uploads = On
upload_max_filesize = 20M
max_file_uploads = 20
allow_url_fopen = On
allow_url_include = Off
default_socket_timeout = 60
;;;;;;;;;;;;;;;;;;;
; Module Settings ;
;;;;;;;;;;;;;;;;;;;
[CLI Server]
cli_server.color = On
[Date]
date.timezone = Asia/Tokyo
[Pdo_mysql]
pdo_mysql.cache_size = 2000
pdo_mysql.default_socket=
[mail function]
smtp_port = 25
; For Unix only. You may supply arguments as well (default: "sendmail -t -i").
; http://php.net/sendmail-path
; sendmail_path = "/usr/sbin/sendmail -t -i"
; Force the addition of the specified parameters to be passed as extra parameters
; to the sendmail binary. These parameters will always replace the value of
; the 5th parameter to mail(), even in safe mode.
;mail.force_extra_parameters =
; Add X-PHP-Originating-Script: that will include uid of the script followed by the filname
mail.add_x_header = On
; The path to a log file that will log all mail() calls. Log entries include
; the full path of the script, line number, To address and headers.
;mail.log =
[SQL]
sql.safe_mode = Off
[ODBC]
odbc.allow_persistent = On
odbc.check_persistent = On
odbc.max_persistent = -1
odbc.max_links = -1
odbc.defaultlrl = 4096
odbc.defaultbinmode = 1
[Interbase]
ibase.allow_persistent = 1
ibase.max_persistent = -1
ibase.max_links = -1
ibase.timestampformat = "%Y-%m-%d %H:%M:%S"
ibase.dateformat = "%Y-%m-%d"
ibase.timeformat = "%H:%M:%S"
[MySQL]
mysql.allow_local_infile = On
mysql.allow_persistent = On
mysql.cache_size = 2000
mysql.max_persistent = -1
mysql.max_links = -1
mysql.default_port =
mysql.default_socket =
mysql.default_host =
mysql.default_user =
mysql.default_password =
mysql.connect_timeout = 60
mysql.trace_mode = Off
[MySQLi]
mysqli.max_persistent = -1
mysqli.allow_persistent = On
mysqli.max_links = -1
mysqli.cache_size = 2000
mysqli.default_port = 3306
mysqli.default_socket =
mysqli.default_host =
mysqli.default_user =
mysqli.default_pw =
mysqli.reconnect = Off
[mysqlnd]
mysqlnd.collect_statistics = On
mysqlnd.collect_memory_statistics = Off
[PostgreSQL]
pgsql.allow_persistent = On
pgsql.auto_reset_persistent = Off
pgsql.max_persistent = -1
pgsql.max_links = -1
pgsql.ignore_notice = 0
pgsql.log_notice = 0
[Sybase-CT]
sybct.allow_persistent = On
sybct.max_persistent = -1
sybct.max_links = -1
sybct.min_server_severity = 10
sybct.min_client_severity = 10
[bcmath]
bcmath.scale = 0
[Session]
session.save_handler = files
session.save_path = "/var/lib/php/session"
session.use_cookies = 1
session.use_only_cookies = 1
session.name = PHPSESSID
session.auto_start = 0
session.cookie_lifetime = 0
session.cookie_path = /
session.cookie_domain =
session.cookie_httponly =
session.serialize_handler = php
session.gc_probability = 1
session.gc_divisor = 1000
session.gc_maxlifetime = 1440
session.bug_compat_42 = Off
session.bug_compat_warn = Off
session.referer_check =
session.cache_limiter = nocache
session.cache_expire = 180
session.use_trans_sid = 0
session.hash_function = 0
session.hash_bits_per_character = 5
url_rewriter.tags = "a=href,area=href,frame=src,input=src,form=fakeentry"
[MSSQL]
mssql.allow_persistent = On
mssql.max_persistent = -1
mssql.max_links = -1
mssql.min_error_severity = 10
mssql.min_message_severity = 10
mssql.compatability_mode = Off
mssql.secure_connection = Off
tidy.clean_output = Off
soap.wsdl_cache_enabled=1
soap.wsdl_cache_dir="/tmp"
soap.wsdl_cache_ttl=86400
soap.wsdl_cache_limit = 5
ldap.max_links = -1

Install LetsEncrypt SSL Certs

If OpenSSL is installed and the default settings are in httpd.conf and ssl.conf, then LetsEncrypt should work in a straightforward way. Do add the various virtual server and virtual aliases in both files, and for the ./letsencrypt-auto command, include all hosts adding on -d host.domain.tld one after the other. Also, for Amazon Linux AMI have to include the --debug flag.

yum -y install git
git clone https://github.com/letsencrypt/letsencrypt /opt/letsencrypt
cd /opt/letsencrypt
./letsencrypt-auto --debug --apache -d host.domain.com

Note: Use the staging environment for testing before doing a live run. It can save you an hour's wait, if there are things to work out.

Get the Certs into the HSTS Preload List

PHP Configuration

php.ini - stuff - more stuff ... MORE ...

MySQL 5.6 vs. MySQL 5.7

As of mid-July, 2017 there are two main options for MySQL: version 5.6 or version 5.7. MySQL 5.6 is available from the AMI repository, but 5.7 only from Oracle's community repository. Many people have complained about this, as they well should. MariaDB 10.x is a competitor, but without much adoption. The speed and functionality improvements of 5.7 make it the desired distribution release. The issue with the community repository is that it is unclear which distribution to use on Amazon Linux AMI. The standard redhat and fedora distributions don't work because they assume systemd (e.g., RHEL/CentOS 7.x). Some sources suggest using the generic linux distribution. Another option is the RHEL/CentOS 6.x build. Both seem viable, as long as 7.x repositories and distributions are disabled.

RDS with MySQL and Aurora

Besides installing and configuring a database on an EC2 or Lightsail instance (same thing), there are other Amazon database server options. The Amazon Relaltional Database Service (RDS), supports multiple engines including: - RDS for MySQL - RDS for Aurora Note that along with these there are other options such as nosql, redis, etc., and also various caching options.

For a basic MySQL installation (not on RDS, a separate database server), installing via a yum repository makes a shortcut.

MySQL 5.7 on Amazon Linux AMI standard installation

Install some new dependencies, if not present:

yum -y install libaio
yum -y install numactl

Download the repository (see latest version numbers here):

wget http://dev.mysql.com/get/mysql57-community-release-el6-11.noarch.rpm
yum -y localinstall mysql57-community-release-el6-11.noarch.rpm

Check to see if repo is installed, which ones are installed, and which available:

yum repolist | grep mysql

Read more about installing and enabling these MySQL repositories. Run the installation command, which will also install various common, libs, client, and server packages.

yum -y install mysql-community-server

Start the service

service mysqld start

Grep the error log which will have the generated password

grep 'temporary password' /var/log/mysqld.log

Login with that password

mysql –u root –p

Type in the password Then, change password

ALTER USER 'root'@'localhost' IDENTIFIED BY 'NewPassword';

Check to see if the password is hashed in the database, and also the version of MySQL installed.

select user,host,authentication_string from mysql.user;
select @@version,@@basedir,@@datadir;

Exit out of mysqld

exit

Set mysqld to start on boot, and see if it is set correctly:

chkconfig mysqld on
chkconfig --list mysqld

PhpMyAdmin on Amazon Linux

Install PhpMyAdmin from the Amazon EPEL Repository:

yum -y install phpmyadmin

Edit the file /etc/httpd/conf.d/phpMyAdmin.conf and replace 127.0.0.1 with the ip address of the client.

nano /etc/httpd/conf.d/phpMyAdmin.conf

Restart the web server and database server (to be safe)

service httpd restart
service mysqld restart

Test to see if it works

https://host.domain.tld/phpmyadmin/
Posted on

Amazon Lightsail

Amazon Lightsail is a VPS services offered by Amazon that competes with the likes of Rackspace, DigitalOcean, Linode, etc. Note: As of mid 2018 AWS effectively halved its prices on Lightsail. This means there is a $2.50 USD/mo. option and the $40 option listed below (4gb ram/2 cpu/60gb ssd/4tb xfer) is actually only $20 now. Compared head-to-head the Lightsail option is a middle-of-the-road offering. However, compared with AWS and including the highly optimized nature of running Amazon Linux AMI (and not overselling with bullshit numbers like some providers), Amazon Lightsail is an extremely attractive VPS. S3 snapshot backups and other aspects of high reliability make this a go-to package for the VPS market.

Lightsail Specifications

See the Amazon Lightsail FAQs - Up to 3 DNS zones - Up to 5 ip addresses (elastic IPs) - Available in about half of AWS zones The various sizes of Lightsail are (as of July 2017): - $5/mo. - 512mb ram, 1 core, 20gb ssd, 1tb transfer - $10/mo. - 1gb ram, 1 core, 30gb ssd, 2tb transfer - $20/mo. - 2gb ram, 1 core, 40gb ssd, 3tb transfer - $40/mo. - 4gb ram, 2 core, 60gb ssd, 4tb transfer - $80/mo. - 8gb ram, 2 core, 80gb ssd, 5tb transfer Note that transfer allowances are half of the above, for Mumbai and Sydney currently.

Lightsail vs. EC2 Pricing

The real genius in Lightsail is the pricing. Compared with a 1 year reserved T2.Nano instance, a $5 Lightsail would be as follows: - T2.Nano reserved $3.36/mo - 1gb data xfer, subsequent at $0.09/gb/mo. (1tb = $89.91) - 1 elastic ip vs. 5 elastic ips (instances can only use 1 in ec2) - $0.11gb/mo of provisioned ebs (disk) = $2.22/mo in value - DNS = 3 zones included vs. $0.50/mo/zone for Route53 Total value of $8.13-$98.04 in value (depending mainly on data transfer). However, if you had only a single zone, a single IP, 8gb of disk (smallest available), and under 1gb of data transfer, then the value is $4.74/mo., which is within 5% of the cost of a $5/mo. Lightsail. That said, it is not clear how the vcpu works under Lightsail vs. EC2. However, since this is a single infrastructure, likely the performance is similar, and AWS is just going after a different segment of the market (one that is price-conscious).

Lightsail Docs and CLI

Lightsail has docs and a cli.

Lightsail Tasks

  • Create zone(s)
  • Create and download SSH Cert
  • Log in from command prompt with
    • ssh -i /path/to/.ssh/key.pem ec2-user@server.domain.tld
  • Operate under root rights with sudo su

Lightsail Control Panel

Lightsail is not integrated into the rest of AWS, though it is possible to see some aspects of it (perhaps storage?) from the console. Definitely it is managed separately from EC2 and Route53. This lack of integration is a bit of a pain, but likely it will go away (slowly and partially) over time (perhaps).

Securing Lightsail

Depending upon one's security requirements, it might be useful to create a new user and disable or remove rights to the ec2-user account. The steps to create a user with the same rights as ec2-user are: - create the account useradd username - set a password for the account passwd username - add the account to the sudo group usermod -aG wheel username - log in with the account su - username - create a .ssh directory mkdir .ssh - set security on the directory chmod 700 .ssh - log out of username exit - now back in root, copy the authorized_keys file to username

cp /home/ec2-user/.ssh/authorized_keys /home/username/.ssh/authorized_keys

Log all the way out of the system, and try and log in with the username, and same public key. Once logged in invoke sudo su to ensure it has the correct rights. There should be an error message. The last step is to replace ec2-user with username in the file: /etc/sudoers.d/cloud-init If this works, then you have a new account with the same priviledges as the ec2-user (and you have also removed ec2-user from the ability to become root) and can safely delete (or ignore) that account.

Lightsail Limitations

Lightsail has a few limitations, including no tools for transfer or resizing, though in late 2018 an ability to export snapshots to EC2 was added. In addition, Lightsail cannot port filter at the IP address, only at the port level. And for DNS management, CAA records are not supported (as opposed to Route 53 where they are).