Software Cubes by Juan Jaramillo

16Dec/102

How to run Ubuntu on AWS EC2

This article is pretty outdated now.  This have improved a lot and it's pretty easy to get going with Ubuntu on AWS EC2. These notes should be enough to get you up and running:

  • It's always safer to use Canonical's official AMIs
  • You don't need an elastic IP in most cases (contrary to what my original post said) the instance's default domain name works fine
  • When connecting for the first time with your key, you want to log in as user "ubuntu" and not "root" (right click on your instance on the AWS console and click "connect", then copy the command and change the username to "ubuntu"
  • Make sure you've given yourself access to port 22 in the security group you put your instance in so that you can ssh in.
Other than that, the process is pretty straightforward.

 

----

Original post:

 

 

I have been working with AWS lately and I really like it. However, I found a few unclear steps when setting up an Ubuntu server on EC2. I couldn't find many useful guides when I was doing this and so I decided to put one together for future reference.

Setting up an Ubuntu Server on Amazon Web Services' EC2:

Please bear in mind that this guide assumes you're using the AWS Management Console. There are other ways to accomplish this, but this is probably the easiest way to get started. Please also note that this is not a comprehensive guide to EC2, Amazon has an excellent documentation & support community.

1 - Find the Ubuntu AMI you want to install

EC2 systems are based on AMIs (Amazon Machine Image) which consist of a pre-installed operating system snapshot and some meta-data. I've found that the most trusted, reliable, and straightforward way to get Ubuntu running on EC2 is to go with Canonical † Ubuntu AMIs.

The first step is then for you to decide what image you would like to use. Each AMI is specific to an availability zone and an EC2 Instance Type. For this example I've selected m1.large as the type of instance I want to install, and us-east-1 as the availability zone. Please note that m1.small instances should also allow you to set up m1.micro instances, and that m1.large instances should work for larger instance types.

Go to the AMI releases page, select the version of Ubuntu you'd like to use, then copy the number under the "ami" column.

2 - Locate the AMI on the AWS Management Console

Once in the management console, click on "Launch instance", then select the "Community AMIs" tab and wait until the list is loaded.

On the search input box, type the code you copied from the Canonical page, e.g. ami-4a0df923. Once the image is located, click on "Select"


3 - Configure your instance

Continue with the launch process by selecting the instance type (It will give you more options that the ones the AMI was designed for). As far as I know you can use any type that is available on the list. If you haven't already, make sure you create a key-pair and download the pem file.

As for the firewall configuration select "default", unless you already have a security group that allows port 22 connections from wherever you will be accessing your sever.

Click "Launch"


4 - Connecting to your new server

Once the instance is running, assign an Elastic IP to it by first provisioning one from the "Elastic IPs" section of EC2, and then right click on it and select "Associate address". A meny will appear showing you your EC2 instance.

You will also need to go into your "Security Groups", click on the group you selected for your instance (in my case "default") and add a custom rule like so:

Just replace 12.34.56.78 with your ip addres... /0 means only that ip address matches that rule.

Having done that, go back to your Instances screen and right click on the instance you just created. Then select "connect". You will get a dialog with some instructions which you can follow, except for the command it asks you to execute:

ssh -i mykey_goes_here.pem [email protected]

For Ubuntu images you should use:

ssh -i mykey_goes_here.pem ubuntu@ec2-12-34-56-78.compute-1.amazonaws.com

And I've also found that sometimes the host provided does not work immediately, so it's better to just use the associated elastic ip address:

ssh -i mykey_goes_here.pem ubuntu@34.56.78.90

Note: If you are using PuTTY from Windows, you may have to convert the pem key to a different format. (I might post the details once I get to try that, as I've only been accessing my instances from Linux).

Also note that once you are connected, you can edit /etc/ssh/sshd_config and enable PasswordAuthentication so that you can connect directly with a password. This is more convenient, but a notch less secure.

Filed under: Uncategorized 2 Comments
11Mar/108

How to install Teambox on Ubuntu using Passenger, Apache and SendGrid

Teambox is a project collaboration tool written in Ruby. They offer a hosted version, which is likely a good choice, but I wanted to install it on my own server for more flexibility and for testing purposes.

I found that the official Teambox installation guide is too basic and perhaps incomplete, especially for someone who is deploying a Ruby on Rails project for the first time like me. I could be more critical of the documentation and resources offered, but I decided to cut the developers some slack because it's a fairly new project and because they've done an amazing job with the application itself. I am sure the documentation will become more and more comprehensive over time.

In the meantime, I decided to publish my own guide hoping to help other new users and the community itself. Update: An official installation wiki has been made available by the Teambox guys. It's based on this article, but being a wiki will make it more dynamic and current.

Update 2: If you are having issues uploading files (avatars, attachments, etc) do the following (after installing everything):

mkdir --mode=777 /websites/teambox.mydomain.com/public/avatars
mkdir --mode=777 /websites/teambox.mydomain.com/assets

Thanks GIT, for not supporting empty folders :).

(Relevant) Server Specifications:

  • Linux - 2.6.24-26-generic #1 SMP Tue Dec 1 18:37:31 UTC 2009 i686 GNU/Linux
  • Ubuntu 8.04.3 LTS

Installing necessary software:

The following packages are required at some point during the installation:

sudo apt-get update
sudo apt-get install apache2 mysql-server imagemagick git \
 git-core ruby rake rubygems libdbd-mysql-ruby \
 libmysql-ruby liberuby-dev libopenssl-ruby1.8 \
 apache2-prefork-dev

Please note:

    • apache2 and mysql will likely already be on your server. I am assuming you have a mysql user account that can create databases.
    • If you already have some of these packages installed, executing the above will update them if there is a new version. This may cause unexpected results - so beware of that.
    • I did my first install on a 9.10 server on which I was able to install "ruby-dev" instead of "liberuby-dev"
    • Package names may be different in other versions of Ubuntu. I use Package Search for reference.

(Ubuntu 8.04 only) Upgrade to Ruby 1.8.7

After installing Ruby, I noticed that I ended up with v 1.8.6 (run ruby -v to check), but Teambox requires 1.8.7. So after some looking around, I found the solution:

cd /usr/src
wget http://archive.ubuntu.com/ubuntu/pool/main/r/ruby1.8/ruby1.8_1.8.7.174-1_i386.deb
wget http://archive.ubuntu.com/ubuntu/pool/main/r/ruby1.8/libruby1.8_1.8.7.174-1_i386.deb
wget http://archive.ubuntu.com/ubuntu/pool/main/r/ruby1.8/ruby1.8-dev_1.8.7.174-1_i386.deb
wget http://mirrors.kernel.org/ubuntu/pool/universe/libx/libxml-ruby/libxml-ruby1.8_1.1.3-1_i386.deb

sudo dpkg -i libruby1.8_1.8.7.174-1_i386.deb ruby1.8_1.8.7.174-1_i386.deb ruby1.8-dev_1.8.7.174-1_i386.deb libxml-ruby1.8_1.1.3-1_i386.deb
sudo install ruby

You can skip this step if you are running Ubuntu 9.04+ (Ubuntu 8.10 might work too, I am not sure).

Check out a copy of Teambox from git.

I am installing Teambox in /websites/teambox.mydomain.com, so I will check out a copy of their stable branch:

git clone git://github.com/micho/teambox.git teambox.mydomain.com

(You may want to check the official Teambox installation guide for up to date info on this, but it's unlikely to change much)

Install required gems:

 gem update
 gem update --system
 gem install -v=2.3.4 rails
 gem install RedCloth
 gem install mime-types
 gem install sprockets
 

Configure Teambox:

Edit:

  • ./config/teambox.yml
    • Set your domain
    • Set email information
      • For sendgrid, use:
        • host: smtp.sendgrid.net
        • username: [email protected]
        • password: your_password
        • auth: plain
        • port: 25
        • enable_starttls_auto: false
      • I could not get this working using a local postfix server without authentication.
  • ./config/databases.yml
    • Set your database user and pass under production. (Others are optional)

Build the database:

Replace the =production with =development if you want to build the development environment as well.

RAILS_ENV=production† rake db:create
RAILS_ENV=production† rake db:auto:migrate

Install Passenger:

sudo gem install passenger
sudo passenger-install-apache2-module

create or edit: /etc/apache2/mods-available/passenger.conf:

PassengerRoot /usr/lib/ruby/gems/1.8/gems/passenger-2.2.11
PassengerRuby /usr/bin/ruby1.8

create or edit: /etc/apache2/mods-available/passenger.load:

LoadModule passenger_module /usr/lib/ruby/gems/1.8/gems/passenger-2.2.11/ext/apache2/mod_passenger.so

Enable mod_passenger:

cd /etc/apache2/mods-enabled
ln -s ../mods-available/passenger.* ./

Restart apache: sudo /etc/init.d/apache2 restart

Sample vhost:

<VirtualHost *:80>
 Options +Indexes
 ServerAdmin [email protected]
 ServerName teambox.mydomain.com

 DocumentRoot /websites/teambox.mydomain.com/public

 <Directory /websites/teambox.mydomain.com/public>
 Options Indexes FollowSymLinks
 AllowOverride All
 Order allow,deny
 Allow from all
 Options -MultiViews
 </Directory>

 RailsEnv production
 #RailsEnv development

</VirtualHost>

Enjoy!

Filed under: How To 8 Comments
16Feb/100

Grow your application organically, not forcefully

Software applications and organisms grow in a very similar way. A newborn human baby lacks a significant number of the abilities that most adults have. If babies reached adulthood in the wound, the mother would†literally explode; which is exactly what happens to software companies that try to include a large percentage of their overall feature-set in version 1.

The resulting abomination is not quite a baby, nor an adult. This humanoid looks like a grownup but he can't quite run correctly, often fails to respond and will undoubtedly end up in life support eventually. Similarly, a prematurely grown application will very rapidly start getting out of hand and you'll be riding the fail train faster than you can say epic.

There is a way though. Applications should be developed organically and knowing from the beginning that your brain can envision features much faster than you can implement them.

Implement the core first. The first step is to identify and isolate the core or "soul" of your application. Which of the problems your application is solving are the most important ones, and which functions are absolutely critical for solving them? This is the trickiest part, as in the midst of the excitement of having come up with what seems to be a super-awesome idea people tend to think that all of the items on the list are crucial. While that may be true in some cases, most applications (even simple ones) have plenty of room extra ideas to be conceived. Sometimes it gets to the point where you don't think you will be able to attract users (paying customers or otherwise) unless you have every single thing that you thought of as a feature. You're most likely wronger than Wrong W. Wrongenstine.

Remember that "version 1 sucks, but ship it anyway". If your application is useful and you've succeeded at identifying its core, users will likely don't care too much that you haven't implemented X or Y feature. You will have more opportunities to surprise them down the road and you will be able to use their feedback sooner which may help you focus your valuable time on features that are more likely to increase the value of your application.

Involve your audience early. Even though it is true that users often don't know what they want, exposing your ideas to people who are not involved in developing the application will help you make it more usable and it might also uncover some points you hadn't thought about.
Every release cycle can benefit from real feedback, and it will give users a feeling of control and empowerment.

Engage your team with the core of your application. Make sure that every single developer understands intimately what the core "values" of your application are. If they understand the spirit of each feature they're developing, your overhead will be largely reduced. Let me explain; Developers are usually very creative people. In fact, our job consists mostly of solve problems. For that reason, the only 2 approaches that tend to work are to either tell each developer exactly what to do and how to do it or to have a team that understands what they're doing. The latter gives developers the freedom to do what they're best at with less guidance.

Prototype, then build. There are several excellent prototyping tools, like Axure RP and Balsamiq Mockups. I personally use both because each of them has a very specific function. Axure is great for creating navigable interfaces where a button or link will actually take you to the right screen. It produces a realistic application that will enable you to identify functional issues that sometimes require major restructuring of the code. Balsamiq is a much simpler tool that is best suited for one-screen, quick mock-ups. Its biggest limitation is its best feature. Balsamiq is "ugly" by design, in the sense that it will not let you slow yourself down focusing on lining things up to the pixel. The goal here is to identify the elements and overall positioning of all the items on a screen.

Once you've identified the tools you want to use (even pen and paper are acceptable), it's important to make it a habit to prototype any screen that you'll be building. Going through the exercise of building a screen will almost always uncover some functional details that again, might require a modifications to the design of your back-end code.

The core is ready, what next?. Once you've reached version 1.0, apply the above steps to each addition but making sure that anything you add should be in line with the ideals of your core. At this point, it will likely be easier to continue growing because you've cleared the most difficult hurdle. you may start treating each major feature as a whole project and apply the same steps over and over again.

Filed under: Uncategorized No Comments
9Feb/100

Time-saving practices for software developers

How much effort should you put into developing robust day-to-day work practices? Basically, if you're serious about software development, then it's logical that you will want to spend most of your time and energy doing actual work rather than worrying about re-writing code you've lost, figuring out how to fix your recently compromised server or re-installing your operating system because your hard-drive crashed.

Design it well, do it once, and re-use it. Even though you want to continuously tweak your overall procedures, you don't really want to re-invent†the way you do simple tasks every time you run into them. It is important to come up with a framework that works well and leverage it every time you can.

My top practices to implement are (in no particular order):

  • Use a RAID in your main development workstation. Virtually all motherboards nowadays come with built-in software raid controllers. Combine these with 4 hard drives in RAID-10 and you'll get both better performance and protection against single-drive failure.
  • Set up a daily full system backup. The above gives you a degree of protection, but other things can go wrong - like dual-drive failure or a virus. Adding an external USB drive and setting up a full system image is trivial and fairly cheap. On Windows, Acronis True Image works very well and you only have to set it and forget it.
  • Use version control. I would say that not using some form of version control is absolutely unacceptable for any good developer, let alone an organization. Get in the habit of using version control for every piece of code you work with and you'll never have to worry about overwriting a newer copy. Additionally, using version control give you the freedom to make experimental changes of any magnitude to your code base without worrying about how to get back if something goes wrong. Two free options are subversion and git.
  • Set up automatic database backups. Find out how to set up an automatic, full database backup. Having snapshots of your development database is sometimes important. This takes very little time to set up and it'll pay for itself the first time you accidentally delete an entire table off your database. This is a quick backup script for MySQL.
  • Use a password manager. Keeping passwords in unencrypted media such as email, documents, outlook notes or even worse sticky notes on your screen is sloppy and most importantly ineffective. Your job inherently requires many passwords and keeping them secure and indexed is the logical way to go. There are many password managers. I use KeePass because it's open source, free and easy to use. There are other alternatives, but I'd stay away from closed-source and web-based tools unless you've built them yourself. Oh yea, and don't even think about using the same password everywhere. You might alter time space-time†continuum.
  • Use a file-sync manager. Having access to some of your files is sometimes vital. There are several ways to keep a folder synchronized†across†all the computers you use regularly. Dropbox is my favourite one because it ties right into the operating system's native file management. I use it to store manuals, portable applications, and to share some resources with my team. It's a real time-saver.

The above recommendations are very high level and mostly focused on the tools we use on a daily basis. If you'd like to explore more in-depth practices, I'd recommend the Joel Test: 12 steps to better code. I have also written about habits of efficient programmers.

Filed under: Uncategorized No Comments
3Oct/090

Generating a function call hash in php for caching purposes

It†is sometimes necessary to generate a signature for a specific function call. For example, in the case of function caching, this signature is what you would use as your unique key for storing the output in the cache.

A function call hash is a string that uniquely identifies a function call. Let's examine some examples:

	function addNumbers( $summand_1, $summand_2 ){
		return $summand_1 + $summand_2;
	}

	$result = addNumbers( 2, 3 );
	// The function signature for this function would uniquely identify
	// [class name (if applicable)] & function name & value of each argument
        // (2 and 3)

	$result = addNumbers( 21, 48 );
	// The function signature for this function would uniquely identify
	// [class name (if applicable)] & function name & value of each argument
        // (21 and 48)

It is desirable to have a straightforward way for generating these hashes that requires as little information to be manually provided as possible. The following is an implementation I wrote some time ago.

    class FunctionTools {
        /**
        * Generates a unique identifier for a specific function call,
        * taking its parameters into consideration.
        * Function name, and parameter values* are made into a hash along with
        * a $salt if provided.
        * * Parameter values for non-scalar types are calculated based on size. This
        *   may not be accurate enough, so the use of a salt is recommended.
        *
        *
        * @param mixed $salt String to further individualize a signature.
        * @param mixed $hash_algorithm if null, the raw identifier is returned..
        *   if algorithm name, like sha1, it'll hash the result.
        * @returns string A uniqe function call signature.
        */
        public static function getFunctionCallSignature( $salt = '', $hash_algorithm = 'sha1' ){
            $debug_backtrace = debug_backtrace();
            $debug_backtrace = $debug_backtrace[1];

            if( empty( $debug_backtrace['function'] ) ){
                throw new Exception( 'Invalid call to ' . __FUNCTION__ . ' from a non-function context.');
            }

            $elegible_args_values = '';

            foreach( $debug_backtrace['args'] as $arg => $arg_value ){
                if( is_scalar( $arg_value ) ){
                    $elegible_args_values .= $arg . '_' . $arg_value . '_';
                } else {
                    $elegible_args_values .= $arg . '_' . sizeof( $arg_value )  . '_';
                }
            }

            $hash_parts =
            $salt .
            $debug_backtrace['class'] . '_' .
            $debug_backtrace['function'] . '_' .
            $elegible_args_values;

            if( !empty( $hash_algorithm ) ){
                return hash( $hash_algorithm, $hash_parts );
            } else {
                return $hash_parts ;
            }
        }
    }
Filed under: Uncategorized No Comments