Customizing an AMI on Amazon EC2…

This will guide you though creating a customized AMI on Amazon EC2.


This is mostly for the benefit of those in the class who read this post. I’m writing this mostly as a tutorial instead of a “what I did” because I’m only going to give enough instruction to get something running, not tell you all the tinkering I did. I also apologize for the varying tense of the writing. Some steps got written before and some after I had actually done them.

I’m going to be setting up my server instance using the latest instance from Ubuntu as my starting point. I’ll also go over how I set up my computer, a MacBook Pro running Mac OS X 10.6.6.

For those not in the class, I’m running my instance on the US East Region, so any AMI IDs mentioned refer to that region. And of course, you’ll need to change bucket names and file names if yours are different.

Here’s the specs of my finished AMI:

  • Ubuntu 10.10 (Maverick Meerkat) Server 32-bit
  • Apache 2.2
  • PHP 5.3
  • mod_python (just like the TA…just in case)
  • Smarty template engine

Before we begin

The first thing I did was create a key pair. You can do this when you set up your first instance, but if you get it out of the way first, it’s easier to get your whole computer setup out of the way. Generate the key pair. We’ll use it pretty soon.

You’ll also need the private key and certificate. You’re not going to get anywhere without these things. Once you’ve got them, we can begin.

Computer Setup

