Version Control Can Be Dangerous

Version control for a website sounds like a great idea. Everyone wants to be able to make risk-free changes to their website. It’s a great feeling to know that at any given time you can revert to previous versions of files. With a VCS (Version Control System) like Subversion, you get a nice central location for all your code, a web interface to browse your files and, well, it’s a great thing to brag about to all your techie friends. The only problem is that it can seriously screw up your web development workflow if the implementation of such a system is not thought out carefully.

One Dilly of a Pickle

The biggest potential hurdle in setting up a VCS for web development is the web server. Unless you’re an HTML-only web developer (hopefully they don’t even exist anymore), then you either have a special development web server set up or you use your live web server to test out your scripts. Once you’ve figured out how to check your files in and out via your VCS, you’ll realize that you need to get these files to your web server. If you don’t have root access to your server, you might be in trouble. At this point you’ll want to stop everything and re-evaluate implementing VCS into your web development workflow. I’ve had to re-evaluate my processes a few times and the following describes what I’ve learned about various web workflow methods I have experimented with, as well as a detailed description of my current web development workflow.


[ad name=”Google Adsense 468×60″]

Remote Web and Subversion Server Accessed by Samba Share…

…a theoretically simple setup, but practically, it turned about to be a nightmare. I set up a basic LAMP box and also installed Subversion on it. I also set up a Samba share and created Apache virtual hosts to map to those shares. The theory was that I would check out files from the Subversion server to my local machine to a network drive mapped to the Samba share. So when working on files I could just CTRL+S and see my changes immediately on the remote server. When I was happy with the changes I would commit them. This setup almost worked, except for the checking in part. I kept getting file permission errors whenever I tried commit due to the Windows Subversion client not having permissions to write to the Samba share. I spent quite awhile trying to figure out what was going on, but I knew that if it takes this much effort to get it working, then no thanks. I don’t like my development to be put on hold because I can’t save my work properly.

There was one additional disadvantage of this method. By using Samba shares, I was limited to only local development unless I wanted to use VPN or SSH tunnels. It was time to move on.

Remote Web and Subversion Server with Files Checked in to Test

This method involves having Subversion installed to your web server and having it automatically export your project on commit to your web directory. This works pretty well. Your code is safe, as it’s checked in to your server constantly. The only problem is that checking in a file every time you make a change gets very annoying very quickly. There’s also the post-commit script that has to be configured properly, and if you have multiple projects you’ll have to account for that in your post-commit script. In my opinion, it’s not worth the trouble.


[ad name=”Google Adsense 468×60″]

How I Do It

I use three machines for development: an iMac running OS X 10.6 and a ThinkPad running Windows 7 at home, and a PC running Vista at work.

On each of these machines, I use Zend Studio 7.1 as my IDE and Zend Server CE 5.0 as my local web server.

Each one of my projects gets its own repository on my Subversion service hosted by Springloops. In most cases, for each project I have two deployment servers set up: one for production and one for staging.

Zend Studio handles all my Subversion tasks, although I sometimes use Tortoise SVN (Windows) or a terminal (Mac or Linux) for other non-code-related files.

I set up virtual hosts to point to each one of my projects’ working copy located in my Zend Studio workspaces folder.

My Typical Coding Session

My typical coding session would go like this:

Update local working copy of my project in Zend Studio.

Write some code and test on local development web server (Zend Server CE).

When I’m happy with those changes, I will commit them in Zend Studio, and then Springloops will automatically deploy the code to my staging server.

Once the site has been fully tested, I log in to my Springloops account and manually deploy my site to my production server.

But What About Databases?

You may have noticed I haven’t mentioned databases. Due to the potentially catastrophic issues that could occur from mixing staging and production databases, I keep them separate. I use both local and remote MySQL servers, depending on the type of project. I manually syncronize them when necessary by using phpMyAdmin.


I came across a stupid problem the other day while trying to figure out why my site changes weren’t showing up.

I’m writing my problem and solution on my blog so I’ll remember and not screw up the same way again.

Consider the following virtual host files.


<VirtualHost *:80>
    ServerAlias *

    . . .



<VirtualHost *:80>
    ServerAlias *

    . . .


My goal is to have and point to one vhost with the exception of and The problem is that Apache loads the scripts in order by file name. So when the second virtual host is loaded Apache pretty much ignores it because * overrides

I changed my file names of my vhost files, reloaded Apache, and all was fixed.

The correct file names:

