How to setup the perfect LAMP stack on Ubuntu 14.04 LTS

Ok, ladies and gentlemen!

I needed local development server closer as possible to the production one. I downloaded and Installed Ubuntu, but didn’t know how to get Apache, MySQL and PHP installed. After a few hours of reading random blogs found on Google and head banging I succeed.

My requirements was:

  1. Set up multiple subdomains automatically (i.e. Virtual Document Root)
  2. Password protect all my subdomains when they are accessed outside my home network but access them directly, without need to provide password, when I am connected to my local network and develop.
  3. To separate the error logs by virtual host (subdomain).

Below is a laundry list of commands to help you configure your own perfect Ubuntu server, too.

LAMP Installation

First things first: update and upgrade your Ubuntu.

$ sudo apt-get update && sudo apt-get upgrade

Install LAMP Stack (Apache, Mysql, PHP) in one command:

$ sudo apt-get install lamp-server^

Now, if you try to open http://localhost you will see a greeting. “It works!” actually.
So far, so good. We can continue with the next step – configuring our automagically mapped subdomains.

Virtual Hosts

There is in my work fancy development server, on which every single project checkout is mapped to a subdomain of the developed web site. For example, we are developing and this is the address of the main production site. But, if you try to open, for example, the HTTP request is forwarded to our local development server which try to find project directory with the same name (john) and serves content from it. This way, you only need one domain name for all your projects (or all your colleague’s checkouts) in dev environment, and still have the benefit of having each project reside on a separate (sub)domain, which simplifies the use of mod rewrite. That was actually the first time I have ever seen such as tricky and useful server setup.

Apache2 has the concept of sites, which are separate configuration files that Apache2 will read. These are available in /etc/apache2/sites-available. By default, there is one site available called 000-default. This is what you will see when you browse to http://localhost or You can have many different site configurations available, and activate only those that you need.

We’ll simply edit the default one.

First, be good boy and play self – do backup!

$ sudo cp /etc/apache2/sites-available/000-default.conf /etc/apache2/sites-available/000-default.conf.bak

Than open the config with Gedit using root privileges:

$ gksu gedit /etc/apache2/sites-available/000-default.conf

Replace the entire file’s content with that provided bellow and save changes.

# =====================================
#    V I R T U A L   D O C   R O O T
# =====================================

<virtualhost *:80>
ServerAlias *
ServerName localhost
UseCanonicalName Off
VirtualDocumentRoot "/var/www/%1/htdocs"
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined

<Directory "/var/www/">
AllowOverride All

Order deny,allow
Deny from all

AuthName "Restricted Development Server"
AuthUserFile /etc/apache2/passwords/.htpasswd
AuthType Basic
Require valid-user
Deny From All
Allow From 192.168.1.

Satisfy Any

As you might have already noticed, the config defines basic HTTP authentication and apache will look for a .htpasswd file containing one or more user/password pair. In order to work, you should generate this .htpasswd in /etc/apache2/passwords (this directory doesn’t exist, you should create it). Of course, you can place the file anywhere on the file system.
How to generate a .htpasswd is quite well described here so I will skip my explanation.

Ok, we now have perfect configuration file and .htpasswd setup. Now it’s time to  restart the apache2 server using the following command and make the changes above available.

$ sudo /etc/init.d/apache2 restart

The next step is to setup an A record for all your subdomains. It’s quete easy – just login at your cPanel or domain management panel and add an “A” – record with name *  and your development server IP as record’s value. Now, (,, etc) will point to your dev serevr IP.

Try to open Ha! An error! Why? Simply, there is no such as folder in /var/www. Create new directory /var/www/john/htdocs and place new index.php file on it.

$ sudo mkdir -p /var/www/john/htdocs
$ cd /var/www/john/htdocs
$ sudo touch index.php && echo "Hello, World!" > index.php

Try to open again. You should see a classic greeting message in your browser. Ta-da-da! You just finished the setup!

Separate the error logs by virtual host 

Apache generates an error and access log, each of which contains messages from all virtual hosts (subdomains). If you want to debug specific subdomain, you have to use grep to filter the global error.log and extract only the error messages which refer to your subdomain. It sounds as a lot of working. And definitely could be better if you just have separate error log for every single virtual host (subdomain).

It can be done with simple log-splitting php script.
Copy – paste following script and save it as /usr/local/sbin/logsplitter.php


define('LOG_DIR', '/var/log/apache2');

    $line = fgets(STDIN);
	if (preg_match('/\/var\/www\/([a-zA-Z0-9\-]+)\/?/', $line, $match)) {
		file_put_contents(LOG_DIR . '/' . $match[1] . '_errors.log', $line, FILE_APPEND);
	} else {
		file_put_contents(LOG_DIR . '/general_errors.log', $line, FILE_APPEND);

The script should have execute permissions for the correct owners in order to be runnable. So, run the following command:

$ sudo chmod +x /usr/local/sbin/logsplitter.php

The last part is to pipe Apache log in order to be processed by the logsplitter.php script.
Use the pipe character “|“, followed by the path to our script file which receive the log information on its standard input.
So, basically, you have to open the Apache site config again

$ gksu gedit /etc/apache2/sites-available/000-default.conf

… and change the following directive:

ErrorLog "| /usr/local/sbin/logsplitter.php"

Now, just restart the Apache service again and you are ready.
Voila! All your error logs will be separated and saved under different names, based on the folder name (respectively – subdomain name).