Stalk me on the internet

When I was younger, I enjoyed an afternoon playing the board game “Stock Ticker”. It was a new concept to me (no board to travel around), it dealt with money (and getting rich), and I was playing it with some really great friends. All in all, it was an enjoyable experience.

But what stayed with me through the years was the question: “Wouldn’t this game be more interesting if the player had more agency?” As it was, the game was very, very random, with interesting decisions only really happening near the Off Market line – and even those were just betting with higher variance. Over the past few weeks, I’ve been thinking about how to do that, and I think I’ve come up with something fun to play.

I’ll definitely try putting together a prototype and guilting my friends into playing it, but for anyone else interested, I’m putting the rules online as well. If you try a game, let me know!

Insider Trading

Sometimes being a super-wealthy financial mogul isn’t enough anymore. You have to be the best super-wealthy financial mogul. And that involves proving your worth. You and up to five other players play the part of well-connected and unscrupulous capitalists, attempting to settle a bet: With just $5000 and your own resources, how much money can you make in five years? The winner gets the best table at the country club, while everyone else is forced to eat at the servant’s table. Ugh.


  • Game board: A tall board with 5 Price columns and five Quarterly Report squares. Five companies are depicted thereon, with each company having a column and a square all its own. The Price columns go from “BANKRUPT ($0)” at the bottom to “SPLIT ($200)” at the top in $10 increments. The $100 row is specially highlighted.
  • 5 Price Markers, one for each company.
  • 10 Quarterly Report cards. These cards have the numbers 1-6 on them, alongside a value adjustment, such as +$10 or -$30.
  • 50 Influence cards. These cards have Quarterly Report-altering effects on them, such as “On a 6, +$10″, or “For all rolls less than 3, roll again.” They also have a cost listed, indicating the amount of stock that must be forfeited to activate the Influence card.
  • A whole whack of play money.

Game Setup

  1. Place the game board on the table, with markers for each company in the middle of the board at the $100 level.
  2. Give each player $5000.
  3. Shuffle the Influence deck and deal out 3 Influence cards per player.
  4. Shuffle the Quarterly Report deck and deal one on each company’s Report square.
  5. Give the First Trader token to the winner of a roll-off (highest wins, ties re-roll).

Turn Order

  1. Purchase Phase:
    1. Play starts with the First Trader.
    2. Choose a single Quarterly Report card to secretly peek at. This card *cannot* be shown to any other player, but the peeking player *may* choose to share the information gained. The information shared does not have to be complete, accurate, or even correct.
    3. Buy stock from the board, or sell stock you own. Stock is bought and sold to and from the bank, and for the price currently listed on the board.
    4. Play passes to the next player clockwise, until all players have played.
  2. Influence Phase:
    1. Players may play Influence cards face-down on top of company Quarterly Report cards, provided they pay the cost of the Influence card in shares of stock *for* that company.
  3. Report Phase:
    1. Reveal each company’s Quarterly Report and Influence cards in turn from top to bottom. Then, roll for each company in turn from top to bottom and resolve their Quarterly Report and Influence cards.
    2. Any stock that has reached “SPLIT ($200)” has split! Anyone who owns that stock receives an additional amount equivalent to their current amount, doubling the amount they own. The stock’s price is moved back to $100.
    3. Any stock that has reached “BANKRUPT ($0)” has gone bankrupt! Anyone who owns that stock forfeits it entirely. The stock’s price is moved back to $100.
  4. Cleanup Phase:
    1. Quarterly Report cards go back in the deck, which is re-shuffled. Deal out one card on each company’s Report square, as before.
    2. Influence cards go into the Influence discard pile. Players draw Influence cards to bring their total back up to 3. Players may choose at this time to discard *one* Influence card, though they will have to wait until next turn to refill. If the Influence deck runs out, reshuffle the discard pile as the new Influence deck.
    3. The First Trader token is passed to the next player, clockwise.


The game progresses for five game years, or twenty game quarters. The winner is the player with the most value in their portfolio, including cash on-hand and stocks at current board value.

Recently, one of Retuers’ blogs was hacked, and false stories were posted as if they were real news.

