Monthly Archives: July 2012

31Jul

Mechanics of a Small Acquisition

When a startup successfully exits, chances are it was an acquisition. Unfortunately for the founders, that acquisition was likely their first, while the acquirer has probably gone through many. This was the case with Stypi. Fortunately, my cofounder and I were lucky enough to have had access to several other acquired founders who helped us ultimately navigate our first multimillion-dollar exit for a company barely a year old. Hopefully by sharing what we learned and encountered, you can be slightly less lost, should you be faced with an acquisition of your own.

DISCLAIMER: Every startup and founder group is unique so the data provided here may not apply in all cases. In particular, it is skewed towards < $25m acquisitions made by much larger companies. An acquisition is important enough that you should always do your own research. Reach out to acquired founders in your space, company size range, and/or acquired by the same company that may acquire your company. If any of these apply to me feel free to contact me at jason [at] stypi [dot] com.

First Contact

Potentials acquirers are a lot like the opposite sex: their intentions are confusing but the prospects are exciting. It will likely be a founder or the Corporate Development department of a larger company, acting on behalf of an interested internal team, that first approaches you. Either way, get comfortable with this person, as he/she will be setting up and facilitating your meetings, and will likely be the one you eventually haggle with over terms.

Before moving forward, it is worth noting that the cost of pursuing an acquisition is nonzero—in fact, it’s quite high. You and your cofounder(s) will be consumed by the process for weeks and divulge a lot of otherwise private information to potential competitors. But, more importantly, rejection hurts. Believing that the finish line is just yards away and finding that it is actually miles is not going to be good for your company’s morale.

Courtship

Assuming the decision is to open your company’s kimono and pursue an acquisition, you and your cofounder(s) will end up going on a series of meetings with the potential acquiring company (except at the pace of trying to decide if you want to get married by the end of the week). For larger companies, Mutual NDAs will likely be signed by the first meeting. Decisions to continue the relationship are made very quickly after each meeting. This of course goes both ways—we decided to end the relationship early with more than half of interested potential acquirers.

If feelings are positive on both sides, arrangements would be made to meet again, probably with different people. Regardless of who we were meeting with, they were usually available the next or following day, which seem to suggest the priority for acquisition meetings are reasonably high. One founder, we discovered, cancelled racing Audi R8s to meet with us.

The Term Sheet

We averaged three to four of these dates before we were invited into bed with a term sheet. The relationship is not exclusive so it is kosher and advisable to be pursued by multiple potential acquirers in parallel. Ideally they would be lined up such that multiple terms sheets would come at roughly the same time. Different companies prefer to have varying amounts of information or certainty before putting together a term sheet. In general, the time spent or saved here will be made up for during due diligence. But, for your purpose of timing the term sheets, it is not unreasonable to ask about the potential acquirer’s timeline and form expectations.

Once you get your first term sheet, it’s time to celebrate with your cofounder(s). If the offer is interesting enough, then it’s also time to get a lawyer. Ideally other offers will soon be coming in and you can use them to get better terms from each company. While you will be negotiating the key terms, your lawyers will be taking care of less familiar ones like escrow, indemnification, etc. They’ll explain what this means, the consequences, and for significant ones, ask how hard you want to push for more favorable terms. For these, we usually just asked them to push for market terms.

It took us roughly a week to agree on the terms and decide which company Stypi would join.

Due Diligence and Closing

Now it’s time for monogamy. When you sign a term sheet there will also be a separate exclusivity agreement that requires you to reject any other outstanding offers and for a period of 45 days, remain faithful and not solicit other offers. There will be more meetings and every document your company has ever signed will be scrutinized (which your lawyers will want to screen before sharing) to make sure you did not misrepresent your company’s position. This process should be taken seriously as either party can still back out of the deal. But the default outcome is that the deal will close and unless you are hiding something big, like a lawsuit or stealing code, there shouldn’t be anything to lose sleep over.

In parallel with due diligence, weighted towards the tail end, preparations will begin for closing. Mechanically this means filling out and signing a lot of forms. A lot of time will be spent chasing down information from people connected to your company, for example your advisors’ addresses or investors’ wire instructions. Many will need signatures so there might actually be some physical chasing down.

The complexity of the deal or parties involved will dictate the time frame but for small companies, this process will take roughly 3-4 weeks.

Exit

What happens after exit is entirely up to up to you. Life can be as different or as similar to what it was before. Some founders take time off, some throw massive parties, and others buy and crash brand new Lamborghinis. For Stypi, life has not changed very much and we went straight to work the day after closing. We still have a long way to go before Stypi becomes what we envisioned and we chose an acquirer that shares and wants us to pursue that vision unencumbered.

8Jul

Optimizing WordPress Performance

Good programmers know the dangers of premature optimization; but even my techiest friends are surprised to find how little horsepower it takes to bring down their site. Let’s find out how much:

