Optimizing Your Amazon Web Services Costs

I’ve been with Amazon for quite a long time now and you must have heard that their web hosting services aren’t very cheap. The average total of one instance per month (including EBS, S3 and all the others) was around $120 at the start. That was back in July 2009 when I had no idea about how all this stuff works. With a lot of experimenting I managed to drop my instance per month costs down by around 40%. Below are a few tips that can help you lower your Amazon Web Services charges:

  • Use reserved EC2 Instances where possible. Amazon charges $0.085 per hour for an m1.small Linux instance in the US, that’s around $61 per month and $734 per year. A reserved instance costs me $227 for one year, plus $0.03 per running hour, that makes it around $490 per year for an m1.small instance. Use reserved instances only if you’re sure that you’ll be using it for a whole year. You can save even more if you purchase a reserved instance for three years.
  • Storage: EBS vs EC2. Pick EC2! That’s right, EC2! EBS charges you for provisioned storage, IO requests and snapshots. These may rise pretty quickly if you’re running MySQL on an EBS block – very risky! Run your MySQL on EC2. The php files and everything else should preferably be on EC2 aswell. You can use your EBS block for tiny backups of core PHP files if you’re running more than one EC2 instance.
  • EBS is cheaper than S3. S3 should only be used in cases where you have to serve your static content from different servers (perhaps through CloudFront), and maybe store some backups there too (don’t forget to remove the old ones!), but EBS is cheaper, even with snapshots.
  • CloudFront is okay. It does speed up your website, but you have to know that it’s more expensive for requests to Japan and Hong Kong

There you go. With these tips you should be able to get the Amazon hosting services for around $90/month, unless of course you have a 3 million visitors per day website ;) Also, for those of you wondering.. I haven’t used RackSpace, but I did compare their prices to Amazon’s and they’re more expensive.

Cloud Tips: Rediscovering Amazon CloudFront

So, three months later I realized I wasn’t using CloudFront at all! Huh? I took a deeper look at my Amazon Web Services bill last month and found out that I wasn’t even charged for CloudFront! But hey, I delivered all my static content through CloudFront distributions from S3 and I had a subdomain mapped to those distributions and everything was working fine (thought I).. Let’s see:

Amazon CloudFront delivers your content using a global network of edge locations. Requests for your objects are automatically routed to the nearest edge location, so content is delivered with the best possible performance.

Right, and that’s probably what they charge for in the CloudFront section, so the fact is that I haven’t been using it at all. Gathering all the static content from the so-called “origin server” is far from what CloudFront can do. What I’ve been using for the past few months is simply delivering content from my S3 server, which is also good, but “good” is not enough. I browsed throughout the AWS Management Console for hours and couldn’t find out what I was doing wrong, the server kept pulling the content from the origin. Then, finally I realized that after I’ve created a distribution I was given two addresses and as they said, one was the origin server, the second one was the CloudFront server (it’s a .cloudfront.net subdomain underlined red), thus the settings I got all wrong were at the DNS level, not the Management Console.

Cloud Tips: Rediscovering Amazon CloudFront

So I logged back to my registrar, found the DNS management options and switched my CNAMEs to the CloudFront domain instead of the origin bucket and hoped that everything works well. The very next day I got my very first bill for Amazon CloudFront – three cents! Hurray! I’m not sure if this is well written in the documentation for CloudFront and S3 (I doubt that people read them) but I have a few friends who have experienced the same problem and why the address of the origin bucket in the first place? Weird. The S3 Firefox Organizer groups both fields into one and that’s even more weird. Oh well, glad I sorted it out.

Cloud Tips: Automatic Backups to S3

In a previous post about backing up EC2 MySQL to an Amazon S3 bucket we covered dumping MySQL datasets, compressing them and uploading to S3. After a few weeks test-driving the shell script, I came up with a new version that checks, fixes and optimizes all tables before generating the dump. This is pretty important as mysqldump will fail on whatever step would cause an error (data corruption, crashed tables, etc), thus your uploaded to S3 archive would be kind of corrupt. Here’s the script:

filename=mysql.`date +%Y-%m-%d`.sql.gz
echo Checking, Fixing and Optimizing all tables
mysqlcheck -u username -p password --auto-repair --check --optimize --all-databases
echo Generating MySQL Dump: ${filename}
mysqldump -u username -p password --all-databases | gzip -c9 > /tmp/${filename}
echo Uploading ${filename} to S3 bucket
php /ebs/data/s3-php/upload.php ${filename}
echo Removing local ${filename}
rm -f /tmp/${filename}
echo Complete
<pre>

