Eddy Chan

giving back to the hacker community

4 notes &

The ONLY thing you need to get good at is selling…

I had the pleasure of being able to meet up with my old boss Bardia Housman on the weekend at our annual ex-Business Catalyst employee reunion. He’s a guy who has founded and sold 2 startups and is now running a startup co-working space, I look up to him as a quasi start-up mentor and go to him for advice every now and then. 

We were at a family-oriented pool party/BBQ and in between all the eating, drinking and playing with kids, he drilled me on my startup ZenBookings

  • How many customers did we have? How many free ones, how many paid ones.
  • What was their feedback?
  • What were our biggest obstacles? What are we doing about it?

And so on and so forth, just to make sure my business was heading in the right general direction. It was really refreshing to be able to confide so honestly with somebody who’s been there and done it all before. Twice. But the one thing that really stuck with me from that meeting was the following exchange - 

"Eddy, if I have one piece of advice for you it’s this: the ONLY thing you have to get really good at is selling. Product doesn’t matter…well it does matter…but you need to get good at selling FIRST and then follow it up with great product execution. The only reason why Business Catalyst succeeded was because we knew how to sell. We started off with 2 fantastic sales people as co-founders and then we refined selling into a process and got good at selling online…"

And then, one of the kids started crying, the conversation was over. I sat back and thought about it, beer in hand…if 2012 was all about teaching myself how to technically build a moderately complex SaaS product (and proving to myself that I could do it), then 2013 must be the year of putting the same effort into learning and becoming a good salesperson and marketer, EVERYTHING depends on this. 

I thought about it some more, it was only 13 months ago I was teaching myself to build a web-app in Django from scratch, it’s only a matter of practice and effort to get good at selling right?

Here’s my 7 point action plan to becoming a better hustler

1. Existing Customers

I’m going to approach all of my existing customers and politely ask for referrals. Given that customer acquisition costs are so huge for a new startup in the established, crowded B2B market where we are, it’s worth putting a process in place that rewards existing customers with a 20% discount for each new paying customer they can refer.

2. Old Clients

I’m going to approach the client network that I built up at my ex-employer. I was ethical enough to follow the terms of my 1 year non-compete clause but that expired last month so it’s time to actively chase my old network and show them what my new startup can do. People who know you personally are much more likely to lend a bit of their time for a demo or test drive and are much more willing to give constructive criticism.

3. SEO

Believe it or not, I used to think SEO was snakeshit until one of my co-founders recently put our site through the Google Webmaster tools. I was horrified by what I saw with regards to content keywords. While it might be aesthetically pleasing to humans to have a clean minimalist website with a simple message the (sad) fact is Google forces us to optimise for keywords. I’ve also collected enough analytics data in the last few months to know our website is not converting well. Luckily I launched early in September 2012 so I know this now.

4. More SEO

Related to the above point on SEO, I need to be generating worthwhile backlinks (not spammy ones) - this means I need to spend regular time on the forums and portals where my small business customers are likely to be found and publishing informative articles that marry their needs (online appointment and event scheduling) with my domain of expertise (SaaS) and do it all in a way that’s easily accessible to them.

5. Local door-knocking and cold-calling/emailing

Being physically present in the online age IS a point of differentiation. I tried some ‘cold selling’ towards the end of last year without much result but I wasn’t able to pin it down to whether it really doesn’t work or whether I was just crap at it. I think I need to persist at this to find out what works and what doesn’t before I write it off. Little things like doing a bit of research on a business before I cold approach them to see what their existing website looks like and what pain points they might have so I can tailor each pitch to each customer, at the very least if I can walk away with some feedback it’s worth my while. It’s expensive and slow but the reality is that a SaaS business is painfully built 1 customer at a time.

6. Vertical Channels

Like it or not, I will have to prepare for and pitch to vertical markets for a couple of ‘big hits’ that will go a long way to getting us profitable. My ‘800lb gorilla’ competitor in the yoga studio space is MindBodyOnline but that’s not going to stop me from pitching to say Yoga Australia and showing how I can help them and their members.

7. Networking

Last but not least, I need to go out and physically network a whole lot more, I’m going to set aside 3 hours a week for this (1 weekday evening) to go to various startup meetups in Sydney like Silicon Beach Drinks. You just never know what opportunities pop up when you meet new people. I was so absorbed in building and shipping that I (ignorantly) discounted the value of networking last year but now that I’ve changed my frame of mind from ‘building’ to ‘selling’, networking is something I need to invest more time in.

As a technical-ish/product founder, I wish I had the money to hire a good hustler to do all these things for me and more, I’m sure an experienced person would bring more to the table but as with everything in life there’s always intrinsic value in learning to do it yourself and getting relatively good at it. Here’s hoping my investment in getting good at selling in 2013 pays off, it’s the only thing I need to get good at…

