Running Laravel on shared hosting subdomain

Running Laravel 5 on a shared host subdomain (I use Vidahost) is a little daunting because Laravel requires the web root to point to the /public folder and generally with a subdomain the website root is the root folder that is created for you.

My solution was to create a directory in the subdomain root folder and copy all the code into there. I then copied the contents of the /public folder into the subdomain root folder and edited index.php.

The two require lines need modifying to remove the ‘..’ characters and replace with the actual path.

//require __DIR__.'/../bootstrap/autoload.php';
require __DIR__.'/mysubdirectory/bootstrap/autoload.php';

It’s not pretty but it worked OK.

The little application I wrote is to help with non-verbal reasoning tests, to memorise the numeric equivalents of the alphabet: Alphabet to Numbers.

Folder structure for running Laravel from site root folder
Folder structure for running Laravel from site root folder

Magento SQL query for customer with billing and shipping address

Here is an SQL query I construct to extract customers with billing and shipping address from a Magento 1.9 store.
This joins on table sales_flat_order_address to ensure that only customers that have ordered are included.

You may need to adjust the entity attribute id’s – if you look in those tables it is pretty obvious what each value represents.

SELECT
    ce.entity_id AS customer_id,
    ce.email,
    cev2.value AS firstname,
    cev3.value AS lastname,
    caet.value AS billing_first_line,
    caev1.value AS billing_town,
    caev2.value AS billing_postcode,
    sfoa.entity_id AS sfoa_entity_id,
    sfoa.street AS shipping_first_line,
    sfoa.city AS shipping_city,
    sfoa.postcode AS shipping_postcode
FROM
    customer_entity ce
    -- first name
    INNER JOIN
    customer_entity_varchar cev2 ON (ce.entity_id = cev2.entity_id
        AND cev2.attribute_id = 5)
    -- last name
    INNER JOIN
    customer_entity_varchar cev3 ON (ce.entity_id = cev3.entity_id
        AND cev3.attribute_id = 7)
    -- address first line
    INNER JOIN
    customer_address_entity cae ON (ce.entity_id = cae.parent_id)
    INNER JOIN
    customer_address_entity_text caet ON (cae.entity_id = caet.entity_id)
    -- town
    INNER JOIN
    customer_address_entity_varchar caev1 ON (cae.entity_id = caev1.entity_id
    AND caev1.attribute_id = 26)
    -- postcode
    INNER JOIN
    customer_address_entity_varchar caev2 ON (cae.entity_id = caev2.entity_id
    AND caev2.attribute_id = 30)
    -- sales
    INNER JOIN
    sales_flat_order sfo ON (ce.entity_id = sfo.customer_id)
    -- shipping address
    INNER JOIN
    sales_flat_order_address sfoa ON (sfo.entity_id = sfoa.parent_id)
    WHERE sfo.status = 'complete'

Vagrant notes

Stop box checking for updates

If you want to stop your VM from checking for updates to the Vagrant box add the following immediately after the Vagrant.configure line:

# don't check for VM updates
config.vm.box_check_update = false

Update Guest Additions

There is a plugin: vagrant-vbguest which will check if your VirtualBox Guest Additions are out of date in your VM and automatically update if necessary. You can install it with:

vagrant plugin install vagrant-vbguest

Once the Guest Additions have been installed you may want to use the following to prevent further updates (add just after the Vagrant.configure line):

# don't update guest additions
config.vbguest.auto_update = false

Better synced folder permissions

Instead of the default synced folder settings which may cause problems when your server tries to change the files (e.g. WordPress updating itself) I use the following with Ubuntu:

config.vm.synced_folder "./", "/vagrant", id: "vagrant-root",
owner: "vagrant",
group: "www-data",
mount_options: ["dmode=775,fmode=664"]

If you are using CentOS then the group should be apache instead of www-data.

Magento performance

You can boost Magento performance (or any complicated PHP app) when running from a VM by changing the PHP OPcache revalidate frequency. It defaults to 2 seconds which means when you are navigating a site all the PHP files are recompiled with every click. With tens of thousands of PHP files that’s a hefty penalty.

Changing this to something like 20 seconds means you’ll be using cached code. Do this with:

sudo nano /etc/php5/apache2/php.ini

and set

opcache_revalidate_freq = 20

Times Tables

My times tables site is now back online at times-tables.willis-owen.co.uk. Rote learning is no longer fashionable but it still remains an effective tool to get kids to memorise times tables instead of trying to work out the sum in their heads each time.

Although this site is simple, it gives competitive kids a sense of achievement and there is nothing to distract them from the task at hand.

For parents there is no marketing / advertising and no agenda.

Times Tables screenshot

Technical Details

It has been updated to use the superb PHP Fat-Free Framework v3.5 which is now installable using Composer.

Why would MySQL crash when WordPress attacked?

WordPress brute force attacks are increasingly common at the time I write this – September 2014. Recently a server I look after was coming under attack and then after a few minutes the site would display ‘Error establishing a Database Connection’. error-establishing-database-connectionWhen I logged into the server the MySQL service wasn’t running.

My first thoughts were that something in the attack was causing MySQL to crash, There was no information in the MySQL error.log to indicate why though so I spent time looking at plugins to help mitigate a brute force attacks, which tend to focus on the WordPress wp-login.php and xmlrpc.php files:

Disable XML-RPC will disable WordPress XML-RPC functionality meaning that nothing can be done to your content, however this does nothing to prevent initial database queries so MySQL can still be affected when running this, and it does nothing about wp-login.php either.

BruteProtect – I’ve seen comments that it will protect xmlrpc but I’ve seen it in action during an attack and as of version 2.2.2 it did nothing to stop it.

NinjaFirewall – there are a lot of configuration options but this one does the job. It sits in front of WordPress and so it can intercept the attack before all the database activity starts up. This worked great when I used it during an attack.

However you may host multiple WordPress sites on a single server and it could be tedious having to install this and configure it for each site, plus there is going to be duplication of what the code is doing and Apache still has to handle all the incoming requests.

It may be better to stop any attacks at the firewall because that’s the single point of entry to your server. This approach still requires a plugin – WP fail2ban but this one will log attacks to your systems auth.log which can be picked up by fail2ban and automatically added for a temporary period to your firewall rules. It is more complicated than the other plugins to install but once a malicious IP has been blocked it can’t affect any of the sites on your server will keep the system load much lower.

After getting the fail2ban solution in place the database was brought down yet again. I ended up looking in kern.log and at the time of the attack was the line ‘apache2 invoked oom-killer’ – that revealed the problem… Apache was using so many processes that it was running out of memory and as this particular server runs off an SSD the swap file is disabled. As there was nowhere else to get memory from it started killing off other processes, the biggest of these was MySQL.

What a relief to find the cause – MySQL wasn’t crashing at all. The solution was just to reduce the MaxClients value in apache2.conf – the default value of 150 is way too big for a modest sized server. If each process takes 40 MB then 150 processes require 6 GB of RAM. Getting a realistic value for this requires a little load testing plus the use of some tools to see how the memory usage increases as Apache has to handle more requests.