There you go. If you remember my previous example I stored the temporary backup file on Amazon EBS (Elastic Block Storage) which is quite not appropriate. Amazon charges for EBS storage, reads and writes, so why the extra cost? Dump everything into your temp folder on EC2 and remove afterwards. Don't forget to make changes in your upload.php script ($local_dir settings). Also, just as a personal not and to people who didn't figure out how to upload archives with data to S3, here's another version of the script which takes your public_html (www, htdocs, etc) directory, archives it, compresses and uploads to an Amazon S3 bucket:

<pre>filename=data.`date +%Y-%m-%d`.sql.gz
echo Collecting data
tar -czf /tmp/${filename} /ebs/home/yourusername/www
echo Uploading ${filename} to S3 bucket
php /ebs/data/s3-php/upload.php ${filename}
echo Removing local ${filename}
rm -f /tmp/${filename}
echo Complete

Oh and have you noticed? Amazon has changed the design a little bit, and woah! They’ve finally changed the way they show the Access Secret without a trailing space character! Congrats Amazon, it took you only a few months.

Cloud Tips: Backing Up MySQL on Amazon EC2 to S3

Now that I’m all set up in the Amazon cloud I’m starting to think about backups. Elastic Block Storage (EBS) on Amazon is great and the Snapshots (backups) can be generated with a few clicks from the Management Console, but, for a few reasons I’d like to set up my own backup scripts and here’s why:

  • Amazon EBS snapshots are cool, but there might be a situation where I’d like to restore only one file, or a few rows from a MySQL dump or whatever. EBS works in bundled mode, this means that you store an image of the hard-drive you’re working it, no matter how many files there are. It might be painful setting up an extra hard-drive just for backups and work with its snapshots
  • I don’t believe there’s a feature to schedule or automate EBS snapshots
  • I’d like a simple way to download backed up date onto my local PC
  • Some of my clients like to get their weekly backups by FTP

I don’t really care about my php files, images and other stuff that’s located on my EBS, cause I’m sure I have local copies of all that. The most important part in all my projects is the data stored in my MySQL database, thus I’m going to show you how to setup a simple shell script to generate daily MySQL backups and a simple php script to upload them to a secure S3 bucket.

Take a look at this simple shell script:

filename=mysql.`date +%d.%m.%Y`.sql.gz
echo Generating MySQL Dump: ${filename}
mysqldump -uyour_username -pyour_password --all-databases | gzip -c9 > /ebs/backups/${filename}
echo Uploading ${filename} to S3 bucket
php /ebs/data/s3-php/upload.php ${filename}
echo Removing local ${filename}
rm -f /ebs/backups/${filename}
echo Complete

I’m assuming you’re familiar with shell scripting, thus there’s no need to explain the first few lines. Don’t forget to type in your own username and password for MySQL access, also, I used the path /ebs/backups/ for my daily MySQL backups. You choose your own.

There are a few scripts located in /ebs/data/s3-php/ including upload.php, which takes a single parameter – filename (don’t put your path there, let’s keep things simple). The script simply reads the given file and uploads it to a preset path into your preset S3 bucket. I’m working with the S3-php5-curl class by Donovan Schonknecht. It uses the Amazon S3 REST API to upload files and it’s just one php file called S3.php, which in my case is located in /ebs/data/s3-php right next to my upload.php script.

Before going on to upload.php take a look at this file which I called S3auth.php:

$access_id = 'your_access_id';
$secret_key = 'your_secret_key';
$bucket_name = 'bucket';
$local_dir = '/ebs/backups/';
$remote_dir = 'backups/';

This is the settings file which I use in upload.php. These particular settings assume your backups will be located in /ebs/backups and will be backed up to an Amazon S3 bucket called ‘bucket’ and in the ‘backups’ directory within that bucket. Using single quotes is quite important, especially with the secret_key, as Amazon secret keys often include the backslash symbol. Here’s the upload.php script:

require("S3.php");
require("S3auth.php");

$s3 = new S3($access_id, $secret_key);
$s3->putBucket($bucket_name, S3::ACL_PRIVATE);
$s3->putObjectFile($local_dir.$argv[1], $bucket_name, $remote_dir.$argv[1], S3::ACL_PRIVATE);