3 notes &

What a relief…I have launched my MVP!

It’s called ZenBookings - it’s an online booking service for people who run classes like dance, yoga, fitness, cooking teachers and more. We provide them with a simple but elegantly designed website out of the box where they setup their class schedule and details and then lets their students/customers book in via the website.

I’m going to be expanding it soon to have what I call the ‘Open Availability’ model so professional service providers can use it too and let their customers book appointments with them from desktop or mobile browsers. But for now the MVP just targets class providers (otherwise it wouldn’t be an MVP would it?).

I use Fabric to do a ‘one command deploy’ for my Django App via BitBucket onto my production EC2 environment (more on this setup in an upcoming post) and let me tell you it was a strange mixture of relief and excitement to hit that <Enter> to make it all go live!


As a startup founder it is nothing short of a tough grind to go from idea to having a functioning product that the general public can use. Even an MVP is a grind to get out and at the end it’s a huge relief because:

  1. You get to the point where you have a functioning prototype and then you figure out it’s going to take more effort just to iron out all the little bugs that shouldn’t be there because even an MVP is no excuse for poor quality software.
  2. Every potential customer you pitch to is asking “When can I use it?” and the longer you leave it for the less likely you are to getting them onboard
  3. Friends and family are constantly asking you every time you see them about how your startup is doing, when you’re going to launch.
  4. The longer you go without launching the bigger that weed of self-doubt grows in the back of your mind - ‘Am I cut out to be a founder?’ - nothing kills that weed off like shipping. You go from ‘Can I do this’ to ‘I can do this!’


And this brings me to excitement - I’m well and truly excited because this is just the beginning. I look forward to:

  1. All the feedback people are going to give me. In my mind there’s no such thing as bad/negative feedback because all feedback leads to improvements in my product. 
  2. Being able to pitch to customers and watch them use my product straight away. It’s truly satisfying to think ‘I built that, and they’re using it!’.
  3. Not having to code all the time anymore because now we can go out to sell and hopefully get ramen profitable before too long.

So come check it out at ZenBookings - if you know anybody who might be interested please tell them about us, we really want to work closely with people who teach classes for a living cos I’m itching to keep making it better but I don’t want to do it without customer feedback. :)

P.S the <ol>s were just for you Jackson

6 notes &

Minimum Viable Ops - Deploying your first Django App to Amazon EC2

So you’ve learnt a bit of django, you’ve built some small, simple apps, you’re pretty confident with “./manage.py runserver” and the results at http://localhost:8000 are starting to make sense. Where to next? In this How-To I’m going to walk you through what I call ‘Minimum Viable Ops’ to get your app deployed onto Amazon EC2 for the first time.

You want to do this because:

  1. You want to show your friends and family what you’re working on by sharing a URL with them
  2. You’ll need to learn enough Ops stuff to build a proper production environment in the future, this is the first step
  3. You want to validate your prototype with prospective customers/beta testers by watching them use your app in the context of their own devices and browser. (similar to 1)
  4. It just feels awesome to deploy, especially if you turn this into a regular habit

So close your IM client, email, turn off your phone and close the HN and Reddit tabs in chrome, let’s get started…

*Disclaimer: all stack technology choices made in this post were made on the rationale of being maximally mainstream and minimally viable.

Launch your Free EC2 Amazon Machine Image (AMI)

First sign-up for Amazon’s EC2 service, it’s a pretty straightforward process where they ask you for some personal details, credit card and verify your identity via an automated phone call. Once you’re confirmed, you can log in to the AWS Management Console and go to the ‘EC2’ tab to fire up a free (for the 1st year) micro instance in the region that’s closest to you.

Now you’ll need to go through the classic wizard, in the ‘Choose an AMI’ step we’re going to use a Community AMI from Alestic. The folks at Alestic have been kind enough to setup Ubuntu to run securely on Amazon EC2 and create an image from that setup which we can simply load onto our instance.

  1. Go to the ‘Community AMIs’ tab and search for “ami-6da8f128” - that’s the ID for a 64 bit Ubuntu image in the US West-1 location. If you want to use a different location you’ll need to look up the correct ID on the Alestic page.
  2. In ‘Instance Details’ you’ll want 1 instance and you’ll need to choose the Micro Instance Type so it qualifies for the free tier.
  3. Next you’ll need to create and download a key pair which will enable you to SSH into your machine later.
  4. For the rest of the ‘Launch Instance’ wizard you can choose the default options presented and skip through to the end to launch it.

Allocate Elastic IP Address and Update Security Groups

Now we’re going to create allocate an elastic IP address to the machine instance we just launched so we can access the machine directly (via HTTP or SSH) over the internet. Go to the ‘Elastic IPs’ link underneath ‘Network and Security’ in the left sidebar and ‘Allocate New Address’. Now go to ‘Associate Address’ and choose the one and only machine that will appear in the dropdown.