Now, while that’s news in and of itself, the big takeaway that’s relevant to me and PanicPress is that if Reuters can have one of their blogs broken into, anyone can.

Obviously, they use secure passwords at Reuters, and have backups, and keep their blogging software up-to-date – the works. Well, okay maybe not “obviously”, but it’s a solid guess. They probably take as many precautions as the can, and they still managed to be hacked and have false stories posted.

Would PanicPress have made a difference? Very possibly! One of the most important concepts in security is the concept of layers – that is having a whole bunch of security systems in place, all working in tandem. PanicPress provides yet another layer of security that WordPress doesn’t otherwise offer, and even if a hacker managed to guess or steal a legitimate reporter’s password, it’s highly unlikely they’d be using it from a known IP. PanicPress would have detected that and alerted the administrator, who could have shut down the admin section before the hacker had a chance to post those fabricated stories.

I’m really looking forward to launching for real – the “todo” list is getting much, much shorter by the day, while the need for PanicPress grows.

Yes, yes he should.

Posted by on 05.08.2012 in Coding

Nerd humour time.

I’m having some trouble with my coffeescript compiler. Every time I try to get my webserver to compile a new coffeescript file as part of developing this new website of mine, I get the following error:

env: node: No such file or directory

Near as I can tell, this means that “node” doesn’t know where the “coffee” script is (“node” being the execution environment used to run the “coffee” script, which compiles coffeescript into javascript to be run in the browser).

For a little bit, I was concerned that this was because I didn’t have my environment variables set up correctly for the _www user (the user that Apache normally runs as), but then I recalled having changed the user Apache runs as… to me.

Perplexed, I uttered: “The hell? Dan should know where coffee is!”

Yes. Yes Dan should know where coffee is.

I’m gonna go pour myself a cup right now, actually.

EDIT: Solved thanks to the internet and this kind fellow.

Well, it sure has been a while since I’ve posted. I have that terrible habit, of course – I get so involved in Doing Other Things that I neglect the ol’ blog in-between. Apologies. Won’t happen again. (Yes it will.)

Now while I love doing what I’m good at, I wanted to take a break from not posting to share what I’ve been working on:

PanicPress – A WordPress plugin that adds a critical extra layer of security on top of your blog. The moment an attacker tries to access your WordPress administration section, you get a warning text.

But let’s take that one step further – reply to that text with one of your own reading “panic”, and the entire administration section will shut down with a convincing-looking PHP error, giving you the time necessary to find out and fix what’s broken. Once you’ve solved your problem, texting “safe” will restore the administration section and let you get back to posting uninterrupted.

I’m nearly ready to launch the site – about 90% or so. But as they say, the first 90% takes 90% of the time. The last 10% takes the other 90% of the time. I expect to launch with a Minimum Viable Product within a week or two.

If you’re interested in hearing about the launch on Day One, hit the Sign Up page anyway! I’m collecting email addresses from interested parties, and the moment I finish putting the site live for real, I’ll send an email out to everyone on that list. (And after that, I’ll discard that list forever, so please don’t worry about spam on my behalf!)

In the meantime, if you wouldn’t mind visiting the site and clicking the little “Like” button up in the corner, oh and if you could go and like this Facebook page too, that would be a real help. Anything you can do to spread the word!

So Much Fail.

Posted by on 14.05.2012 in Games

The only thing worse than this video:

Is the comments beneath it.

lol, is this supposed to be “hot” or something? I guess this kind of marketing works on virgins or something, but it’s funny how much this shit doesn’t even faze you once you get a girlfriend. Try again, Ubisoft — this bitch is hideous, your game looks generic, and you should probably fire your marketing department.
BTW, it’s pretty obvious that your marketing bots gave you 600 of those likes.

– SolipsistGrifter

Wow, this chick(?) is hideous… What terrible marketing. She looks like some Las Vegas tranny with bad plastic surgery (sorry) and this is supposed to make me want to play this game? Even if you didn’t objectify ugly women to sell your shit game I probably still wouldn’t play it; looks like every other generic brown shooter.

– phubans