>> siege http://www.blog.com -t30s -c10 -b
** SIEGE 2.70
** Preparing 10 concurrent users for battle.
The server is now under siege...
Lifting the server siege... done.
Transactions: 389 hits
Availability: 100.00 %
Elapsed time: 29.40 secs
Data transferred: 2.76 MB
Response time: 0.75 secs
Transaction rate: 13.23 trans/sec
Throughput: 0.09 MB/sec
Concurrency: 9.90
Successful transactions: 389
Failed transactions: 0
Longest transaction: 1.21
Shortest transaction: 0.50

The blog was only able to handle an unlucky 13 requests per second. That’s it. In reality that number will be even lower because of additional content and plugins installed. Thus the average latop today can easily bring an unoptmizied WordPress blog to its knees. However with a few simple optimizations, you can more than 10x the amount of traffic your blog can support.

Even if you are not worried about DoSers or jealous (and tech savvy) girlfriends, making the site fast and responsive improves the user experience. You’ll also never have to worry about posting something too popular that your blog buckles under the surge of interested readers. We’ll do this by optimizing the backend with WP Super Cache and Varnish and optimizing the frontend with compression and WP Minify.

Test Setup

All tests are run against a newly installed WordPress (v3.4.1) site running on a Linode 512 (512MB RAM) served by Nginx (v1.2.2). For exact setup/configurations, refer to my Installing WordPress on Linode guide. I have edited my hosts file to point www.blog.com to this server (I unfortunately don’t actually own that domain).

Thoughout this post, I will be using Siege and Google PageSpeed Insights to benchmark our progress.

Disclaimer: Only benchmark sites you own or have explicit permission to do so. Otherwise it can be viewed as an attack which will put you in loads of trouble with your parents (and the law).

Backend Optimizations

Two easy ways to optimize the backend are installing WP Super Cache or Varnish. You get more mileage out of Varnish and it’s a general purpose solution but it’s slightly harder to install and set up. I’ll go over both but feel free to skip the WP Super Cache section if you intend on just using Varnish.

WP Super Cache

WP Super Cache is just a WordPress plugin so just install it like any other WordPress plugin and enable it with basic settings. Now let’s lay siege:

>> siege http://www.blog.com -t30s -c25 -b
** SIEGE 2.70
** Preparing 25 concurrent users for battle.
The server is now under siege...
Lifting the server siege... done.
Transactions: 4555 hits
Availability: 100.00 %
Elapsed time: 29.82 secs
Data transferred: 32.89 MB
Response time: 0.16 secs
Transaction rate: 152.75 trans/sec
Throughput: 1.10 MB/sec
Concurrency: 24.92
Successful transactions: 4555
Failed transactions: 0
Longest transaction: 1.39
Shortest transaction: 0.09

A whopping 11x improvement! WP Super Cache saves us from the biggest bottleneck which is the database, and as you can see it’s quite significant. But we can do even better.

The astute observer will notice that I changed the concurrency from 10 to 25. The reason is if the server is responding faster than we are requesting, we are not truly testing the full limits of the server. However if we send too fast, the server will choke. So while I only show one siege result, I have actually run several trials and am only posting the optimal one.

Varnish

Varnish will sit in front of Nginx and cache requests, so it can skip Nginx and everything behind it (which includes WP Super Cache). Thus Varnish is a general purpose solution that can optimize any site, not just WordPress. It’s not quite as easy to set up but still relatively simple. To install: yum install varnish

Now open up /etc/sysconfig/varnish and find the line VARNISH_LISTEN_PORT and set it to 80

VARNISH_LISTEN_PORT=80

Now edit /etc/varnish/default.vcl and replace the backend port with a high one of your own. I will use 8080:

backend default {
  .host = "127.0.0.1";
  .port = "8080";
}