I’m using a Mac. I found a great little tutorial that I used to setup my laptop. Here’s the steps I took to setup my laptop with a few, but not all of the commands I used.

  1. Open up a new terminal window. Create a new directory .ec2:
    mkdir .ec2 
  2. Copy the private keys into this directory. Once there, cd into the directory and change the permissions to user readable only:
    cd .ec2/ chmod 400 *.pem 
  3. Now download the Amazon EC2 API Tools and copy the bin and lib folders into the .ec2 directory. I guess you don’t need these to start an instance or anything, but they can only make your life easier. I also deleted the cmd files from the bin, this isn’t Windows:
    rm bin/*.cmd 
  4. You’ll have to setup some environment variables in order to use these tools. Open up your bash profile (vi ~/.profile for me) and add the following lines:
    # Setup Amazon EC2 Command-Line Tools export EC2_HOME=~/.ec2 export PATH=$PATH:$EC2_HOME/bin export EC2_PRIVATE_KEY=$EC2_HOME/PrivateKey.pem export EC2_CERT=$EC2_HOME/X509Cert.pem export JAVA_HOME=/System/Library/Frameworks/JavaVM.framework/Home/ 
  5. When you launch your instance, you’ll want to SSH into it, and to help me out, I added these lines to my ~/.ssh/config file:
    Host ec2-* HostName User ubuntu IdentityFile ~/.ec2/personal-key-pair.pem UserKnownHostsFile ~/.ec2/known_hosts StrictHostKeyChecking no 

This will allow you to simply type ssh ec2-##-##-##-## and get into your client.

  1. Close your terminal. Your bash profile changes won’t take affect until you restart. Restart and execute the command ec2-describe-instances. You should see a list of the running instances (remember to turn yours off when you’re not using it!).

That’s all you should need to do on your personal machine.

Creating a New AMI

I went into a lot of detail with the computer setup. I’m not going to give a command by command details with setting up an AMI, because that’s the assignment.

Edit: I think I actually did just what I said I wouldn’t…

Base AMI

I started with the latest Ubuntu server image. This is Ubuntu 10.10 (Maverick Meerkat) Server 32-bit. The AMI info page can be found here. I recommend using the listed (at the time of this writing) AMI ami-­1a837773.

There is an updated image available that is not listed on Amazon’s pages (yet) but is listed on the Ubuntu website, but it has one bug that can cause a lot of headaches. The US East AMI ID is ami-a6f504cf. You can decide if you want to be brave or if you want to be safe.

ec2-bund-vol is broken (kinda)

The latest AMI (ami-a6f504cf) has a small bug that will prevent it from bundling without using a patched version of ec2-bund-volRead for more information. You can avoid a lot of trouble by using the previous AMI: ami-­1a837773. It should be recent enough that you shouldn’t have to worry.

I found the above information after attempting to bundle about 20 times. I started from a base AMI about 6 times. I was doing everything right, but each time, my newly bundled/uploaded/registered AMI would fail to launch. (I have saved you, my reader, from hours—maybe days—of frustration.)

Installing packages

First thing’s first. In your favorite text editor, open /etc/apt/sources.list. Uncomment the four lines that end in multiverse (4th group). This will allow you to do the updates and get the correct software for your distribution.

If you used the latest AMI (ami-a6f504cf), you’ll need to complete one extra step. If you’re using ami-­1a837773, you can skip ahead. ami-a6f504cf users, type this:

sudo add-apt-repository ppa:smoser/bundle-fix-sru-test 

You’ll then want to update apt. I recommend upgrading everything too:

sudo apt-get update sudo apt-get upgrade 

Here’s some the packages you’ll absolutely need or want:

ec2-ami-tools ec2-api-tools apache2 zip 

If you’re using PHP, you should install the following packages:

php5 php5-gd php5-curl php5-dev php-pear smarty 

If you’ll be using Python (or if you want the option of switching to it if PHP can’t cut it):

libapache2-mod-python python-imaging python-dev python-setuptools python-boto python-cheetah python-simplejson python-pycurl python-gd 

Web server configuration

At this point, the easy part is over. Now you need to setup your server to your liking. If you’re picky, this can take a while. I recommend fiddling as little as possible (which, funny enough, was not what I did).

If you installed the apache2 package, it should be running and good to go. the document root is found at /var/www/.


I didn’t have to do anything to get PHP working, though you should make sure index.php is in the DirectoryIndex directive in /etc/apache2/mods-enabled/dir.conf.


If you’re using Python, you’ll want follow Steve’s directions. I took his code and put it in/etc/apache2/mods-available/python.conf:

<IfModule mod_python.c> AddHandler mod_python .py PythonHandler mod_python.publisher PythonDebug On </IfModule> 

You’ll need to create a symbolic link from mods-enabled to mods-available forpython.conf. Also, edit dir.conf and add to your DirectoryIndex directive.

Tip: mod_python works very differently than PHP. Check for some info.

Let’s take this program:

from mod_python import apache def index(req): return "Index" def say(req, what="NOTHING"): return "I am saying %s" % (what,) 

If we call this script and place it in our document root, then going to / on our server (in a browser) will display “Index”. Going to /say will display “I am saying NOTHING”./say?what=Hello will display “I am saying Hello”. This page on traversal explains path traversal in more detail.


You should test your Apache configuration at this point. Once you know your configuration is going to work, you’re good. Don’t fiddle too much, or you could be spending 2 hours trying to find a bug that you introduced when you added an extra / to a configuration file. (True story.)


Some bloke in class brought up the fact that Ubuntu has a handy feature called cloud-init.It’s true. So you can just stop worrying your little head about that.

Bundling an AMI

The Amazon EC2 User Guide contains all the instructions for bundling your instance. You can also look on page 226 of Programming Amazon Web Services. Also, you can read this.


You need to prepare for the bundling first. You’ll need:

  • The private key pair.
  • The certificate file.
  • The AWS user id, found in the Account section of the AWS site. Do not include the hyphens in this number.
  • Access Key ID and Access Secret Key, also in the account section

Copy all of those files through scp to your instance. You must move them to /mnt. Do not leave them in your home folder, as they will be stored in your instance.

You can take the extra effort of truncating apache logs and your bash and vim history if you want. Just in case someone else starts your instance. And you’ve typed anything you don’t want people snooping.


After moving your files over to /mnt, cd there yourself. Type ec2-bundle-vol --help to get an idea of the command. I’d make a directory to write the image files too, then type the command:

sudo ec2-bundle-vol -p my-ami.img -d /mnt/bundle/image -r i386 \ -c X509Cert.pem -k PrivateKey.pem -u `cat user_id.txt` 

Change my-ami-img to a prefix with something that identifies you. And change any paths or files names you need. I’ve followed the advice of Programming Amazon Web Services and wrote my image to the bigger /mnt disk. I also put the user id number into a file user_id.txtfor convenience.

This process will take about 10-20 minutes.

If it takes longer than that, check for a broken pipe (hit enter).


Now you have to upload the AMI to S3 to make it available. I put my access key into the fileaccess_key.txt and my secret key into secret_key.txt. Type ec2-upload-bundle --help to get an idea of the upload command. Once you’ve done that, you’ll just need to run:

ec2-upload-bundle -m /mnt/bundle/image/my-ami.img.manifest.xml \
    -b cs462-machines/my-user-name -a `cat access_key.txt` -s `cat secret_key.txt`

Be sure to change my-user-name to something more applicable. But this part is important so that the bucket doesn’t get so cluttered. This only takes a minute or two.


Once you’re uploaded, you’re ready to register. If you’ve got the ec2-api-tools package, you should be able to do this right from your instance. (You can still apt-get install ec2-api-tools and get them.) Or you can do this part from another machine, use Ruby, or even use the AWS Console.

From your instance, you can type this:

ec2-register -K PrivateKey.pem -C X509Cert.pem \ cs462-machines/your-user-name/my-ami.img.manifest.xml 

From your own computer, if you’ve set up your EC2 tools properly, you can type:

ec2-register cs462-machines/your-user-name/my-ami.img.manifest.xml 

This takes only a few seconds, and you should be ready to go.

Test your AMI

Now for the true test. Start up a new instance with your newly bundled AMI. If you’re truly daring, you can stop your previous instance first. But you might want to make sure your instance works and that it will run your user-data as a bootstrap script.

Other Things


For those of you using PHP, make sure you check out php-aws, because you’re probably going to need it later. I didn’t mention it until now, because I don’t recommend putting it in your PHP globals, so you can package it with the rest of your code. You’ll probably need it locally for reference anyhow.


Because our AWS account has been used for so long and never cleaned out, there’s a lot of garbage in our buckets. Being a fan of the command line, I found this little gem. s3cmd will let you interact with S3 without coding up Ruby or going through the slow web interface. It does have the downside of only being able to delete one object at a time, but it’s probably better that way.

You can use s3cmd to create small scripts, but you can do the same with Python or Ruby too. But if your favorite language is Bash, this can come in handy.


I want to make you aware of something you should know if you’re going to use EC2 AMIs. When you bundle an AMI, it saves the authorized_keys files with the bundle. I actually added my own personal public key to my AMI so that I can access it from my laptop or work computer without needing my key-pair on Amazon.

But you should be aware that if you use someone’s AMI, you get whatever they give you. For example, if Bob launches my AMI, I have a back door into the instance. Bob shouldn’t be running my AMI anyway, even if he can (because he’s in my class), so this isn’t a problem. But this is another reason to make sure you use an AMI from a trusted source. (The AMI IDs that I give are from a trusted source.)


After you get the hang of it (or do it 6+ times in 4 days), you’ll see that it’s a pretty simple process. But until you finally start up your customized server, you don’t realized how useful it is. Now I’m able to start up 1 or 100 servers that all have Apache configured the way I want with packages that I find useful. That’s handy.

Leave a reply...