I love how they purport to attack the sexism in the ad, while throwing out phrases like “this bitch is hideous” and “Las Vegas tranny”. My god, the irony in the sentence “Even if you didn’t objectify ugly women to sell your shit game”… So hold on, objectifying women upsets you, and you focus on whether the woman in the ad is pretty or not to judge her value?

The internet makes me so sad some days.

When writing code, so many things can go wrong. So many little things can be forgotten or overlooked and cause bugs and interruption. However, your time is finite and your patience is limited. Removing all these little causes of frustration pays incredible dividends down the line.

One of the frustrations I regularly encounter is failing to save a file in our backend tool after making modifications in SVN, which is caused by a permissions conflict. The user I run SVN as (me) is different from the user I run Apache as (_www by default), which means that if when I own a file, Apache can run into trouble trying to save it (such as through our backend tool).

For a while, I depended on a custom bash script that would recursively modify the permissions in my development folder, but I still have to remember to run that script every time I make certain modifications via SVN. Every once in a while I’ll forget and get glaring error messages. It breaks my flow, which slows me down and frustrates me. Thankfully, there is an easy solution.

Be someone else

If Apache runs as the same user that SVN does, suddenly these problems dissappear. They both have the same rights and access to the files, and no longer need I worry about running scripts to fix things.

Kick open a console:

$ sudo nano /etc/apache2/httpd.conf

Find the line that says:

User _www

And change “_www” to your username. If you’re not sure what that is, type “whoami” at the console to find out. With that done, save and restart Apache:

$ sudo apachectl restart

From here on out, your problems should be solved! (Well, you may need to change permissions on or remove certain files created by _www, like session files.) Apache will open and save files as you, so as long as you have access, so too will your web server.

Seriously, if you haven’t fallen in love with spreadsheets yet, you’re doin’ it wrong. I’m currently in the middle of figuring out a multiple-week game loop with really tight targets. How the heck would you ever get this done without a well-constructed spreadsheet? Trial and error would take forever. Guesstimates wouldn’t get you anywhere near what you wanted. No, you need constantly-updating formulae and graphs and colours and stuff. The difference it makes in your capabilities is insane.

A quick example

Say you have an enemy – a cute little slime-creature. And when he’s defeated, he drops a macguffin – but occasionally! Players need ten of these macguffins to progress to the next area, where there’s a boar who drops a similar macguffin. And in the next area, there’s the final creature – a gargoyle – and ten more macguffins to collect.

Three monsters, three macguffins. We want this area to be challenging, but not too frustrating, so let’s set some base assumptions: If it takes less than 100 encounters, it’s not challenging enough. If it takes more than 300 encounters, it’s too frustrating.

Now, we could just throw some numbers onto those creatures and hope, but I’ve got a better way. Let’s set up a spreadsheet with some intuition-based numbers and see how close we come.

Table 1: Drop Rates

The first thing we need to figure out is how often a player is going to get a macguffin drop from a creature. To do that, I’ve created the following table:

Column A is the name of the creature the player will be encountering. B is the chance they will beat that creature when fighting them. C is the chance they drop the macguffin they are looking for. And finally D is the number of expected macguffins from each encounter. So far, we can see that for every time you fight a slime, you can expect to get 0.07 of a macguffin. Seems pretty low, but we’ll find out just how low in a second. Let’s make a second table.

Table 2: Encounters Needed

Column A has the same creature names as before. B is the amount we need to collect before we can progress. And C is the number of expected encounters a player will need to go through to get the amount listed in column B.

And WOW are those numbers high! Seems our intuition was off, and it’s time to play with the numbers a bit to balance this out. We have some options:

  • We could increase the drop rate of the macguffins. This will not only speed up the collection, but also reduce variance for players. (Variance is a topic for another time, but in short, you want less of it. High variance means that you’ll have a lot of players who fall outside of your expected numbers, which is either exceedingly frustrating or boring for those players.)
  • We could decrease the difficulty of the encounters. This will allow players to collect secondary assets (gold, experience) more quickly while speeding up collection as well.
  • We could decrease the number of macguffins needed. Psychologically, collecting 10 macguffins at a 10% drop rate feels a lot less like a chore than collecting 100 macguffins at a 100% drop rate.