Now go to all your nginx configuration files and change it to listen on this custom high port instead of 80. Which means /etc/nginx/nginx.conf, /etc/nginx/sites-available/*, and /etc/nginx/conf.d/*. Now restart nginx (service nginx restart) and start varnish (service varnish start) and let’s lay siege again:

>> siege http://www.blog.com -t30s -c50 -b
** SIEGE 2.70
** Preparing 50 concurrent users for battle.
The server is now under siege...
Lifting the server siege... done.
Transactions: 4912 hits
Availability: 100.00 %
Elapsed time: 29.54 secs
Data transferred: 35.47 MB
Response time: 0.28 secs
Transaction rate: 166.28 trans/sec
Throughput: 1.20 MB/sec
Concurrency: 45.90
Successful transactions: 4912
Failed transactions: 0
Longest transaction: 5.65
Shortest transaction: 0.07

We managed to squeeze another 12 requests/second over WP Super Cache!

Frontend Optimizations

While siege is fun, most of the sluggishness a user experiences is on the frontend. Google PageSpeed Insight is a great tool to find out ways we can improve on this front. After installing and running we can see we need to enable compression and optimize our css and javascript.

[pagespeed-74.jpg

Compression

To enable compression, open your nginx configuration /etc/nginx/nginx.conf and uncomment the line #gzip on and add the following:

gzip on;
gzip_http_version 1.0;
gzip_vary on;
gzip_comp_level 6;
gzip_proxied any;
gzip_types text/plain text/html text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript application/javascript;
gzip_buffers 16 8k;

Minify and Combine JS/CSS

To minify/combine javascript and css, just install and the WP Minify plugin. The plugin misses some files, ex. theme files, so for those just go to WP Minify’s settings -> “Show Advanced Options” -> and enter each file into the “Non-Local Files Minification” textarea.

We rerun PageSpeed Insight and get an almost perfect 99/100.

[pagespeed-99.jpg

With just these simple optimizations of installing Varnish/WP Super Cache, enabling compression, and js/css minification, your blog can handle hundreds of requests a second and load with blazing speed on the browser. Now that being slashdotted is no longer a concern, off you go to write some content to go viral!

6Jul

Installing WordPress

WordPress has a fairly straightforward installation process, but we first need to prepare the web and database servers. WordPress requires only the LMP of LEMP but this guide is targeted towards Nginx users (sorry Apache). We will cover the Nginx configuration, MySQL setup, and finally the WordPress installation itself.

Nginx

Ideally you are separating your nginx configuration files per site, which you are if you followed my LEMP setup guide. Create and enable a new configuration for the new WordPress blog:

cd /etc/nginx/sites-enabled
touch /etc/nginx/sites-available/jasonchen.me.conf
ln –s ../sites-available/jasonchen.me.conf jasonchen.me.conf
vim jasonchen.me.conf

If you are using a single configuration file, it is most likely in /etc/nginx/nginx.conf. Open it with your favorite text editor:

vim /etc/nginx/nginx.conf

Now paste the following lines into the new file or between the http block:

server {
    listen      80;
    server_name www.jasonchen.me;
    access_log  /var/log/jasonchen.me/access.log;
    error_log   /var/log/jasonchen.me/error.log;
    root        /opt/jasonchen.me;
    index       index.php;
    location = /favicon.ico {
        log_not_found off;
        access_log off;
    }
    location = /robots.txt {
        allow all;
        log_not_found off;
        access_log off;
    }
    location / {
        try_files $uri $uri/ /index.php;
    }
    location ~ \.php$ {
        include       /etc/nginx/fastcgi_params;
        fastcgi_pass  127.0.0.1:9000;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME /opt/jasonchen.me$fastcgi_script_name;
    }
    location ~* \.(js|css|png|jpg|jpeg|gif|ico)$ {
        expires max;
        log_not_found off;
    }
}
server {
    listen  80;
    server_name jasonchen.me;
    server_name_in_redirect off;
    rewrite  ^ http://www.jasonchen.me$request_uri?  permanent;
}

This essentially tells nginx to serve a website named www.jasonchen.me, with php support. Static files are served directly and not logged. All traffic to jasonchen.me will also be redirected to www.jasonchen.me. We should now create the log directory for nginx, create a dummy index.php file to test this configuration, and restart nginx.

mkdir /var/log/jasonchen.me
mkdir /opt/jasonchen.me
echo "<?php phpinfo(); ?>" >> /opt/jasonchen.me/index.php
service nginx restart

Now if you visit your site from a browser, you should see the purple php info page.

MySQL

For security, we are going to create a separate MySQL user and database for wordpress. To do so log in as an admin:

mysql –uroot –p

and enter in your password. Now in the mysql console, we will create a database and a dedicated user with permissions only for that database:

create database wordpress;
create user 'wordpress'@'localhost' identified by 'password';
grant all privileges on wordpress.* to wordpress@localhost;

Now make sure this works by logging in exiting out of the current mysql root console (CMD+D) and logging in as your new user:

mysql -uwordpress -ppassword

If you get the mysql console we are now finally ready to install WordPress.

WordPress

Now let’s navigate to the installation directory and remove the dummy php test we added earlier:

cd /opt
rm jasonchen.me -rf

Next, download wordpress, extract and rename it:

wget http://wordpress.org/latest.tar.gz
tar -xvf latest.tar.gz
mv wordpress jasonchen.me

WordPress should now work but we will want to fix the file ownership so they are owned by apache.

chown -R apache:apache jasonchen.me

This way you can easily install plugins and updates from the web interface. Why apache and not nginx? Php-fpm runs under the user apache by default. You can change this in /etc/php-fpm.d/www.conf if you would like.

Now visit your blog in the web browser and follow the instructions and you should be set to configure your new blog!

I’ll leave most of the customization up to you but will mention one. By default posts are in the form jasonchen.me/?p=123. However most people want readable URL’s like this: jasonchen.me/2012/07/sample-post/. WordPress almost does this for you but they include index.php in the name: jasonchen.me/index.php/2012/07/sample-post/.

If you want to get rid of index.php just select “Custom Structure” in the Permalink Settings page: jasonchen.me/wp-admin/options-permalink.php and change enter in /%year%/%monthnum%/%postname%/ in the textbox. If you followed the nginx configuration instructions above, your web server is already configured to handle this.

Congratulations on your new and now fully functional WordPress blog!

If you want to make it blazing fast, check out my Optimizing WordPress Performance guide.

© Copyright 2013, All Rights Reserved