This will give you an Associated IP address with which you can access your machine that you launched a moment ago. But before you do that you’ll need to edit your default Security Group so that it allows incoming SSH and HTTP requests. Go to ‘Security Groups’ then click on default and the ‘Inbound’ tab so you add the new rules for HTTP and SSH (If you have a static IP address for your home/office you should put that address into the ‘Source’ field for the SSH rule instead of Don’t forget to ‘Apply Rule Changes’.

At this point, it’s a good idea to go to your domain registrar (like Godaddy) to set the A record for one of your domains to point to your Elastic IP Address so you (and the people you show your app to) have something more friendly to work with rather than entering an IP address directly into their URL bar.

Ok - let’s test it out. You should be able to open a terminal, go to the directory the downloaded keypair resides in and SSH into your instance by doing:

chmod 400 MyKeyPair.pem; 
ssh -i MyKeyPair.pem ubuntu@mydomain.com

With the Alestic AMI, the user that’s setup for you to login as is called ‘ubuntu’. You can either use your domain or the IP address where I’ve typed ‘mydomain.com’. You should see something like this:

Install the Required Applications onto the EC2 Instance

Since we’re now able to SSH into our EC2 instance this is where the fun begins. We get to install the technology stack. For this tutorial we’re going setup Apache, Python/Django, PostgreSQL monolithically on the same machine to keep it as simple as possible and also stay within the free tier at Amazon.

Get latest package database and upgrade existing programs to latest version.

sudo apt-get update; sudo apt-get upgrade

Install Apache2 with WSGI

sudo apt-get install apache2 libapache2-mod-wsgi

Install Python Package Installer

sudo apt-get install python-pip

Install Django

sudo pip install django

Install Build Essential

sudo apt-get install build-essential

Install PostgreSQL server/client and PyGreSql, a postgresql module for python.

sudo apt-get install postgresql postgresql-client postgresql-contrib python-pygresql

Install Postgresql-dev-all (extension build tool) so you can build the psycopg extension (next)

sudo apt-get install postgresql-server-dev-all

Install Psycopg, Python Dev 2.7 (so our Django App can connect to PostgreSQL)

sudo apt-get install python2.7-dev; sudo easy_install psycopg2

At this point you Amazon instance now has a full technology stack (OS, web server, database server, Python/Django) that will allow you to run your app. The next 2 hurdles will involve configuring the web server and database server.

Configure Apache To Work With Django App

We’re going to configure Apache so it uses WSGI. Put simply WSGI is the middleware that allows Apache to serve up dynamic content from Django. We’ll also enable Apache to serve static files inside your project directly.

To do this you’ll need to edit /etc/apache2/httpd.conf. I kinda know my way around vim so I’ll be using that as the editor.

sudo vim /etc/apache2/httpd.conf

When you’ve opened the file in your editor you’ll need to add the following:

Alias /static/ /home/ubuntu/my-django-app/static/

<Directory /home/ubuntu/my-django-app/static>
Order deny, allow
Allow from all

WSGIScriptAlias / /home/ubuntu/my-django-app/apache/django.wsgi

Save the file and quit vim. What’s happening here is we’re telling Apache to serve the static files inside ‘my-django-app/static’. We’re also telling Apache to look inside my-django-app/apache/django.wsgi for the WSGI script. As you can probably tell we’ll be deploying ‘my-django-app’ directly into the home directory for ‘ubuntu’ but you can change this if you want.

Setup PostgreSQL Database for Django App

Now you need to setup a postgresql database for your app to use so it doesn’t use SQLite in your ‘production like’ environment (just for a bit of fun really).

Open PostgreSQL client from Linux command line

sudo su postgres -c psql template1

Change ‘postgres’ users password to ‘password’ and then quit the client:

template1=# ALTER USER postgres WITH PASSWORD 'password';
template1=# \q

In the terminal change the linux user ‘postgres’ password to ‘password’:

sudo passwd -d postgres
sudo su postgres -c passwd

Now login again to PostgreSQL client again

sudo su postgres -c psql template1

Create a database user and a database that your app will use:

postgres=# CREATE USER mydjangoapp WITH PASSWORD 'mypassword';
postgres=# create database mydjangoappdb;
postgres=# grant all privileges on database mydjangoappdb to mydjangoapp;
postgres=# \q

Edit the pgSQL conf file

sudo vim /etc/postgresql/9.1/main/pg_hba.conf 

Add following line to the bottom

local   mydjangoappdb     mydjangoapp                         md5

Restart the Postgresql server

sudo service postgresql restart

This sequence of commands will have created a database for which you’ll be able to put the details into the settings.py file of your app.

'Deploy' and Configure Your App

Chances are, if you’ve been developing and running Django apps on your local machine you probably haven’t thought much about how to get this code onto an Amazon server like the one you just built. The simplest way to do it is to use a code repository service like BitBucket with Mercurial. That way you can push the code from your own machine to BitBucket and then SSH into your Amazon machine to clone the whole repository or subsequently pull the updates from BitBucket.

Instructions for setting up a BitBucket repository and pushing your code there for the first time is outside the scope of this how-to. On your EC2 instance you’ll need to install Mercurial which will give you the command line tools to clone/pull your code:

sudo apt-get install mercurial

Then can clone your project by running this command in /home/ubuntu:

hg clone https://bitbucket.org/myusername/mydjangoapp

Before we get too excited just yet, there’s a couple of things we need to edit inside our app namely the settings.py file and adding the apache/django.wsgi file.


You’re using a postgres database now so we’ll need to change our database settings:

    'default': {
         'ENGINE': 'django.db.backends.postgresql_psycopg2',
         'NAME': 'mydjangoappdb',
         'USER': 'mydjangoapp',
         'HOST' : '',
         'PORT' : '',

You also setup Apache to serve your static files from your domain so you’ll need to ensure the STATIC_ROOT and STATIC_URL are set correctly

SITE_ROOT = os.path.dirname(os.path.realpath(__file__))
STATIC_ROOT = os.path.join(SITE_ROOT, 'static')
STATIC_URL = 'http://mydjangoappdomain.com/static/'

ADMIN_MEDIA_PREFIX = '/static/admin/'

Save and close your settings.py file.You’ll notice that I put ADMIN_MEDIA_PREFIX down the bottom, what we’re going to do here is symlink the Django Admin static assets to our static directory so they can be served too by Apache.

ln -s /usr/lib/pymodules/python2.7/django/contrib/admin/media /home/ubuntu/appointly/static/admin


Create a folder in your django app called apache and then create a file called django.wsgi (remember that our httpd.conf for Apache will be looking for this file). Then copy the following into the file:

import os
import sys

path = '/home/ubuntu/my-django-app'
if path not in sys.path:

os.environ['DJANGO_SETTINGS_MODULE'] = 'settings'

import django.core.handlers.wsgi
application = django.core.handlers.wsgi.WSGIHandler()

Save and close the file, we’re almost there… let’s do a syncdb in the app root directory so your tables get created in the postgres database.

./manage.py syncdb

And finally you need to restart Apache so it will serve up your app with wsgi.

sudo /etc/init.d/apache2 restart

Hooray! With any luck you should be going to http://mydjangoappdomain.com and see you your app running just like it does at http://localhost:8000 but now it’s running on a server in the cloud and accessible via the internet. Pretty f@#%$^ epic huh?

Where to from here???

So as I said at the beginning, this is a minimally viable setup for you to learn more about Ops and to do customer validation with your new app, you could possibly plug along like this and sign-up a few free pilot customers while spending most of your time on app dev before you need to come back to make changes to take this setup to the next level.

It’s in no way truly ‘web-scale production ready’, we’ve only taken the first step, there’s heaps of considerations that I haven’t taken into account here like:

  • Should I use Nginx or Apache for my webserver?
  • I need to serve static assets from a different machine, how do I do that?
  • Should I continue with Postgre or move onto Amazon RDS (MySQL), or should I setup MongoDB (a big architectural change)
  • Security concerns - to be honest I don’t know what I don’t know
  • Database Backups and disaster recovery

But you know what? I don’t have enough paying customers to start asking those questions yet, I don’t even have a single paying customer. Until then I’m spending my time building my MVP and doing customer validation.

Join the conversation at Hacker News.

Filed under amazon ec2 ops how-to

0 notes &

aptive asked: Hi Eddy, Read your interesting blog entry about learning python and django, found it on Hacker News. What caught my eye was that you are located in Sydney and doing a Startup. I wanted to ask if you are involved in meetups with other enterpreneurs, and whether it's worth it. I am located in Melbourne, but wanted to make the move to Sydney and also bit of a career change to a smaller company. Cheers, Ivo.

Hey Ivo, to be honest I haven’t been huge on going to meet-ups, not as yet anyway simply because I need to be focusing all my time on building my product right now to get to MVP.

I’m actually building a SaaS online booking/reservation tool for small businesses but doing it right unlike all the other bazillion offerings that are out there right now. Once I’ve got a beta to show people and a story to tell then (2 most important things for networking) I’ll be hitting the streets and going to things like Barcamp, Pycon, Open Coffee meetup and Silicon Beach drinks as well. But in my mind this comes 2nd to spending time meeting customers in my list of priorities. Meeting customers is more important than meeting other entrepreneurs.

My personal startup network consists of a few friends who were in Startmate 2011 and built Noosbox, I also know some of the ‘Aussie Mafia’ in Silicon Valley cos I used to work with them in SF.

Hope that helps!