And that’s outside of doing something crazy tricksy, like adding or removing more creatures, allowing players to buy or craft macguffins, etc. So let’s play with the numbers some, and see if we can come up with something a little more fun.

Table 3: Some Interesting Numbers

It only took me about five minutes of tweaking to come up with this, and I can already tell that it’s a lot better. For one, it only takes 191 encounters to resolve – almost exactly in the middle of our 100-300 range. For another, see how the Encounters column in the second table gently rises? It didn’t when I first started playing around with the numbers, but I quickly saw how going from 50 encounters to 25 encounters to 125 encounters would be very weird, and altered my values to suit.

Of course, you’ll still want to play-test this to ensure it’s actually fun when you play it, but this is a much better starting point for your playtest than our original numbers, and it only took five minutes to find out, and five minutes to improve it a vast amount.

Hopefully you can see how much of a difference a good spreadsheet can bring to a game developer’s toolkit. I’ve still got a few more concepts I want to cover regarding spreadsheets (the LOOKUP function, conditional formatting, etc.), so stay tuned!

Female Game Developers

Posted by on 29.02.2012 in Coding, Design, Life

I follow a bunch of female game developers on Twitter. Now, I also follow a bunch of male game developers on Twitter, too. In fact, it’s fairer to say that I just follow a bunch of game developers on Twitter. But that’s exactly the issue, isn’t it?

What are you talking about?

The point is, a few days ago, @whitney – one of the game devs I follow – tweeted the following:

Folks contact me b/c they need a female game designer. Makes me want to relabel a giant jar of mayo with MAGIC GIRL SAUCE & carry it around.

Then followed it up with:

Was also going to say I can’t wait until “female game designer” sounds as antiquated as “female doctor” but uh, people still say the latter.

And then:

Pilotess! Doctorette! Police officerina! Game designelle?

Well she’s right, you know

Well, maybe. I’m sure that in many cases – and probably the original case she mentioned – it’s just hiring managers ticking a checkbox. “Must have X number of female developers on staff.” Or worse, clueless wanna-be Zyngas thinking they can hire @whitney and have her sell them The Secret Behind Bilking Ladies Out Of Money.

But on the other hand, there can be an incredible value in adding a female to an already all-male team.


Imagine you have to go into the doctor’s office and have your, ah… sensitive areas examined – you think your partner might have been cheating on you, and that rash down there is hella embarrassing and worrying. But the only doctors available are of the opposite gender.

Sure, maybe you’re strong enough and un-self-conscious enough to go get it done anyway, but there are going to be plenty of people out there who are embarrassed to the point where they may skip having the examination done at all.

Having a female doctor on-staff may save lives.

Police officerina!

10-16! 10-16! We have a domestic disturbance! Car 460, you are closest, please respond!

And yet car 416 has only male officers. Arriving on-scene, they’re able to separate the squabbling couple. The man insists that his “stupid bitch” of a wife is trying to ruin his life and he doesn’t remember who started swinging first. The lady is too intimidated by the large male police officer to say anything. In this case, having officers of both genders on-site ensures that both parties get fair, unbiased, caring, and un-intimidating treatment.

Yeah, but Pilotess?

You got me on that one. That IS ridiculous.

Okay, so… Female Game Developer, then?

I still think this one has merit. I went to a presentation at PAX East last year on “Expanding Your Game’s Market”, and expected tips about SEO, or cross-brand promotion, etc. How wrong I was. The entire presentation – the entire presentation – was about finding entirely different markets for your game. Not how to advertise better, but how to think of and appeal to entirely different people.

A great deal was said about transgender gamers. Transgender people typically tend to be very brand-loyal – when they find a company that values them and values their values, they make go out of their way to reward that effort with increased patronage. Many of the people on the panel were blown away by the fact that there were no games or game companies falling over themselves to appeal to transgender people.

But really, how can they without having someone on-staff who understands the position of transgender people? I’ll be honest, I don’t know the first thing about what it’s like to identify as transgender. I don’t have any transgender friends, or even acquaintances! So how am I supposed to make a game that appeals to that market without hiring from within that market?