All simple here according to the S3.php class documentation. Notice the $argv[1], that’s the first argument passed to the upload.php script, thus the filename of the backup file.

That’s about everything. Try a few test runs with the shell script (remember to chmod +x it otherwise you’ll not be able to execute it) and finally setup a cron running the script daily. Mine works like a charm!

Cloud Tips: Amazon EC2 Email & S3 CNAME Issues

So you moved your blog or website (or whatever) to Amazon EC2 and wondering why your e-mail notices have stopped working? Now I know there’s bunch of articles about the EC2 email issues, and most of them state that the letters are getting into the spam boxes or aren’t getting delivered at all, because Amazon’s IP pool has been blacklisted by most e-mail providers.

Don’t panic! Not just yet.. You might as well try the postfix via google mail or perhaps some paid mail relay servers, but hey, the php mail function requires the sendmail daemon to be running, and if you’re using the Fedora Core 8 AMI on EC2, you might as well try to turn it on:

service sendmail start

Worked for me, and the messages aren’t being marked as spam, while I’m still getting messages from my WordPress installation on MediaTemple marked as Junk by Windows Live Mail ;) I don’t believe Amazon’s in the blacklists… Really… Anyone, but not Amazon .. Right?

The next AWS issue a novice is going to bump into is the CNAME dillema. It’s so straightforward though, really… Let’s say I want an S3 bucket on s3.foller.me instead of the good old s3.amazonaws.com address. Create a new bucket called s3.foller.me, go to your DNS editor and add a CNAME record for s3.foller.me pointing to s3.foller.me.s3.amazonaws.com. Done. The bucket name and the CNAME have to be the same and this is the one and only trick.

Happy clouding, cheers!

Working With Amazon EC2: Tips & Tricks

It’s been a while now since I’ve been hosting on Amazon Web Services and I’d just like to point out some issues I had and quick ways of solving them. We’re gonna talk about setting up a server that would serve not only you, but your clients too, cause $100/mo is quite expensive, isn’t it? So let’s begin and keep this as straightforward as possible. If you don’t understand something, it’s probably because you haven’t read the official EC2 docs and haven’t searched the forums. This is not a tutorial, it’s just a set of rules you may want to follow to make things right.

Once you start a new instance from an Amazon predefined AMI (Fedora Core 8 for example) I suggest you start building your structure right straight away. Attach an EBS volume to you instance (I mount it to /ebs) and start creating your users with their home directories in /ebs/home/kovshenin not the regular /home/kovshenin. Also point your MySQL server to keep your database files in /ebs/mysql. There are plenty tutorials out there on how to do that.

Now, edit your httpd.conf, add your vhosts, point them to the right users dirs, install an ftp server and make sure you chroot the users to their home directories. That way they won’t be able to mess up with eachothers files and folders, peek passwords etc. You might want to change the root user’s home directory to / instead of /root in case you’ll want to use ftp via your root user (which is quite dangerous).

Now comes the fun part. The HTTP server runs under the apache user by default in FC8 and I recommend you don’t touch this. Damn it took me quite some time to figure out how the heck can the apache user execute and write to files not belonging to apache. I messed up big time with the groups, adding apache to all my client’s users groups, but thank god I found mod_suphp in the end. Install that one and make sure you use it and there’s no need to change the users umasks anymore.

Note: There’s a little issue with the mod_suphp in Fedora as far as I know, which doesn’t let you use the suPHP_UserGroup directive in the httpd.conf yelling that it does not exist. Most of the man pages on the net say you have to use that directive, but I’m good without it. It seems that suphp can figure out what user to run on its own, look closely at the config files, and also make sure you’re running php-cgi, not the CLI version. By the way, this is the part where WordPress stops asking you your FTP credentials on plugins/themes update, install, remove and core upgrade too. Speeds up the whole process ;)

I used the following code to test how mod_suphp works (or doesnt):

<?php echo system("id"); ?>

Which should output what’s the current user. Make sure you check everything works before going public, and do not set your min_uid and min_gid in suphp lower than 50. It’s safer to chown -R files and folders than to let suphp run your scripts via root or some other powerful user.

Backing up your EC2 and EBS

