One of the biggest challenges when developing a web application is ensuring everything works correctly once it is deployed to the production environment. It sounds straightforward, but how many times have you developed an app locally, only to find out that once you deploy it the server is running PHP 5.2, and vital functions have been deprecated. Or possibly even more common, the php ini memory limit is lower, and suddenly pages are returning blank? Well I can tell you in my over 8 yrs of PHP experience, this is an extremely common occurrence and one that hopefully this blog post will help you avoid as much as possible.

Here at Zoop, our application, as with many applications these days, is deployed “in da cloud”, and more specifically, on EC2; part of the Amazon Web Services offering. To help us manage our deployment on EC2 more effectively we are also utilizing Rightscale, a cloud agnostic “Platform as a Service”, which is code for a “web based admin that hooks into many cloud hosting providers”. The great thing about this service is that it allows us to bring up a replication of our entire production environment, or a scaled down version, in just a few clicks, which has been amazing for our UAT and Staging phases. However, the problem of inconsistent environments between development and staging still remains, as it is still much more efficient to develop and test locally before pushing things up to Staging.

This set me on a mission to recreate a simplified version of the Zoop production environment locally. One that will allow us to develop and thoroughly test on a consistent stack from local, to staging and finally to production. The Zoop e-commerce application runs on a CentOS (linux) box using the Zend Server stack, hence I require the exact same stack running locally.

To make this as efficient and cost effective as possible, I decided that I would run this environment as a Virtual Machine (VM) on my Windows Home Server 2011 (Which is essentially Windows Server 2008 R2) and for the rest of the tutorial will be referenced as my “Host”. Having this on a centralized server, rather than on each developer's local machine (the “Client”), is for a number of practical reasons including maintenance, backups and cost, as we then only require one license of Zend Server (which isn't cheap for a startup). A VM also has the added benefit of running multiple instances on a single machine, cloning the whole environment and re-deploying elsewhere, which is why I chose a virtualized deployment over a physical one.

        

The aim of this tutorial is to show you how to achieve a consistent development stack and despite Zoop’s specific requirements, the same principles apply to any Operating System or Application stack that you may run.

Below is the Beginner version of the tutorial, however if you are familiar with Linux and VirtualBox I have written an Advanced version which is much more condensed.

Download:

The VM manager I’m going to use is VirtualBox by Oracle. There may be better ones out there but this is free and consistently updated.

  1. Download the latest version of VirtualBox https://www.virtualbox.org/wiki/Downloads . The version I’m using in this tutorial is 4.1.1.12
  2. Install, selecting all default settings.
  3. Download the VirtualBox Extension Pack and install

Download a Linux VM:

As I stated earlier, Zoop uses CentOS however you can use any OS you like. The instructions may differ slightly depending on Linux distro, and majorly depending on variety of OS eg. Windows etc.

  1. Download CentOS 5.6 (269.9 MB compressed): http://sourceforge.net/projects/virtualboximage/files/CentOS/5.6/Centos-x86_64.7z/download
  1. user: root
  2. password: reverse
  1. Unpack using Winrar or 7z
  2. Double click the .vbox file and it will appear in your VirtualBox Manager

Setting up the VM

  1. Select the VM and click settings:
  1. System:
  1. You can change the base memory if you need, however if it is only for a few clients you wont need more than 512MB.
  2. Unselect “floppy” and “cd/dvd-rom” from the boot order.
  1. Audio
  1. Uncheck “Enable Audio” as it’s unnecessary
  1. Network (this is the important part)
  1. Ensure the “Enable Network Adapter” is selected
  2. Attached to: NAT
  1. USB
  1. Uncheck “Enable USB controller
  1. Click ok
  2. Select the VM and click “Start
  3. Once the login appears enter the specific user login details for the VM you downloaded.
  1. The CentOS VM I provided a link to is

user: root
password:
reverse

  1. Your Linux VM is now up and running! Note: To release your mouse from the VirtualBox VM window you just hit your “Right-Ctrl” key.

Setting up SSH