[ad#Google Adsense 728×90]


Cloud Computing & Cloud Hosting by Rackspace


This guide will help you set up the following:

  • Zend Server CE (Apache/PHP)
  • Iptables
  • SSH
  • MySQL
  • Postfix (for outgoing mail)

Some of these steps are taken from the Rackspace Cloud Server Knowledgebase.

Create a new server instance

Log in to and create a new server instance with Ubuntu 9.10. Any instance size is great. I’d recommend naming your server with your FQDN as it saves a few changes later on.

Securing the server

The Rackspace Cloud Server comes with the root account enabled and no firewall setup. This is not a good thing for a public server. So the first thing we will do is create a new administrator account which we will use to log in via SSH, and then we will set up Iptables as our firewall.

Rackspace will email you the IP address and password of your new server instance.

Log in over SSH to your server instance. If you have a Mac just open a terminal window and enter something like the following:

ssh root@your_server_ip

If you use windows download putty, enter the IP address in the host box and click connect.

You should now be logged in to your new Cloud Server.

The first thing we are going to do is change the root password.

Change the password by using:


Since we don’t want to log in as root anymore, we need to create a new user.

adduser admin

We want the admin user to be able to become a super user so we need to add admin to the visudo file by entering this:


Nano will open a file; add the following to the bottom of the file.

admin ALL=(ALL) ALL

Next we will make some changes to the SSH configuration file. It is also a good idea to change the port SSH uses for security. We will also disable root logins and enable admin to log in via SSH.

nano /etc/ssh/sshd_config

Port 54321
PermitRootLogin no
X11Forwarding no
UsePAM no
UseDNS no
AllowUsers admin

To make those changes take effect, restart SSH. You will not be disconnected, but if you do disconnect, you will need to reconnect using your new username and new port.

/etc/init.d/ssh restart

Firewall Configuration

This server will be a web host so very few ports will be opened.

  • HTTP 80
  • HTTPS 443
  • HTTP 10081 (Zend Server CE)
  • SSH 54321

All other ports are dropped.

Create a file named iptables.test.rules in /etc and open it using nano.

nano /etc/iptables.test.rules

Add the file lines to that file. Make changes where required.

* filter
:INPUT DROP [1:48]
:OUTPUT ACCEPT [129:20352]  

#  Allows all loopback (lo0) traffic and drop all traffic to 127/8 that doesn't
-A INPUT -i lo -j ACCEPT
-A INPUT -i ! lo -d -j REJECT


#Accept SSH connections
-A INPUT -p tcp -m state --state NEW --dport 54321 -j ACCEPT    

#Accept Established connections
-A INPUT -m state --state RELATED,ESTABLISH -j ACCEPT    

#Accept HTTP connections
-A INPUT -p tcp -m tcp --dport 80 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 443 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 10081 -j ACCEPT


#Accept all PING requests on ICMP
-A INPUT -p icmp -m icmp --icmp-type 8 -j ACCEPT

# Reject all other inbound - default deny unless explicitly allowed policy


Now we are going to load the file to check for errors and to ensure the configuration is valid and our firewall works as expected.

iptables-restore < /etc/iptables.test.rules

You can view the active firewall rules by running this command.

iptables -L

If everything is satisfactory, save the rules into a new file which we will then configure to be automatically loaded upon boot.

iptables-save > /etc/iptables.up.rules

Now we need to add a line to the network interface’s initialization script so that our firewall rules will be loaded upon boot.

nano /etc/network/interfaces

Add the following line after ‘iface lo inet loopback’:

pre-up iptables-restore < /etc/iptables.up.rules

Now before we do anything else, we need to test the configuration. We don’t want to inadvertently lock ourselves out of the server, so we will test the firewall by opening a new SSH connection in a new window. As long as we don’t close our currently active connection we can still make changes if our new SSH connection fails.

If you can successfully connect to the server with the new account on the new port with the firewall rules enabled, then you should reboot the server and verify that iptables loads your configuration file on boot.

sudo reboot

You will be disconnected from both your SSH sessions.
Try reconnecting after 20 or 30 seconds, log in and then check your firewall configuration.

iptables -L

If the rules load successfully then we can move onto the next step.

Time Synchronization Setup

Run the timezone package configuration wizard selecting your time zone.

sudo dpkg-reconfigure tzdata

Create a cron job script:

sudo nano /etc/cron.daily/ntpdate

Enter the following in the /etc/cron.daily/ntpdate file:

sudo ntpdate

Change permissions of the cron job script:

sudo chmod 755 /etc/cron.daily/ntpdate

Configure User Locales:

sudo locale-gen en_US.UTF-8

Configure local time zone:

sudo ln -sf /usr/share/zoneinfo/America/Toronto /etc/localtime

Outgoing Mail Server Setup

Install postfix and mail tools:

sudo apt-get install postfix mailx

MySQL Installation

Run the following command to install MySQL:

sudo apt-get install mysql-server

Zend Server CE Setup

I prefer the manual installation method. Instructions can be found here on Zend’s site.
I use a portion of those instructions in my setup.

Define a new package repository by opening the following file: /etc/apt/sources.list and adding the line:

deb server non-free

Now download the GPG key:

sudo wget -O- |sudo apt-key add -

Update the package list:

sudo apt-get update

Install Zend Server with PHP 5.3. Note: Zend does provide Zend Server with PHP 5.2 packages. View the Zend Server CE documentation for more information.

sudo apt-get install zend-server-ce-php-5.3

I like to install phpmyadmin but it is optional:

sudo apt-get install phpmyadmin-zend-server

[ad#Google Adsense 728×90]