This is very important. Once you have everything set up and running, DO backup. Backing up the EBS is quite simple, just create a snapshot from the Amazon EC2 Management Console. Backing up the running AMI (instance) is a little bit mroe complex. You have to use the ec2 command line tools to bundle a new volume, upload it to an Amazon S3 bucket and register the AMI. There are plenty tutorials on the net on how to do that. Shouldn’t take you more than half an hour to figure it out.

Just make sure you have copies of all the major config files (httpd.conf, crontab, fstab, ..) backed up on your /ebs/config for instance. You might need them in the future (when you loose everything, haha ;) Restoring a backed up AMI instance is simple. Launch a new instance using the AMI you generated, attach the Amazon Elastic IP address to it and voila. Way too simple.

About the EBS, there are quite a few things you should be able to do with it before continuing. Restoring a backed up Snapshot: Create Volume from Snapshot, umount /ebs, deattach old volume, attach new volume, mount /ebs. Cool? Be careful when you’re resizing your EBS. The xfs filesystem automatically grows as far as I know, but in my case I use the ext3 filesystem. So if you need to grow your ext3 EBS you’ll go:

  1. Create a Snapshot
  2. Create a new EBS Volume from that Snapshot you created (say 10 GB if you were running 5 GB)
  3. Attach it to your Instance, say /dev/sdg
  4. Use the resize2fs command to resize the partition to 10GB
  5. Mount it to /ebs2 or whatever
  6. Check to see if everything’s in place
  7. Unmount /ebs2, deattach /ebs2, unmount /ebs, deattach /ebs
  8. Attach the 10GB volume to where /ebs was attached (/dev/sdf)
  9. Mount /ebs and start your services

There you go, back to work, server. By the way, when working with Amazon AWS, note that you should be working in the same region where your AMI is (us, eu, east, 1c, …) otherwise some of the options (when attaching, etc) might just not come up. Beware of that.

Well, I guess those are pretty much all the basics. Don’t forget to read the Amazon S3 tutorials and API, pretty sweet stuff! Good luck.

Have You Tried the Amazon Web Services?

Amazon EC2, EBS, S3.. I’ve been looking for the perfect web hosting for over two years now. Is this it?

A few months ago I really liked MediaTemple cause they offered pretty good US hosting starting from $20/mo, which was quite good for the Foller.me project, so at the starting point I chose them. Their service is cool, definitely worth the money, but. A few weeks have passed, along with some major development on the service update and I got stuck with MySQL and overall server performance. It’s pretty tough to scan through 2,000,000 relations from @cnnbrk and then geocode their locations so I thought that I need to fine-tune MySQL and work out a more powerful caching system.

Yes, MediaTemple do offer dedicated MySQL grids for $50/mo, so that’s $70/mo overall. Not that bad, but thinking ahead, I’d also like to tweak up my http server, so that’d be a virtual dedicated plan for $50/mo, which makes $100/mo in total. Woah! And that’s just the start (around 500 megs RAM, 20 GB disk space and 1 TB bandwidth).

Now the Amazon Web Services offers a 2 GB RAM, 1.6 GHz virtual machine for only $0.10/hr, that makes ~$70/mo. Put up an Elastic Block Store (EBS) up to 1 TB and attach it to the instance around $20/mo. and perhaps an Amazon S3 bucket $10/mo. That makes about $100/mo in total. It’s not just the price though, I loved the way you’re in total control of whatever is happening on your server. You tune it however you like, whenever you like. Save bundled volumes and start over at any time. One-click EBS volume backups, elastic IP address and up to 20 instanced running simultaneously (you can increase this number by contacting Amazon). You also get to pick whatever OS you’d like to run (they’re called AMIs). You can build your own bundled OSs and make them available public.

Oh, and one of the best things about Amazon EC2 (Elastic Cloud) is that it’s so flexible! Switching servers has never been so easy. Start a new instance, attach an EBS, tune it up. Associate your old Elastic IP address to the new instance and voila! Go ahead and terminate your old instance, cause you’re riding your new mustang now!

I’m also sure that you can setup multiple servers and network balancers.. Like clustered computing y’know, the possibilities are endless! But I’m too far away from that at the moment, though I’m sure that whenever I have some free time, I will throw some experiments in that field ;) I’ve already setup Trac and SVN server a few days ago, works great!

Virtual Private Servers, Dedicated Servers, blah blah blah. Those are from the past. It’s Amazon Web Services. Go get your account right now ;)