Now, a market that games companies are falling all over themselves to appeal to is women. Yet a great many game companies are still composed entirely of men! Now while we all (generally) know some women that we can consult with or at least mentally model, how much more beneficial would it be to actually have a lady on-staff that can contribute regularly and meaningfully?


A little. We don’t have many female game developers at Hitgrab, true. And yet we somehow manage to put out a game that does appeal to women.

But it’s hard.

Putting yourself in someone else’s shoes – successfully – is difficult. We’ve lamented a few times the difficulties we face in trying to appeal to the various play styles and tastes of the people who play MouseHunt, especially when we don’t share those same tastes. We do our best to put the stuff we’d like to do in the game, as well as listen to our community, and put in the things that they request.

But it’s hard.

Many great, game-changing ideas fall by the wayside because they don’t have a champion. Many incredible ideas never get raised because nobody with that point of view is there. Many good, cross-gender-appealing ideas do make it in the game, but they have rough edges that only get polished off once the game is live and a full cross-section of our players have the chance to realize what does and doesn’t work.

Like I said, it’s hard.

So would I hire a female game dev as a magic bullet to make my game appeal to women? Heck no.

But would I hire a game dev with insight into the mind of a wider market – all other qualifications being equal? Sure. And that dev would have an excellent chance of being female, I’m sure.

Broken Glass

Posted by on 16.02.2012 in Coding

Imagine, for a moment…

You’re the new guy at BlokkStone Games, and you’ve had a pretty good first month. You fit in with the other programmers, and your team has made some excellent progress towards releasing their new title: Carolina Jess And The Temple Of Gloom. It’s a retro-graphics cell-based adventure game that is looking pretty sweet.

Now occasionally – when a player is hit, or an enemy dies – you need to add a glow to a shape. You do this by calling an internal library function written long ago: “addGlowToShape()”. Everything was working fine… until you tried using shapes that weren’t exact squares. Everything still ends up being an exact square, every time!

Dutifully, you dig up the library file, find the function in question, and are greeted with… this:

        add a glow to a shape