The best way to manage your VM is through a SSH client like PuTTY. To get this up and running you need to set up port forwarding on your VM.

  1. Add a firewall rule to allow incoming traffic to the 2222 port. On my Windows Home Server it is located in: Control Panel > Windows Firewall > Advanced Settings. Note: you may not need to do this


  1. Find the IP address of your virtual server:
  1. Start and log into your VM (if you haven’t already)
  2. Type: ip a
  3. You will most likely have 2 items and the one you are interested in is “eth0” and in particular the number following the “inet”. In my case the IP is: 10.0.2.15


  1. Find the IP address of your host computer, which in my case is the Windows Home Server.
  1. Go Start > Run > Type “cmd” and click “Ok”
  2. Type “ipconfig
  3. You’re only interested in your main Ethernet adapter which in my case has an IPv4 Address of: 10.1.1.10.


  4. If you haven’t already, it’s actually a good idea to set a static IP address for your host computer. You can do this via Control Panel > Network and Sharing > Change adapter settings > right click “Properties” on your main “Local Area Connection” > Select “Properties” on “Internet Protocol Version 4” select “Use the following IP address”.


  1. Go back to your “VirtualBox Manager”, select your VM and click “Settings”
  1. Select “Network”
  1. Click “Port Forwarding” and Add a Rule:
  1. Name: SSH
  2. Protocol: TCP
  3. Host IP: 10.1.1.10 which is the IP of your server or host computer, see Step 3
  4. Host Port: 2222 (Which is the port we specified for clients to use SSH)
  5. Guest IP: 10.0.2.15 which is the IP address of your VM server we found in Step 2
  6. Guest Port: 22 (which is the default port for SSH server.


  1. You can now connect to your VM from a client computer (or your host computer if you like) using PuTTY.
  1. Open PuTTY
  2. Enter in your host computer IP address eg. 10.1.1.10
  3. Enter the port: 2222
  4. Enter a Saved Sessions name eg. Local VM Dev
  5. Select “Connection > Data” from the Category pane on the left
  1. Enter “root” into the “Auto-login username” field
  1. Go back to “Session” and click “Save”. This allows you to quickly connect to your VM next time.
  2. Now click Open and enter your VM password (which is “reverse” if you used the VM I provided).

Install Zend Server

        If you intend to run MySQL on the same server you must install it before installing Zend Server.

Install MySQL

  1. In PuTTY type:
  1. yum install -y mysql mysql-server
  1. Configure MySQL: This will create a password for the root user and also create a new user so that we don't use “root” to access our database in the application.
  1. /sbin/chkconfig --add mysqld
    /sbin/chkconfig mysqld on
    /sbin/service mysqld start
  2. mysqladmin -u root password 'some_password'
  3. mysql -u root -psome_password
  1. CREATE USER 'new_user'@'localhost' IDENTIFIED BY 'new_password';
    GRANT ALL PRIVILEGES ON *.* TO 'new_user'@'localhost' WITH GRANT OPTION;

Install Zend Server

Let’s now install the application stack, Zend Server, on our CentOS VM. If you dont have a Zend Server license I have provided some alternatives for this section: Zend Server CE (free) and standard PHP install.

  1. Ensure your VM is up and running on your Host computer, if not, start it up again.
  2. Log into your VM via PuTTY
  3. Type (or copy and right-click in PuTTY):
    nano /etc/yum.repos.d/zend.repo
  4. Add the following:
    [Zend]

name=Zend Server

baseurl=http://repos.zend.com/zend-server/rpm/$basearch

enabled=1

gpgcheck=1

gpgkey=http://repos.zend.com/zend.key

[Zend_noarch]

name=Zend Server - noarch

baseurl=http://repos.zend.com/zend-server/rpm/noarch

enabled=1

gpgcheck=1

gpgkey=http://repos.zend.com/zend.key

  1. Exit (Ctrl-X) and save
  2. Type (or copy paste into PuTTY):
    yum install -y zend-server-php-5.3
    yum clean all

Install phpMyAdmin (optional)

If you are using MySQL the easiest way to manage the database is via phpMyAdmin. If you are using a CentOS image you will need to install it manually.

In PuTTY type:

  1. wget http://packages.sw.be/rpmforge-release/rpmforge-release-0.5.2-2.el5.rf.x86_64.rpm
    rpm --import
    http://apt.sw.be/RPM-GPG-KEY.dag.txt
    rpm -i rpmforge-release-0.5.2-2.el5.rf.*.rpm
    yum install -y phpmyadmin-zend-server-php-5.3
  2. rm -f rpmforge-release-0.5.2-2.el5.rf.*.rpm
  3. perl -p -i -e 's/url\.access-deny = \( "" \)/url.access-deny = ( "*" )/' /usr/local/zend/gui/lighttpd/etc/lighttpd.conf
  4. perl -p -i -e "s/\$cfg\['blowfish_secret'\] = '';/\$cfg\['blowfish_secret'\] = 'your_secret';/g" /usr/share/phpmyadmin/config.inc.php
  5. /usr/local/zend/bin/zendctl.sh restart

Install Extra Extensions (optional)

This pack contains extra extensions including PHP MongoDB driver and

  1. From PuTTY type: yum install -y php-5.3-extra-extensions-zend-server

Add port to Firewall

Open your firewall panel again and add:

  1. Zend Server, port: 10081

Add port forwarding to VM

Go to your “VirtualBox Manager”, select your VM and click “Settings”

  1. Select “Network”
  2. Click “Port Forwarding” and Add a Rule:
  1. Name: Zend Server
  2. Protocol: TCP
  3. Host IP: 10.1.1.10 which is the IP of your server or host computer, see Step 3
  4. Host Port: 10081 which is the Zend Server port we use on our client machine. This can theoretically be anything, so if this port is taken on your client, use specify something else.
  5. Guest IP: 10.0.2.15 which is the IP address of your VM server we found in Step 2
  6. Guest Port: 10081 which is the Zend Server port.



While we are here, we should add another port that forwards your actual web page requests. This will become more obvious later but add the following:

  1. Click “Port Forwarding” and Add a Rule:
  1. Name: www
  2. Protocol: TCP
  3. Host IP: 10.1.1.10 which is the IP of your server or host computer, see Step 3
  4. Host Port: 8090 which is the port we are going to send web page requests from as we cannot use the default port 80 as this affect regular web browsing.
  5. Guest IP: 10.0.2.15 which is the IP address of your VM server we found in Step 2
  6. Guest Port: 80 which is the default http port.

You can now access the Zend Server web interface from your clients machines: eg. http://10.1.1.10:10081

  1. Accept the license Agreement
  2. Enter a password to access the management interface
  3. Enter your Zend Server license key. If you dont have one you can sign up for a 30 day free trial by registering: http://www.zend.com/en/products/server/license 

Deploying an Application (zend style)

Now that the Zend Server is up and running you can deploy applications created by Zend Studio directly to Zend Server. There are a variety of ways to do this however I’m not going to cover them in this post. If you are interested you can find a bunch of great tutorials including:

Deploying an Application (virtual host style)

Since Zoop relies on sub domains to display different stores, I am going to show you a different (my preferred) approach to deploy applications using virtual hosts on the Zend Server, a host file on my client machine and a shared folder in the VM.

The most efficient way to access your application in the VM is to share a regular OS folder. This allows you to continue to use your IDE to develop and see the changes in the VM instantly upon saving, removing the need to shuffle files around using FTP or a package manager like Zend Studio.

Create Shared Folders

  1. Create a new, shared folder on your host computer, ensuring that the correct permissions are set so your clients can read and write to it over the network. I created one call “Sites” and set the read/write permissions on Guest. You may want to restrict that a little more and set up specific folders and ACL’s for each developer.
  2. Then using your favourite source control app or just the trusty old copy/paste, add in your application files. Note: It’s going to be best if you use some form of version control here as it keeps everything nice and tidy and removes the need for constant copy/paste.



    As you can see I’ve added 3 different applications, however this can easily be different versions of the same application or even different developer branches. The ones I added are:
  1. complete_purchase-commerce_trunk: A legacy version of our e-commerce application
  2. zoop-commerce_trunk: Our current version of the commerce applciation
  3. zoop-mainsite_trunk: Our main “corporate” site.
  1. Switch to the VirtualBox Manager and select your VM and click “Settings”


  1. Click “Shared Folders
  2. Click the “add folder” icon on the right hand side
  3. Select a “Folder Path” > “Other” then navigate to the shared folder you just created.
  4. Enter a share name. I used “Sites
  5. Check “Auto-mount”
  6. Check “Make Permanent”
  7. Click “OK” then “OK”
  1. On your running VM go to the:


  1. Devices” menu
  2. Click “Install Guest Additions...
  1. Go back to PuTTY (or you can run this directly from the VM, whichever is easiest. I prefer PuTTY on my client).
  1. Run the following:
    yum update -y
    yum install -y gcc kernel-devel make
    reboot
  2. mkdir /cdrom
    mount /dev/cdrom /cdrom
    /cdrom/VBoxLinuxAdditions.run
  1. You should now see your shared folder with the prefix “sf_” to check type the following in PuTTY
    ll /media


  2. Now let’s mount that folder in a more permanent spot by:
  1. mkdir /mnt/www
    mount -t vboxsf “Sites” /mnt/www
  1. In order to have this mount automatically on boot we must edit the rc.local file. Note I tried auto mounting with the fstab file but couldn’t get it to work.
  1. nano /etc/rc.local
  2. Append the follow line to the file:
  1. mount.vboxsf -w -o fmode=0777,dmode=0777 Sites /mnt/www
  1. Reboot. (eg. shutdown -r now or reboot)

Add VirtualHost

The next step is to add hosts to our Zend Server. These tell Apache what content to serve for what URL, and it allows us to have many applications on the one server.

We can edit the main httpd.conf file however it’s much cleaner and safer to create a host file for each application and have them autoload from a single directory. That directory for Zend Server is /usr/local/zend/etc/sites.d/ . In order for files in that directory to be autoloaded they must be prefixed with “vhost_” and have the extension “.conf”. eg. For my Zoop application:

  1. Open PuTTY and log into your VM
  2. Type: nano /usr/local/zend/etc/sites.d/vhost_zoopcommerce.conf

Add the following text to the file and save (the parts in red need to reflect your application info):

<VirtualHost *:80>

    DocumentRoot "/mnt/www/zoop-commerce_trunk/public"

   

    ServerName Zoop

    ServerAlias *.zp.com zp.com

    <Directory "/mnt/www/zoop-commerce_trunk/public">

            EnableSendfile off

                Options FollowSymLinks

        AllowOverride All

        Order allow,deny

        Allow from all

    </Directory>

</VirtualHost>

  1. Restart apache by: service httpd restart

Add Domain to Client hosts file

        Since the domain we outlined in the VirtualHost file (zp.com and the wildcard *.zp.com which allows all sub domains of zp.com) does not actually point to my local site, we need to “trick” our client computers to push all requests for zp.com through to our new VM Zend Server. To do this we:

  1. Open your hosts file in a text editor. On Windows it is typically located:
  1. C:\Windows\System32\drivers\etc\hosts
  1. Add the following line:
  1. 10.1.1.10 zp.com . The first part is the IP address of our host, which in my case is the Windows Home Server. The second part is the domain name we entered in our VirtualHost. Remember this can be anything you want, however it is easiest to keep it short and nothing you would typically use for real. ie. Don’t use google.com or your real site domain!
  2. If you have subdomains as well you will need to enter them on separate lines eg.
  1. 10.1.1.10 www.zp.com 
  2. 10.1.1.10 store.zp.com 
  3. 10.1.1.10 blog.zp.com

Now open your favourite browser and go to zp.com:8090 (remember we need to append the port number we forwarded in the beginning as the default port 80 would affect browsing).

That’s it!! We’re done! If you’d like you can now add multiple hosts and applications by repeating the “Add VirtualHost” and “Add Domain” sections.

Alternative Step 1: Install Zend Server CE

I realize that Zend Server is quite expensive so I will also show how to install their free Zend Server Community Edition (CE). It’s basically just the apache/php web stack without some of the nice to haves including Page Caching, Job Queue, Code Tracing and Application Deployment. The full matrix of features can be found here: http://www.zend.com/en/products/server/editions