function addGlowToShape(&$shape) {

    // getstartloc
    $x = getStartX($shape);
    $y = getStartY($shape);
    global $world;
    $cells = $world->getCells();
    $shape_name = $shape->getName();
    $cellsAffected = 0;
    // do it all
    for ($rowY = $y; $rowY < $y + $shape->getHeight(); $rowY++) {
        for ($rowX = $x; $rowX < $x + $shape->getRowLength($y); $rowX++)
    // @todo: return false on an error
    return $cellsAffected;

Augh! Oh god! What is… Is that comment supposed to mean anything? And… and you don’t even use $shape_name! What is going on in there?

This, my friends, is broken glass. Broken glass all over the place. And I bet you it didn’t start out like this. I bet you it started out very simple, very maintainable – like everyone’s favourite pet code – and then evolved into this horrid mess. But how, you ask? Easily. Someone broke a window.

The Broken Windows Theory

Alright, enough dancing around metaphors here. Let me explain what I actually mean.

In 1982, social scientists James Q. Wilson and George L. Kelling wrote an article containing the following example:

Consider a building with a few broken windows. If the windows are not repaired, the tendency is for vandals to break a few more windows. Eventually, they may even break into the building, and if it’s unoccupied, perhaps become squatters or light fires inside. Or consider a sidewalk. Some litter accumulates. Soon, more litter accumulates. Eventually, people even start leaving bags of trash from take-out restaurants there or breaking into cars.

So influential was this article that it was used to justify a crackdown on vandalism, fare-dodging, and lead to all kinds of “zero-tolerance” policing in the city of New York. The theory was that if the police cleaned up all the “broken windows” (i.e. worked tirelessly to clean up the streets and absolutely prevent lesser crimes), that the overall crime rate would improve. And from 1984 (when the program began) onwards, the rate of serious crime fell dramatically. Today, the City of New York City is not the scary, drug-and-disease-infested hellhole predicted in 1980′s movies. It’s not even comparable.

This is known as The Broken Windows Theory, and it is easily applicable to programming as well. In fact, it could be rewritten as such:

Consider a function with a few coding standard violations. If the violations are not cleaned up, the tendency is for maintainers to ignore a few more standards while editing. Eventually, they may even leave unused variables from previous revisions, or forgo commenting entirely. Or consider a class. Some uncommented functions accumulate. Soon, more functions are added with no comments to describe them. Eventually, people even start copying and pasting whole sections of uncommented code elsewhere.

Sure, it’s a bit of a reach, but I’m sure you’ve all seen some version of it happen in the projects you’ve worked on.

See what happens?

Okay, so back to our example. We can do one of two things here. One, we can just slip in quietly, fix the bug, and get the hell out of there. Or two, we can clean up the function while we fix the bug. Let’s just see what happens.

First, we just fix the bug:

        add a glow to a shape
function addGlowToShape(&$shape) {

    // getstartloc
    $x = getStartX($shape);
    $y = getStartY($shape);
    global $world;
    $cells = $world->getCells();
    $shape_name = $shape->getName();
    $cellsAffected = 0;
    // do it all
    for ($rowY = $y; $rowY < $y + $shape->getHeight(); $rowY++) {
        for ($rowX = $x; $rowX < $x + $shape->getRowLength($rowY); $rowX++)
    // @todo: return false on an error
    return $cellsAffected;

Not so bad. I mean, we fixed that bug – we’re checking the length of each row instead of just the original row. But that function is still a mess for the next person to come by. Why don’t we try cleaning it up?

 * Add a glow effect to all cells in a shape.
 * @param ModelShape $shape The shape to add the glow effect to.
 * @param array      $cells The cells from the world to change.
 * @return mixed The number of cells updated or false on error. 
function addGlowToShape($shape, & $cells) {

    $start_x = getStartX($shape);
    $start_y = getStartY($shape);
    // Get the row to stop at
    $end_y = $start_y + $shape->getHeight();
    $cells_affected = 0;

    $success = true;
    for ($cell_y = $start_y; $cell_y < $end_y; $cell_y++) {

        // Get the cell to stop at for this row
        $end_x = $start_x + $shape->getRowLength($cell_y);

        for ($cell_x = $start_x; $cell_x < $end_x; $cell_x++) {
            $success &= addGlowToCell($cells[$cell_x][$cell_y]);
    return $success ? $cells_affected : false;

See? See what we did there? We fixed the actual bug, did the todo, and fixed another, subtler bug that was hidden until we started going in and doing simple things like adding missing brackets.

Granted, yes, this is also a significant change that you'd need to go over with your team - we changed the signature which means we need to change everywhere that it is called from. But that's why any modern IDE will have a global find-and-replace in it. Or even just a global find-and-mark if you're the paranoid type (and I am).

And the second-order effects from this are enormous. The next person to approach this method will likely see that it has been cared for, and not want to be the first person to mess things up. Code quality goes up, code comprehension goes up, and bugs go down.

So the next time you see "broken glass" in your project, don't just walk around it - clean it up.

If you do web development on Windows, you’re probably used to making do. XAMPP can go a long way, as can Cygwin, but once you want to start playing around with anything state-of-the-art, you’ll start feeling left behind. The solution? Set up a virtual machine running Linux, so you can take advantage of the latest and greatest in their native environments.

Set up Ubuntu

For this purpose, we’re going to be using VirtualBox – originally by Sun, recently(ish) purchased by Oracle. For my money, it still has the best mix of ease-of-use, features, and price (free). You can download the latest version here.

And while you’re at it, go download the latest version of Ubuntu Server. For this article, we’re using 11.10 (Oneiric Ocelot), which you can download here. Grab the 64-bit version.

Install VirtualBox. Before you run it the first time, you’ll want to right-click the icon and choose “Properties”. Then go to the “Compatability” tab and click the checkbox next to “Run this program as an administrator”. If you want any symlinks you create in Ubuntu to be recognized by Windows, you MUST be running the program as an administrator. Windows is funny like that.

Launch VirtualBox, then create a new virtual machine and set the Ubuntu ISO as the CD/DVD drive. (Under the Storage menu in Settings, click on the CD-looking thing under the IDE controller). Also, make sure to set up Networking as “Bridged”. Start up the virtual machine, then follow Ubuntu’s really slick install process. The only application you’ll want to install during setup is the OpenSSH server. We’ll install the rest ourselves.

When all is said and done, restart it and log in. Now the fun begins!

Set up your networking

Let’s set up a static IP address so we don’t have to keep figuring out what dynamic IP the machine obtained.

$ sudo nano /etc/network/interfaces

Edit the last part to look like this:

# The primary network interface
auto eth0
iface eth0 inet static

You’ll have to fiddle with those numbers a bit depending on your networking configuration. Ensure primarily that the address you supply isn’t taken by anyone else on your network, and that the gateway matches the one you get when you type “ipconfig” in Windows. Restart your network to get the changes recognized.

$ sudo /etc/init.d/networking restart

Once that’s working, start up Notepad as Administrator in Windows (right-click and “Run as administrator”). Then open up “C:\Windows\System32\drivers\etc\hosts” (no extension) and add your new machine’s IP address. Now you can do things like SSH directly to the hostname or type the hostname in your browser instead of remembering the IP address.

Install Apache

This is easy, and can be handled entirely through automated utilities built-in to Ubuntu.

$ sudo apt-get install --reinstall language-pack-en
$ sudo dpkg-reconfigure locales
$ sudo apt-get install gcc make wget cron curl
$ sudo apt-get install apache2 apache2-mpm-prefork apache2-prefork-dev apache2-utils apache2.2-common

One quick thing, to avoid getting the error “Could not reliably determine the server’s fully qualified domain name, using for ServerName” every time we restart, we need to make a small change.

$ sudo nano /etc/apache2/httpd.conf

Add the following line and save.

ServerName localhost

Install MySQL

Nearly as easy. Start with the automated utilities.

$ sudo apt-get install mysql-server-5.1

No need to give MySQL a root password on your development box. Then edit the MySQL config file.

$ sudo nano /etc/mysql/my.cnf

Change the “bind-address” line in that file to point the the local server IP. ( in the example above.)

Then, it’s worthwhile allowing root to log in from machines other than localhost. That way you can use whatever Windows GUI tool you like to log in to your virtual machine’s MySQL installation.

$ mysql -u root
GRANT ALL ON *.* TO 'root'@'%';
$ sudo service mysql restart

Install PHP

Now we could just use the built-in version of PHP, if we felt like taking the easy road. But that’s no fun. Let’s install PHP 5.4 RC2, so we can play around with all the new features. As an added bonus, if you get comfortable with compiling PHP now, you can recompile with whatever version and options you want later for when there’s a new release of PHP, and you don’t have to wait for your package maintainers to update.

First we need a bunch of build tools.

$ sudo apt-get build-dep php5
$ sudo apt-get install libxml2 libxml2-dev libzip-dev libbz2-dev curl libcurl4-openssl-dev libcurl3 libcurl3-gnutls libjpeg62 libjpeg62-dev libpng12-0 libpng12-dev libmcrypt-dev libmcrypt4 libxslt1-dev libxml2-dev

Next, grab and extract PHP 5.4.

$ cd ~/
$ mkdir tmp
$ cd tmp
$ wget -O php-5.4.0RC2.tar.gz
$ tar xvfz php-5.4.0RC2.tar.gz

Now, we configure and compile. This takes a while. Feel free to grab a sandwich or something.

$ cd php-5.4.0RC2
$ ./configure --with-apxs2=/usr/bin/apxs2 --with-config-file-path=/etc/php5 --with-mysql=mysqlnd --enable-inline-optimization --disable-debug --enable-bcmath --enable-calendar --enable-ctype --enable-force-cgi-redirect --enable-ftp --with-gd --enable-memory-limit --disable-sigchild --enable-trans-sid --with-ftp --with-jpeg-dir=/usr --with-png-dir=/usr --with-zlib=yes --with-zlib-dir=/usr --with-openssl --with-xsl=/usr --with-gd --with-mcrypt=/usr --with-mhash=/usr --enable-mbstring=all --with-curl=/usr/bin --with-curlwrappers --enable-mbregex --enable-zend-multibyte --with-bz2=/usr --with-mime-magic --with-iconv --with-pdo-mysql=mysqlnd --enable-fileinfo --with-pear --enable-exif
$ make
$ sudo make -i install

Of course, now we have to ensure that Apache knows about PHP.

$ sudo ln -s /usr/local/bin/php /usr/bin/php
$ sudo nano /etc/apache2/mods-available/php5.conf

Add the following lines and save.

AddType application/x-httpd-php .php .phtml .php3
AddType application/x-httpd-php-source .phps

Now enable PHP (and mod-rewrite, while we’re at it).

$ sudo a2enmod php5
$ sudo a2enmod rewrite

It wouldn’t hurt to ensure that PHP is configured how we like it, either.

$ cd /etc
$ sudo mkdir php5
$ cd php5
$ sudo cp ~/tmp/php-5.4.0RC2/php.ini-production php.ini
$ sudo nano php.ini

Ensure the following are set:

date.timezone = America/Toronto (Or whatever is closest to you.)
short_open_tag = On
error_reporting = E_ALL
display_errors = On
log_errors = On
error_log = /var/log/php.log
max_execution_time = 30
memory_limit = 128M
mysql.default_socket = /var/run/mysqld/mysqld.sock

Now make sure that the logfile we specified exists and is writable.

$ sudo touch /var/log/php.log
$ sudo chmod a+rw /var/log/php.log

Finally, restart Apache!

$ sudo service apache2 restart

You should be able to visit the address of your new virtual machine (or the alias you set up in hosts) now and get your basic Apache display.

Extra step – VirtualHosts

I presume you’re going to want to develop multiple projects without having to create separate virtual machines for them all. That’s easy! We’ll just set up an Apache VirtualHost for each one.

$ sudo nano /etc/apache2/sites-available/{development url}

Add the following, then save.

<VirtualHost *:80>
    ServerName {development url}
    DocumentRoot /home/{user}{/{development url}/

    <Directory /home/{user}/{development url}/>
        AllowOverride All

Now enable your site and reload Apache.

$ sudo a2ensite {development url}
$ sudo service apache2 reload

Extra step – Shared folders

I bet you’re wondering how you’re supposed to get files on and off that machine, huh? Well, since you installed OpenSSH, you have options there, but there’s an easier way. You can just share that folder you were referencing above with a specific folder on your host machine. Make changes in Windows, and it will (usually) be reflected in the virtual machine. I’ve noticed a few times that when I’ve created a file, the Ubuntu host flips out and doesn’t properly recognize it, but a quick restart fixes it, and machine restarts are usually like ten seconds, max.

First, make sure that folder above exists on your virtual machine, then click on the “Devices” menu in VirtualBox, then click “Install Guest Additions”. This makes a virtual CD available to your virtual machine that contains the actual guest additions we’re going to install.

$ sudo mount /dev/cdrom /media/cdrom
$ cd /media/cdrom
$ sudo ./

Ignore the crap about failing – we don’t have any GUI installed on the server, so whatever. Now shut down the machine (“sudo shutdown -h now”), and open up the Settings menu and click on Shared Folders. Click the little Folder/Plus icon on the right, and choose a Folder Path from your Windows box, and remember the Folder Name it gives you (or make up your own). Hit “OK” and start that machine back up.

We’re going to set up this machine to automatically mount that folder every time it boots up.

$ sudo nano /etc/init.d/rc.local

Add the following just after “do_start() {“:

    mount -t vboxsf {Folder Name} /home/{user}/{development url}

Now restart to check it out.

$ sudo restart -r now
# After restarting...
$ cd /home/{user}/{development url}
$ ls

You should see all the files from your Windows machine. If you don’t, well… ugh. Okay, I got this fixed by re-running the script, the re-mounting. No clue why that worked, but it worked, so… yeah. Not questioning it.

What Else Could We Possibly Do?

Hot damn, that’s a lot of stuff, isn’t it? Well, we still have Memcache, Memcached (yes, both), and Redis to install. These are all optional, but super-neat tools, and practically essential if you want to write anything that scales well these days.

For now though, you should have a good base to work from. If anything doesn’t work, let me know, but I followed along with my own VM while I was writing this, so I’m pretty confident I didn’t skip anything.