<?xml version="1.0" encoding="UTF-8"?>
<!-- generator="wordpress/2.3.3" -->
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	>

<channel>
	<title>Paul Dowman</title>
	<link>http://pauldowman.com</link>
	<description>Software Developer</description>
	<pubDate>Tue, 09 Mar 2010 13:28:29 +0000</pubDate>
	<generator>http://wordpress.org/?v=2.3.3</generator>
	<language>en</language>
			<item>
		<title>Let me help you!</title>
		<link>http://pauldowman.com/2010/01/25/let-me-help-you/</link>
		<comments>http://pauldowman.com/2010/01/25/let-me-help-you/#comments</comments>
		<pubDate>Tue, 26 Jan 2010 00:17:38 +0000</pubDate>
		<dc:creator>Paul Dowman</dc:creator>
		
		<category><![CDATA[GigPark]]></category>

		<category><![CDATA[Personal]]></category>

		<guid isPermaLink="false">http://pauldowman.com/2010/01/25/let-me-help-you/</guid>
		<description><![CDATA[I&#8217;ve just spent an exciting three years developing GigPark (which was recently named one of the top 10 Toronto web startups of 2009) and managing the integration and transition to it&#8217;s new owners since the acquisition in August.
Now I&#8217;m moving on to new challenges, and I&#8217;m available for contract work.
Do you need help with:

Web application [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve just spent an exciting three years developing <a href="http://www.gigpark.com/">GigPark</a> (which was recently named one of the <a href="/2010/01/10/gigpark-in-top-10-toronto-web-startups-of-2009/">top 10 Toronto web startups of 2009</a>) and managing the integration and transition to it&#8217;s new owners since the <a href="/2009/08/24/canpages-buys-gigpark/">acquisition in August</a>.</p>
<p>Now I&#8217;m moving on to new challenges, and I&#8217;m available for contract work.</p>
<p>Do you need help with:</p>
<ul>
<li>Web application performance and scalability?</li>
<li>Software development using Ruby? (I also have a lot of experience with Java and a variety of other languages and tools.)</li>
<li>System architecture?</li>
<li>Cloud computing, EC2 and Amazon web services?</li>
</ul>
<p>Do you need someone to lead a software development team or help with an Agile software development process?</p>
<p>I have experience with all of these things and I&#8217;d be happy to help.</p>
<p>Please read about some of the <a href="/about">interesting things that I&#8217;ve done</a> and then <a href="/contact">contact me</a> to see how I can help you.</p>
]]></content:encoded>
			<wfw:commentRss>http://pauldowman.com/2010/01/25/let-me-help-you/feed/</wfw:commentRss>
		</item>
		<item>
		<title>GigPark in Top 10 Toronto Web Startups of 2009</title>
		<link>http://pauldowman.com/2010/01/10/gigpark-in-top-10-toronto-web-startups-of-2009/</link>
		<comments>http://pauldowman.com/2010/01/10/gigpark-in-top-10-toronto-web-startups-of-2009/#comments</comments>
		<pubDate>Mon, 11 Jan 2010 02:34:47 +0000</pubDate>
		<dc:creator>Paul Dowman</dc:creator>
		
		<category><![CDATA[GigPark]]></category>

		<category><![CDATA[Personal]]></category>

		<category><![CDATA[Toronto]]></category>

		<guid isPermaLink="false">http://pauldowman.com/2010/01/10/gigpark-in-top-10-toronto-web-startups-of-2009/</guid>
		<description><![CDATA[I&#8217;m incredibly proud to see that blogTO, my personal favorite site for news and happenings in Toronto, has named GigPark one of Toronto&#8217;s top 10 web startups of 2009!
As Director of Technology I was GigPark&#8217;s first employee, and led the development up to and through the acquisition by Canpages in August of 2009.
]]></description>
			<content:encoded><![CDATA[<p>I&#8217;m incredibly proud to see that <a href="http://www.blogto.com/">blogTO</a>, my personal favorite site for news and happenings in Toronto, has named <a href="http://www.gigpark.com/">GigPark</a> one of <a href="http://www.blogto.com/tech/2009/12/the_top_10_toronto_web_startups_of_2009/">Toronto&#8217;s top 10 web startups of 2009</a>!</p>
<p>As Director of Technology I was GigPark&#8217;s first employee, and led the development up to and through the <a href="/2009/08/24/canpages-buys-gigpark/">acquisition by Canpages</a> in August of 2009.</p>
]]></content:encoded>
			<wfw:commentRss>http://pauldowman.com/2010/01/10/gigpark-in-top-10-toronto-web-startups-of-2009/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Movin&#8217; on&#8230; (status of EC2 on Rails)</title>
		<link>http://pauldowman.com/2010/01/10/movin-on-status-of-ec2-on-rails/</link>
		<comments>http://pauldowman.com/2010/01/10/movin-on-status-of-ec2-on-rails/#comments</comments>
		<pubDate>Mon, 11 Jan 2010 01:48:59 +0000</pubDate>
		<dc:creator>Paul Dowman</dc:creator>
		
		<category><![CDATA[EC2]]></category>

		<category><![CDATA[EC2 on Rails]]></category>

		<category><![CDATA[Ruby]]></category>

		<category><![CDATA[Ruby on Rails]]></category>

		<guid isPermaLink="false">http://pauldowman.com/2010/01/10/movin-on-status-of-ec2-on-rails/</guid>
		<description><![CDATA[I began a fun project a couple of years ago: EC2 on Rails. It became quite widely used, people contributed some great code, and a small community developed.
I had a great vision for what it should become. But since I was very busy with a start-up (which we successfully sold last August), I struggled to [...]]]></description>
			<content:encoded><![CDATA[<p>I began a fun project a couple of years ago: <a href="/projects/ruby-on-rails-ec2">EC2 on Rails</a>. It became quite widely used, people contributed some great code, and a small community developed.</p>
<p>I had a great vision for what it should become. But since I was very busy with a start-up (which we <a href="/2009/08/24/canpages-buys-gigpark">successfully sold</a> last August), I struggled to find the time to work on it. I did a lot of work that I never ended up releasing because I couldn&#8217;t find the time for testing and fixing the last few small bugs (though it has been in use in production with great success).</p>
<p>The hardest thing to find time for was always documentation and communication of the status, so today I&#8217;m taking the time to clarify since I get asked a lot:</p>
<p><strong>I won&#8217;t be working on it any more. </strong></p>
<p>But open source is a wonderful thing and anyone who wants to keep using it can fork it and do so.</p>
<p>Thanks to everyone who contributed features and fixes.</p>
<p>I apologize for letting it languish for so long, I had the best intentions to find some more time but now that I have a <a href="/2009/12/17/im-a-dad">four-week old baby</a> I know that it&#8217;s impossible.</p>
<h3>A great success in it&#8217;s day</h3>
<p>It felt great to be sitting in a session at RailsConf 2008 and hear the presenter recommend EC2 on Rails.</p>
<p>When I first created EC2 on Rails it was the first and only Rails AMI, and in fact it was the first public Ubuntu AMI that I know of (though <a href="http://alestic.com/">Eric Hammond</a> went on to create what later became the definitive Ubuntu public AMI and Canonical eventually produced official Ubuntu images).</p>
<p>In spite of the sparse documentation it was simple enough that many people used it either as-is or as a starting point for their own custom setup.</p>
<p>I think there&#8217;s still a great need for a simple open-source Rails server image, but now there are at least a couple of options, and the choices for all components of the Rails production stack have improved hugely.</p>
<p>Some of the custom  functionality is now available via other projects like <a href="http://macournoyer.com/">Marc-André Cournoyer</a>&#8217;s <a href="http://github.com/macournoyer/mysql_s3_backup">mysql_s3_backup</a>.</p>
<h3>I&#8217;d do a few things differently</h3>
<p>If I had the time to continue working on it I&#8217;d make some major changes in the architecture:</p>
<ul>
<li>I&#8217;d use <a href="http://wiki.opscode.com/display/chef/Home">Chef</a> to configure the image instead of a build script. This would allow running instances to be upgraded more easily, allow greater customization by the user, and allow the sharing of common customizations.</li>
<li>I&#8217;d stop using Capistrano for deployment, or at least move all the code that&#8217;s inside Capistrano recipes into scripts that exist on the server. (<a href="http://github.com/ezmobius/chef-deploy">Chef-deploy</a> looks promising but I haven&#8217;t had a chance to play with it yet).</li>
<li>I would provide better support for elastic clusters (i.e. adding and removing instances from the cluster).</li>
</ul>
<p>I have a lot of thoughts on how those things would be achieved, feel free to get in touch with me if you are building something similar and want to chat about it.</p>
<h3>The new and improved but unreleased version</h3>
<p>The unreleased version (<a href="http://github.com/pauldowman/ec2onrails">available on GitHub</a>) has been substantially rewritten. It is now based on <a href="http://nginx.org/">Nginx</a>, and <a href="http://www.modrails.com/">Phusion Passenger</a>, and uses the awesome <a href="http://varnish.projects.linpro.no/">Varnish</a> proxy for balancing across multiple instances (optionally with HTTP caching). As I mentioned it&#8217;s being used in production with great success, but there are still a few minor known issues and probably some untested areas.</p>
<p>Please feel free to fork it and give it new life.</p>
]]></content:encoded>
			<wfw:commentRss>http://pauldowman.com/2010/01/10/movin-on-status-of-ec2-on-rails/feed/</wfw:commentRss>
		</item>
		<item>
		<title>I&#8217;m a dad!</title>
		<link>http://pauldowman.com/2009/12/17/im-a-dad/</link>
		<comments>http://pauldowman.com/2009/12/17/im-a-dad/#comments</comments>
		<pubDate>Thu, 17 Dec 2009 13:53:04 +0000</pubDate>
		<dc:creator>Paul Dowman</dc:creator>
		
		<category><![CDATA[Personal]]></category>

		<guid isPermaLink="false">http://pauldowman.com/2009/12/17/im-a-dad/</guid>
		<description><![CDATA[I&#8217;m pleased to announce that my son Miles was born a week ago, on December 10th, weighing 7 lbs 3 oz. It has been a wonderful week! I&#8217;ll be taking some time off to spend with my family, and I might be a bit slow responding to email for the next little while.

]]></description>
			<content:encoded><![CDATA[<p>I&#8217;m pleased to announce that my son <a href="http://twitter.com/milesdowman">Miles</a> was born a week ago, on December 10th, weighing 7 lbs 3 oz. It has been a wonderful week! I&#8217;ll be taking some time off to spend with my family, and I might be a bit slow responding to email for the next little while.</p>
<p><img src="http://pauldowman.com/wp-content/uploads/2009/12/miles1.jpg" alt="Miles" /></p>
]]></content:encoded>
			<wfw:commentRss>http://pauldowman.com/2009/12/17/im-a-dad/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Canpages buys GigPark!</title>
		<link>http://pauldowman.com/2009/08/24/canpages-buys-gigpark/</link>
		<comments>http://pauldowman.com/2009/08/24/canpages-buys-gigpark/#comments</comments>
		<pubDate>Mon, 24 Aug 2009 13:36:39 +0000</pubDate>
		<dc:creator>Paul Dowman</dc:creator>
		
		<category><![CDATA[GigPark]]></category>

		<category><![CDATA[Personal]]></category>

		<guid isPermaLink="false">http://pauldowman.com/2009/08/24/canpages-buys-gigpark/</guid>
		<description><![CDATA[I&#8217;m very happy to announce that GigPark has been acquired by CanPages!
As Director of Technology I was the first employee of GigPark, which was founded by Pema Hegan and Noah Godfrey, and I&#8217;m proud to say that together with the awesome team of Tony Targonski and Gianni Chiappetta we have built a solid and reliable [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;m very happy to announce that <a href="http://www.gigpark.com/">GigPark</a> has been <a href="http://blog.gigpark.com/2009/08/24/canpages-buys-gigpark/">acquired</a> by <a href="http://www.canpages.ca/">CanPages</a>!</p>
<p>As Director of Technology I was the first employee of GigPark, which was founded by <a href="http://pe.ma/">Pema Hegan</a> and <a href="http://www.gigpark.com/people/noahgodfrey">Noah Godfrey</a>, and I&#8217;m proud to say that together with the awesome team of <a href="http://compsci.ca/blog/">Tony Targonski</a> and <a href="http://www.runlevel6.org/">Gianni Chiappetta</a> we have built a solid and reliable service that people love to use.</p>
<p>Canpages is the fastest growing local search and directories publisher in Canada, and their site gets more than 3.5 million unique visitors per month. Canpages will be integrating GigPark’s recommendations into its online and mobile search platforms which means that a lot more people will be seeing recommendations for businesses on GigPark.</p>
<p>Some highlights of the media coverage:</p>
<ul>
<li><a href="http://www.techcrunch.com/2009/08/24/canpages-bets-on-social-recommendations-buys-gigpark/">TechCrunch</a></li>
<li><a href="http://www.theglobeandmail.com/report-on-business/rewriting-the-future-of-the-phone-book/article1261668/" target="_self">Globe and Mail</a></li>
<li> <a href="http://www.nationalpost.com/story.html?id=1924030">National Post</a></li>
<li><a href="http://thestar.com/article/685878">Toronto Star</a></li>
<li><a href="http://watch.bnn.ca/taking-stock/august-2009/taking-stock-august-24-2009/#clip206785">BNN</a> (interview with Olivier Vincent, Canpages CEO)</li>
<li>the <a href="http://www.marketwire.com/press-release/Canpages-Inc-1034459.html" target="_self">press release</a></li>
</ul>
<p>It has been a pleasure working with the <a href="http://www.gigpark.com/about">GigPark team</a>, and I&#8217;m excited about our future with Canpages!</p>
]]></content:encoded>
			<wfw:commentRss>http://pauldowman.com/2009/08/24/canpages-buys-gigpark/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Speaking at FutureRuby</title>
		<link>http://pauldowman.com/2009/06/30/speaking-at-futureruby/</link>
		<comments>http://pauldowman.com/2009/06/30/speaking-at-futureruby/#comments</comments>
		<pubDate>Tue, 30 Jun 2009 13:47:00 +0000</pubDate>
		<dc:creator>Paul Dowman</dc:creator>
		
		<category><![CDATA[Ruby]]></category>

		<category><![CDATA[Ruby on Rails]]></category>

		<category><![CDATA[Scalability]]></category>

		<category><![CDATA[Speaking]]></category>

		<guid isPermaLink="false">http://pauldowman.com/2009/06/30/speaking-at-futureruby/</guid>
		<description><![CDATA[I&#8217;ll be speaking at the FutureRuby conference, which will be held in Toronto from July 9-12. If it&#8217;s anything like last year&#8217;s RubyFringe conference (also put on by the hard-working Unspace crew) it will be a great time, and anything but your standard tech conference.
I&#8217;m looking forward to hearing some great talks and meeting lots [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ll be speaking at the <a href="http://futureruby.com/">FutureRuby</a> conference, which will be held in Toronto from July 9-12. If it&#8217;s anything like last year&#8217;s RubyFringe conference (also put on by the hard-working <a href="http://unspace.ca/">Unspace</a> crew) it will be a great time, and anything but your standard tech conference.</p>
<p>I&#8217;m looking forward to hearing some great <a href="http://futureruby.com/panels/">talks</a> and meeting lots of interesting new people (the <a href="http://futureruby.com/parties/">evening events</a> alone are worth the price of the ticket!).</p>
<p><img src="http://pauldowman.com/wp-content/uploads/2009/06/futureruby.png" alt="FutureRuby" /></p>
<p>For more info check out the <a href="http://futureruby.com">web site</a> and follow <a href="http://twitter.com/futureruby">@futureruby</a> on Twitter.</p>
]]></content:encoded>
			<wfw:commentRss>http://pauldowman.com/2009/06/30/speaking-at-futureruby/feed/</wfw:commentRss>
		</item>
		<item>
		<title>The S3 Cookbook</title>
		<link>http://pauldowman.com/2009/06/29/the-s3-cookbook/</link>
		<comments>http://pauldowman.com/2009/06/29/the-s3-cookbook/#comments</comments>
		<pubDate>Tue, 30 Jun 2009 00:29:32 +0000</pubDate>
		<dc:creator>Paul Dowman</dc:creator>
		
		<category><![CDATA[S3]]></category>

		<category><![CDATA[Scalability]]></category>

		<category><![CDATA[Software Development]]></category>

		<category><![CDATA[Systems]]></category>

		<guid isPermaLink="false">http://pauldowman.com/2009/06/29/the-s3-cookbook/</guid>
		<description><![CDATA[Did you know that you can enable access logging on S3? Did you know that you can add arbitrary metadata to objects in S3? Did you know that you can serve compressed content from S3?
The S3 Cookbook, an e-book written by Scott Patten, has easy-to-follow recipes to do those and about 60 other things (including [...]]]></description>
			<content:encoded><![CDATA[<p>Did you know that you can enable access logging on <a href="http://aws.amazon.com/s3/">S3</a>? Did you know that you can add arbitrary metadata to objects in S3? Did you know that you can serve compressed content from S3?</p>
<p><a href="http://thes3cookbook.sopobo.com/">The S3 Cookbook</a>, an e-book written by <a href="http://www.spattendesign.com/">Scott Patten</a>, has easy-to-follow recipes to do those and about 60 other things (including one that I contributed for backing up a MySQL database to S3). In addition to the recipes, it also has chapters on S3&#8217;s architecture, authenticating S3 requests, and an overview of the S3 API.</p>
<p>You can checkout the <a href="http://thes3cookbook.sopobo.com/toc">full table of contents</a> and download a <a href="http://thes3cookbook.sopobo.com/sample">sample chapter</a>.</p>
<p>It&#8217;s published on <a href="http://www.sopobo.com/">Sopobo</a>, a new platform for authors to self-publish technical books (that also happens to be created by Scott!). Sopobo includes tools for readers to interact with each other and with the author. If I were writing a book that I planned to shop around to a few publishers I&#8217;d seriously consider putting it on there first to get some feedback (and make a few bucks) before it got picked up.</p>
]]></content:encoded>
			<wfw:commentRss>http://pauldowman.com/2009/06/29/the-s3-cookbook/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Better Logging Rails plugin</title>
		<link>http://pauldowman.com/2009/04/12/better-logging-rails-plugin/</link>
		<comments>http://pauldowman.com/2009/04/12/better-logging-rails-plugin/#comments</comments>
		<pubDate>Sun, 12 Apr 2009 18:58:32 +0000</pubDate>
		<dc:creator>Paul Dowman</dc:creator>
		
		<category><![CDATA[Ruby]]></category>

		<category><![CDATA[Ruby on Rails]]></category>

		<guid isPermaLink="false">http://pauldowman.com/2009/04/12/better-logging-rails-plugin/</guid>
		<description><![CDATA[I have created a Rails plugin that improves the log format. For more info on what it does and why, see the description on GitHub:
http://github.com/pauldowman/better_logging
]]></description>
			<content:encoded><![CDATA[<p>I have created a Rails plugin that improves the log format. For more info on what it does and why, see the description on GitHub:</p>
<p><a href="http://github.com/pauldowman/better_logging">http://github.com/pauldowman/better_logging</a></p>
]]></content:encoded>
			<wfw:commentRss>http://pauldowman.com/2009/04/12/better-logging-rails-plugin/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Backing up your MySQL database to S3</title>
		<link>http://pauldowman.com/2009/02/08/mysql-s3-backup/</link>
		<comments>http://pauldowman.com/2009/02/08/mysql-s3-backup/#comments</comments>
		<pubDate>Sun, 08 Feb 2009 23:54:21 +0000</pubDate>
		<dc:creator>Paul Dowman</dc:creator>
		
		<category><![CDATA[EC2]]></category>

		<category><![CDATA[MySQL]]></category>

		<category><![CDATA[Ruby]]></category>

		<category><![CDATA[S3]]></category>

		<category><![CDATA[Systems]]></category>

		<guid isPermaLink="false">http://pauldowman.com/2009/02/08/mysql-s3-backup/</guid>
		<description><![CDATA[Here&#8217;s a simple recipe, with complete code available on Github (written in Ruby), to automatically back up your MySQL database to Amazon&#8217;s S3 storage service, with regular incremental backup.
This article appears in The S3 Cookbook, an e-book written by Scott Patten. It is is based on the automatic MySQL backup in EC2 on Rails. 
Solution
You [...]]]></description>
			<content:encoded><![CDATA[<p>Here&#8217;s a simple recipe, with <a href="http://github.com/pauldowman/blog_code_examples/tree/master/mysql_s3_backup">complete code available on Github</a> (written in Ruby), to automatically back up your MySQL database to <a href="http://aws.amazon.com/s3/">Amazon&#8217;s S3 storage service</a>, with regular incremental backup.</p>
<p><small><em>This article appears in <a href="/2009/06/29/the-s3-cookbook/">The S3 Cookbook</a>, an e-book written by <a href="http://www.spattendesign.com/">Scott Patten</a>. It is is based on the automatic MySQL backup in <a href="http://ec2onrails.rubyforge.org/">EC2 on Rails</a>. </em></small></p>
<h3>Solution</h3>
<p>You might expect that you could simply upload the MySQL database files to S3. That could work if all your tables were MyISAM tables (assuming you did <a href="http://dev.mysql.com/doc/refman/5.0/en/lock-tables.html">LOCK TABLES</a> and <a href="http://dev.mysql.com/doc/refman/5.0/en/flush.html">FLUSH TABLES</a> to make sure the database files were in a consistent state), but it won&#8217;t work for <a href="http://dev.mysql.com/doc/refman/5.0/en/innodb.html">InnoDB</a> tables. A more general approach is to use the <a href="http://dev.mysql.com/doc/refman/5.0/en/mysqldump.html">mysqldump</a> tool to back up the full contents of the database and then use MySQL&#8217;s <a href="http://dev.mysql.com/doc/refman/5.0/en/binary-log.html">binary log</a> for incremental backups.</p>
<p>The binary log contains all changes to the database that are made since the last full backup, so to restore the database you first restore the full backup (the output from mysqldump) and then apply the changes from the binary log.</p>
<p>Here are Ruby scripts for doing the full backup, incremental backup, and restore.</p>
<p>The full backup script uses <a href="http://dev.mysql.com/doc/refman/5.0/en/mysqldump.html">mysqldump</a> to do the initial full backup and uploads it&#8217;s output to S3. It assumes the bucket is empty.</p>
<p><a href="http://github.com/pauldowman/blog_code_examples/tree/master/mysql_s3_backup/full_backup.rb">full_backup.rb</a>:</p>
<pre>#!/usr/bin/env ruby

require "common"

begin
  FileUtils.mkdir_p @temp_dir

  # assumes the bucket's empty
  dump_file = "#{@temp_dir}/dump.sql.gz"

  cmd = "mysqldump --quick --single-transaction --create-options -u#{@mysql_user}  --flush-logs --master-data=2 --delete-master-logs"
  cmd += " -p'#{@mysql_password}'" unless @mysql_password.nil?
  cmd += " #{@mysql_database} | gzip &gt; #{dump_file}"
  run(cmd)

  AWS::S3::S3Object.store(File.basename(dump_file), open(dump_file), @s3_bucket)
ensure
  FileUtils.rm_rf(@temp_dir)
end</pre>
<p>Once the full backup has been done, the following script can be run frequently (perhaps every 5 or 10 minutes) to rotate the binary log and upload it to S3. It must be run by a user that has read access to the MySQL binary log (see the Discussion section for details on configuring the MySQL binary log path).</p>
<p><a href="http://github.com/pauldowman/blog_code_examples/tree/master/mysql_s3_backup/incremental_backup.rb">incremental_backup.rb</a>:</p>
<pre>#!/usr/bin/env ruby

require "common"

begin
  FileUtils.mkdir_p @temp_dir
  execute_sql "flush logs"
  logs = Dir.glob("#{@mysql_bin_log_dir}/mysql-bin.[0-9]*").sort
  logs_to_archive = logs[0..-2] # all logs except the last
  logs_to_archive.each do |log|
    # The following executes once for each filename in logs_to_archive
    AWS::S3::S3Object.store(File.basename(log), open(log), @s3_bucket)
  end
  execute_sql "purge master logs to '#{File.basename(logs[-1])}'"
ensure
  FileUtils.rm_rf(@temp_dir)
end</pre>
<p>The following script restores the full backup (mysqldump output) and the subsequent binary log files. It assumes the database exists and is empty.</p>
<p><a href="http://github.com/pauldowman/blog_code_examples/tree/master/mysql_s3_backup/restore.rb">restore.rb</a>:</p>
<pre>#!/usr/bin/env ruby

require "common"

# Retrieve a single file from S3
def retrieve_file(file)
  key = File.basename(file)
  AWS::S3::S3Object.find(key, @s3_bucket)

  open(file, 'w') do |f|
    AWS::S3::S3Object.stream(key, @s3_bucket) do |chunk|
      f.write chunk
    end
  end
end

# List the files matching filename_prefix in the S3 bucket
def list_keys(filename_prefix)
  AWS::S3::Bucket.objects(@s3_bucket, :prefix =&gt; filename_prefix).collect{|obj| obj.key}
end

# Retrieve the files matching filename_prefix in the S3 bucket
def retrieve_files(filename_prefix, local_dir)
  list_keys(filename_prefix).each do |k|
    file = "#{local_dir}/#{File.basename(k)}"
    retrieve_file(file)
  end
end

begin
  FileUtils.mkdir_p @temp_dir

  # download the dump file from S3
  file = "#{@temp_dir}/dump.sql.gz"
  retrieve_file(file)

  # restore the dump file
  cmd = "gunzip -c #{file} | mysql -u#{@mysql_user} "
  cmd += " -p'#{@mysql_password}' " unless @mysql_password.nil?
  cmd += " #{@mysql_database}"
  run cmd

  # download the binary log files
  retrieve_files("mysql-bin.", @temp_dir)
  logs = Dir.glob("#{@temp_dir}/mysql-bin.[0-9]*").sort

  # restore the binary log files
  logs.each do |log|
    # The following will be executed for each binary log file
    cmd = "mysqlbinlog --database=#{@mysql_database} #{log} | mysql -u#{@mysql_user} "
    cmd += " -p'#{@mysql_password}' " unless @mysql_password.nil?
    run cmd
  end
ensure
  FileUtils.rm_rf(@temp_dir)
end</pre>
<p>The previous three scripts (<a href="http://github.com/pauldowman/blog_code_examples/tree/master/mysql_s3_backup/full_backup.rb">full_backup.rb</a>, <a href="http://github.com/pauldowman/blog_code_examples/tree/master/mysql_s3_backup/incremental_backup.rb">incremental_backup.rb</a>, and <a href="http://github.com/pauldowman/blog_code_examples/tree/master/mysql_s3_backup/restore.rb">restore.rb</a>) all include <a href="http://github.com/pauldowman/blog_code_examples/tree/master/mysql_s3_backup/config.rb">config.rb</a> which contains all user-specific configuration and <a href="http://github.com/pauldowman/blog_code_examples/tree/master/mysql_s3_backup/common.rb">common.rb</a> which defines some common functions:</p>
<p><a href="http://github.com/pauldowman/blog_code_examples/tree/master/mysql_s3_backup/config.rb">config.rb</a>:</p>
<pre>@mysql_database = "your-mysql-database"
@mysql_user = "root"
@mysql_password = "password"
@s3_bucket = "your-s3-bucket-name"
@aws_access_key_id = "your-aws-access-key"
@aws_secret_access_key = "your-aws-secret-access-key-id"
@mysql_bin_log_dir = "/var/lib/mysql/binlog"
@temp_dir = "/tmp/mysql-backup"</pre>
<p><a href="http://github.com/pauldowman/blog_code_examples/tree/master/mysql_s3_backup/common.rb">common.rb</a>:</p>
<pre>require "config"
require "rubygems"
require "aws/s3"
require "fileutils"

def run(command)
  result = system(command)
  raise("error, process exited with status #{$?.exitstatus}") unless result
end

def execute_sql(sql)
  cmd = %{mysql -u#{@mysql_user} -e "#{sql}"}
  cmd += " -p'#{@mysql_password}' " unless @mysql_password.nil?
  run cmd
end

AWS::S3::Base.establish_connection!(:access_key_id =&gt; @aws_access_key_id, :secret_access_key =&gt; @aws_secret_access_key, :use_ssl =&gt; true)

# It doesn't hurt to try to create a bucket that already exists
AWS::S3::Bucket.create(@s3_bucket)</pre>
<h3>Discussion</h3>
<p>To enable binary logging make sure that the MySQL config file (my.cnf) has the following line in it:</p>
<pre>log_bin = /var/db/mysql/binlog/mysql-bin</pre>
<p>The path (/var/db/mysql/binlog) can be any directory that MySQL can write to, but it needs to match the value of <code>@mysql_bin_log_dir</code> in <a href="http://github.com/pauldowman/blog_code_examples/tree/master/mysql_s3_backup/config.rb">config.rb</a>.</p>
<p>Note for EC2 users: The root volume (&#8221;/&#8221;) has limited space, it&#8217;s a good idea to use /mnt for your MySQL data files and logs.</p>
<p>The MySQL user needs to have the &#8220;RELOAD&#8221; and the &#8220;SUPER&#8221; privileges, these can be granted with the following SQL commands (which need to be executed as the MySQL root user):</p>
<pre>GRANT RELOAD ON *.* TO 'user_name'@'%' IDENTIFIED BY 'password';
GRANT SUPER ON *.* TO 'user_name'@'%' IDENTIFIED BY 'password';</pre>
<p>(Replace user_name with the value of @mysql_user in config.rb).</p>
<p>You&#8217;ll probably want to perform the full backup on a regular schedule, and the incremental backup on a more frequent schedule, but the relative frequency of each will depend on how large your database is, how frequently it&#8217;s updated, and how important it is to be able to restore quickly.  This is because for a large database mysqldump can be slow and can increase the system load noticeably, while rotating the binary log is quick and inexpensive to perform. But if your database changes normally contain many updates (as opposed to just inserts) it can be slower to restore from the binary logs.</p>
<p>To have the backups run automatically you could add something like the following to your crontab file, adjusting the times as necessary:</p>
<p><a href="http://github.com/pauldowman/blog_code_examples/tree/master/mysql_s3_backup/crontab">crontab</a>:</p>
<pre># Incremental backup every 10 minutes
*/10 * * * *  root  /usr/local/bin/incremental_backup.rb
# Full backup every day at 05:01
1 5 * * *  root  /usr/local/bin/full_backup.rb</pre>
<p>Before this can work however, two small details must be taken care of, which have been left as an exercise for the reader:</p>
<ol>
<li>When the full backup runs it should delete any binary log files that might already exist in the bucket. Otherwise the restore will try to restore them even though they&#8217;re older than the full backup.</li>
<li> The execution of the scripts should not overlap. If the full backup hasn&#8217;t finished before the incremental starts (or vice versa) the backup will be in an inconsistent state.</li>
</ol>
]]></content:encoded>
			<wfw:commentRss>http://pauldowman.com/2009/02/08/mysql-s3-backup/feed/</wfw:commentRss>
		</item>
		<item>
		<title>EC2 on Rails version 0.9.9.1 released</title>
		<link>http://pauldowman.com/2009/02/04/ec2-on-rails-version-0991-released/</link>
		<comments>http://pauldowman.com/2009/02/04/ec2-on-rails-version-0991-released/#comments</comments>
		<pubDate>Thu, 05 Feb 2009 00:55:17 +0000</pubDate>
		<dc:creator>Paul Dowman</dc:creator>
		
		<category><![CDATA[EC2]]></category>

		<category><![CDATA[EC2 on Rails]]></category>

		<category><![CDATA[Ruby on Rails]]></category>

		<guid isPermaLink="false">http://pauldowman.com/2009/02/04/ec2-on-rails-version-0991-released/</guid>
		<description><![CDATA[I finally found the time to release a new version of EC2 on Rails. It fixes some bugs, updates some software (Rails 2.2, Rubygems 1.3.1, Ubuntu 8.04.2 LTS), and includes public images for the European EC2 region.
For a full list of changes see the change log.
My next priorities are:

Integrating other people&#8217;s changes, especially Adam Greene&#8217;s [...]]]></description>
			<content:encoded><![CDATA[<p>I finally found the time to release a new version of <a href="http://ec2onrails.rubyforge.org/">EC2 on Rails</a>. It fixes some bugs, updates some software (Rails 2.2, Rubygems 1.3.1, Ubuntu 8.04.2 LTS), and includes public images for the European EC2 region.</p>
<p>For a full list of changes see the <a href="http://github.com/pauldowman/ec2onrails/blob/d7c29fd05dc2924a7fde1c46e3f58d1c1462ae72/gem/History.txt">change log</a>.</p>
<p>My next priorities are:</p>
<ol>
<li>Integrating <a href="http://github.com/pauldowman/ec2onrails/network">other people&#8217;s changes</a>, especially <a href="http://github.com/skippy/ec2onrails/commits/master/">Adam Greene&#8217;s huge changes</a> (support for <a href="http://aws.amazon.com/ebs/">EBS</a> and much more).</li>
<li>Improving (or you could say fixing!) multi-instance support. It should be as easy to manage your app running on an EC2 cluster as it is on a single instance. I&#8217;m now using this myself so I finally have the motivation! :-)</li>
<li>General robustness improvements.</li>
<li>Documentation.</li>
</ol>
<p>Please report any bugs using the <a href="http://rubyforge.org/tracker/index.php?group_id=4552&amp;atid=17558">RubyForge bug tracker</a> or <a href="http://pauldowman.com/contact">by email</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://pauldowman.com/2009/02/04/ec2-on-rails-version-0991-released/feed/</wfw:commentRss>
		</item>
		<item>
		<title>How to convert from Subversion to Git</title>
		<link>http://pauldowman.com/2008/07/26/how-to-convert-from-subversion-to-git/</link>
		<comments>http://pauldowman.com/2008/07/26/how-to-convert-from-subversion-to-git/#comments</comments>
		<pubDate>Sat, 26 Jul 2008 12:31:59 +0000</pubDate>
		<dc:creator>Paul Dowman</dc:creator>
		
		<category><![CDATA[Git]]></category>

		<category><![CDATA[Software Development]]></category>

		<guid isPermaLink="false">http://pauldowman.com/2008/07/26/how-to-convert-from-subversion-to-git/</guid>
		<description><![CDATA[When I was moving EC2 on Rails to Git I found several posts that explained how to convert a repo from svn to Git. But none of them included converting your svn tags to Git tags, so here&#8217;s yet another how-to guide. (Git experts please comment if I&#8217;m doing anything dumb.)
1. Install Git
First, you&#8217;ll need [...]]]></description>
			<content:encoded><![CDATA[<p>When I was <a href="/2008/07/26/got-git/">moving EC2 on Rails to Git</a> I found several posts that explained how to convert a repo from svn to Git. But none of them included converting your svn tags to Git tags, so here&#8217;s yet another how-to guide. (Git experts please comment if I&#8217;m doing anything dumb.)</p>
<h4>1. Install Git</h4>
<p>First, you&#8217;ll need Git installed with <a href="http://www.kernel.org/pub/software/scm/git/docs/git-svn.html">git-svn</a> included (git-svn will actually allow you to push changes back to the original Subversion repository, but for our purposes we&#8217;re assuming that this is a one-time conversion).</p>
<p>If you&#8217;re using OS X you should already be using <a href="http://www.macports.org/">MacPorts</a>, so just do:</p>
<pre>prompt&gt; sudo port install git-core +svn</pre>
<p>Or, on Ubuntu or Debian Linux:</p>
<pre>prompt&gt; sudo apt-get install <a href="http://packages.ubuntu.com/hardy/git-svn">git-svn</a></pre>
<h4>2. Create the authors file</h4>
<p>Next, create a text file that maps Subversion committers to Git authors so the names and email addresses will be correct in the history. Save it as authors.txt:</p>
<pre>
pdowman = Paul Dowman &lt;paul@hellospambot.com&gt;
svnuser2 = Another User &lt;anotheruser@whatever.com&gt;
</anotheruser@whatever.com></paul@hellospambot.com></pre>
<h4>3. Clone the repository</h4>
<p>Now run the command that will import your svn repo into a local Git repo. I&#8217;m assuming your svn repo had the standard layout of /trunk, /tags and /branches.</p>
<pre>
prompt&gt; git svn clone &lt;svn repo url&gt; --no-metadata -A authors.txt -t tags -b branches -T trunk<your_svn_ur> &lt;destination dir name&gt;
</your_svn_ur></pre>
<p>Now running <code>git log</code> should show all your commit history with the correct authors.</p>
<h4>4. Convert branches to tags</h4>
<p>There&#8217;s one more thing. All your tags are now remote branches, not tags, in your Git repo. So you&#8217;ll need to convert them manually (or write a script to do it if you have a lot, I&#8217;ll leave that as an exercise for the reader). For each Subversion tag (i.e. Git remote branch) you&#8217;ll add it as a Git tag, then delete the remote branch. List them with:</p>
<pre>promp&gt; git branch -r</pre>
<p>Then for each tag listed do:</p>
<pre>
prompt&gt; git tag tagname tags/tagname
prompt&gt; git branch -r -d tags/tagname</pre>
<p>You now have a local Git repository with all your history and tags. If you don&#8217;t need to share it with anyone else then you&#8217;re done.</p>
<h4>5. Push to a public repo (optional)</h4>
<p>If you want to publish to a public repository (for example <a href="http://github.com">Github</a>), you&#8217;ll need to add it as a remote repo and then push to it.</p>
<pre>
prompt&gt; git remote add origin git@github.com:userid/project.git
prompt&gt; git push origin master --tags</pre>
<p>You next stop should probably be the <a href="http://git.or.cz/course/svn.html">Git tutorial for Subversion users</a>. Enjoy!</p>
]]></content:encoded>
			<wfw:commentRss>http://pauldowman.com/2008/07/26/how-to-convert-from-subversion-to-git/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Got Git</title>
		<link>http://pauldowman.com/2008/07/26/got-git/</link>
		<comments>http://pauldowman.com/2008/07/26/got-git/#comments</comments>
		<pubDate>Sat, 26 Jul 2008 12:18:59 +0000</pubDate>
		<dc:creator>Paul Dowman</dc:creator>
		
		<category><![CDATA[EC2 on Rails]]></category>

		<category><![CDATA[Git]]></category>

		<category><![CDATA[Software Development]]></category>

		<guid isPermaLink="false">http://pauldowman.com/2008/07/26/got-git/</guid>
		<description><![CDATA[I&#8217;ve moved EC2 on Rails from Subversion to Git. It&#8217;s hosted on Github at pauldowman/ec2onrails.
Most Ruby developers are familiar with Git by now. (If you&#8217;re not: it&#8217;s a distributed version control system that was created in 2005 by Linus Torvalds for Linux kernel development). Within the last year almost every Ruby-based open-source project has switched [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve moved <a href="http://ec2onrails.rubyforge.org/">EC2 on Rails</a> from Subversion to <a href="http://git.or.cz/">Git</a>. It&#8217;s hosted on Github at <a href="http://github.com/pauldowman/ec2onrails">pauldowman/ec2onrails</a>.</p>
<p>Most Ruby developers are familiar with Git by now. (If you&#8217;re not: it&#8217;s a <a href="http://betterexplained.com/articles/intro-to-distributed-version-control-illustrated/">distributed version control system</a> that was <a href="http://en.wikipedia.org/wiki/Git_(software)#Early_history">created in 2005 by Linus Torvalds</a> for Linux kernel development). Within the last year almost every Ruby-based open-source project has switched to Git (including <a href="http://weblog.rubyonrails.org/2008/4/11/rails-premieres-on-github">Rails itself</a>). And in fact they&#8217;re almost all hosted on <a href="http://github.com/">Github</a>!</p>
<p>At first I found it funny that even though they were moving to a distributed version control system, everyone decided to keep their repositories in <em>the exact same place</em>. Being distributed, a Git repository doesn&#8217;t need to be hosted unless you&#8217;re sharing it. You can publish it <a href="http://www.kernel.org/pub/software/scm/git/docs/user-manual.html#setting-up-a-public-repository">easily</a> on any web server, and RubyForge (which has always been the most popular place to host Ruby projects) <a href="http://drnicwilliams.com/2008/04/08/git-for-rubyforge-accounts/">supports git</a>.</p>
<p>But after playing with it a bit I can see why everyone is choosing Github. For one thing they got the project hosting part right, with a <a href="http://www.pjhyett.com/posts/232-why-github-will-overtake-sourceforge">simple clean UI</a> and cool features like <a href="http://github.com/guides/the-github-api">an API</a> and <a href="http://github.com/blog/105-services-galore">hooks for all kinds of services</a>.</p>
<p>But the really cool thing about Github is that it provides <a href="http://www.readwriteweb.com/archives/github_a_social_network_for_programmers.php">a social environment</a>. You can watch projects as you&#8217;d expect, but you can also follow people, send them messages, and easily send them pull requests (to integrate changes you&#8217;ve made). It&#8217;s great for discovering interesting and new projects: just follow friends and people whose work you like to see what they&#8217;re watching, creating and forking.</p>
<p>Now that <a href="/projects/ruby-on-rails-ec2/">EC2 on Rails</a> is on Github it&#8217;s more likely that other people will want to build it themselves so I&#8217;ll try to make that easier with a one-step script at the root of the project. Feel free to fork it, implement changes and send me patches or pull requests.</p>
<p>And <a href="http://github.com/pauldowman">find me on Github</a>!</p>
]]></content:encoded>
			<wfw:commentRss>http://pauldowman.com/2008/07/26/got-git/feed/</wfw:commentRss>
		</item>
		<item>
		<title>EC2 on Rails version 0.9.9 released</title>
		<link>http://pauldowman.com/2008/07/23/ec2-on-rails-version-099-released/</link>
		<comments>http://pauldowman.com/2008/07/23/ec2-on-rails-version-099-released/#comments</comments>
		<pubDate>Wed, 23 Jul 2008 13:17:24 +0000</pubDate>
		<dc:creator>Paul Dowman</dc:creator>
		
		<category><![CDATA[EC2]]></category>

		<category><![CDATA[EC2 on Rails]]></category>

		<category><![CDATA[Ruby]]></category>

		<category><![CDATA[Ruby on Rails]]></category>

		<guid isPermaLink="false">http://pauldowman.com/2008/07/23/ec2-on-rails-version-099-released/</guid>
		<description><![CDATA[I released version 0.9.9 of EC2 on Rails a few weeks ago and announced it on the mailing list but forgot to mention it here. The main change was switching to version 8.04 (&#8221;Hardy&#8221;) of Ubuntu. See the change log for full details.
]]></description>
			<content:encoded><![CDATA[<p>I released version 0.9.9 of <a href="http://ec2onrails.rubyforge.org/">EC2 on Rails</a> a few weeks ago and announced it on the mailing list but forgot to mention it here. The main change was switching to version 8.04 (&#8221;Hardy&#8221;) of Ubuntu. See the <a href="http://ec2onrails.rubyforge.org/svn/tags/REL-0.9.9/gem/History.txt">change log</a> for full details.</p>
]]></content:encoded>
			<wfw:commentRss>http://pauldowman.com/2008/07/23/ec2-on-rails-version-099-released/feed/</wfw:commentRss>
		</item>
		<item>
		<title>EC2 on Rails version 0.9.8 available</title>
		<link>http://pauldowman.com/2008/05/19/ec2-on-rails-version-098-available/</link>
		<comments>http://pauldowman.com/2008/05/19/ec2-on-rails-version-098-available/#comments</comments>
		<pubDate>Mon, 19 May 2008 15:40:19 +0000</pubDate>
		<dc:creator>Paul Dowman</dc:creator>
		
		<category><![CDATA[EC2]]></category>

		<category><![CDATA[EC2 on Rails]]></category>

		<category><![CDATA[Ruby]]></category>

		<category><![CDATA[Ruby on Rails]]></category>

		<guid isPermaLink="false">http://pauldowman.com/2008/05/19/ec2-on-rails-version-098-available/</guid>
		<description><![CDATA[UPDATE: it&#8217;s 0.9.8.1 now, there was a small update to the RubyGem. The new gem uses the same AMI&#8217;s. 
EC2 on Rails version 0.9.8 is now available (or will be in a few hours when the RubyForge servers are synced). This is a recommended update for everyone.
It includes some major new features:

monit monitoring daemon: monitors [...]]]></description>
			<content:encoded><![CDATA[<p><em>UPDATE: it&#8217;s 0.9.8.1 now, there was a small update to the RubyGem. The new gem uses the same AMI&#8217;s. </em></p>
<p><a href="http://ec2onrails.rubyforge.org/">EC2 on Rails</a> version 0.9.8 is now available (or will be in a few hours when the RubyForge servers are synced). This is a recommended update for everyone.</p>
<p>It includes some major new features:</p>
<ul>
<li>monit monitoring daemon: monitors mysqld, apache, memcached, mongrels, system load and free drive space</li>
<li>incremental MySQL backup (important for large databases)</li>
<li>Apache SSL support</li>
<li>a local <a href="http://www.postfix.org/">Postfix</a> SMTP server enabled by default</li>
</ul>
<p>And most importantly this fixes the <a href="http://rubyforge.org/tracker/index.php?func=detail&amp;aid=20040&amp;group_id=4552&amp;atid=17558">problem with broken Ubuntu package updates</a> which was caused by a missing repository in the list of repositories.</p>
<p>As I <a href="/2008/05/18/open-source-made-my-life-easier-today/">mentioned yesterday</a>, the base image is now built using <a href="http://alestic.com/">Eric Hammond&#8217;s EC2 Ubuntu</a> script.</p>
<p>Also, there are major new features such as incremental MySQL backup (important for large databases), Apache SSL support, and a local Postfix SMTP server enabled by default.</p>
<p>My priorities now are:</p>
<ol>
<li>Release an update based on Ubuntu 8.04 Hardy (this version is still using Ubuntu 7.10 Gutsy because I wanted to provide a reliable update as quickly as possible due to bug #20040. But now that the base image is built with Eric Hammond&#8217;s script it should be easy to update to Hardy.)</li>
<li>Create complete documentation.</li>
<li>Release a 100% bug-free version 1.0 with the current feature-set. Please help by reporting any bugs you find, either using the <a href="http://rubyforge.org/tracker/index.php?group_id=4552&amp;atid=17558">RubyForge bug tracker</a> or <a href="/contact">by email</a>.</li>
</ol>
]]></content:encoded>
			<wfw:commentRss>http://pauldowman.com/2008/05/19/ec2-on-rails-version-098-available/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Open Source made my life easier today</title>
		<link>http://pauldowman.com/2008/05/18/open-source-made-my-life-easier-today/</link>
		<comments>http://pauldowman.com/2008/05/18/open-source-made-my-life-easier-today/#comments</comments>
		<pubDate>Sun, 18 May 2008 22:02:14 +0000</pubDate>
		<dc:creator>Paul Dowman</dc:creator>
		
		<category><![CDATA[EC2]]></category>

		<category><![CDATA[EC2 on Rails]]></category>

		<guid isPermaLink="false">http://pauldowman.com/2008/05/18/open-source-made-my-life-easier-today/</guid>
		<description><![CDATA[The point of EC2 on Rails is to save other people from duplicating the effort of building and configuring a Rails server on EC2. When I started it there were no other public Ubuntu server image projects so I had to start from scratch. I had to write a build script to build an Ubuntu [...]]]></description>
			<content:encoded><![CDATA[<p>The point of <a href="/projects/ruby-on-rails-ec2/">EC2 on Rails</a> is to save other people from duplicating the effort of building and configuring a Rails server on EC2. When I started it there were no other public Ubuntu server image projects so I had to start from scratch. I had to write a build script to build an Ubuntu image, patch the Amazon AMI tools to work on Ubuntu, etc., before I could even begin to create the Rails-specific stuff. And every 6 months there&#8217;s a new version of Ubuntu and I have to do at least some of that over again.</p>
<p>But in the meantime Eric Hammond has created an excellent <a href="http://alestic.com/">Ubuntu AMI base install project</a>, it has all the necessary features like installing the AMI tools, getting the public keys on first boot so that you can log in with your EC2 account&#8217;s private key, regenerating the ssh host keys on first boot, etc. And it has some cool new features like the ability to <a href="http://groups.google.com/group/ec2ubuntu/browse_thread/thread/c228d509ef31c630">give an instance an arbitrary script on startup</a> using EC2&#8217;s &#8220;<a href="http://docs.amazonwebservices.com/AWSEC2/2008-02-01/DeveloperGuide/AESDG-chapter-instancedata.html#instancedata-user-data-retrieval" id="d0e4468">user-supplied </a><a href="http://docs.amazonwebservices.com/AWSEC2/2008-02-01/DeveloperGuide/AESDG-chapter-instancedata.html#instancedata-user-data-retrieval">instance data</a>&#8220;. And, it has an <a href="http://groups.google.com/group/ec2ubuntu">active community</a>.</p>
<p>So why would I duplicate that effort?! I&#8217;d rather concentrate on improving the Rails-specific features, so I&#8217;ve adapted my build script to be run from Eric&#8217;s. And by &#8220;adapted&#8221;, I mean &#8220;took out tons of stuff that I no longer need to care about&#8221;! And when I want to make any improvements that aren&#8217;t Rails-specific, I can contribute them to Eric&#8217;s project where they&#8217;ll benefit more people.</p>
<p>If you&#8217;re building your own custom AMI, I highly recommend using Eric&#8217;s base install script. You&#8217;ll end up with a solid base for your image with way less work, and it has a hook to easily include your own build script to customize the build.</p>
<p>Version 0.9.8 of EC2 on Rails uses Eric&#8217;s script for the base install, and it will be released in a couple of days (I&#8217;m using it in production already).</p>
<p>Seriously, why reinvent the wheel? You gotta love open source!</p>
]]></content:encoded>
			<wfw:commentRss>http://pauldowman.com/2008/05/18/open-source-made-my-life-easier-today/feed/</wfw:commentRss>
		</item>
		<item>
		<title>A rock-solid setup for sending SMTP mail from your EC2 web server</title>
		<link>http://pauldowman.com/2008/02/17/smtp-mail-from-ec2-web-server-setup/</link>
		<comments>http://pauldowman.com/2008/02/17/smtp-mail-from-ec2-web-server-setup/#comments</comments>
		<pubDate>Sun, 17 Feb 2008 20:53:48 +0000</pubDate>
		<dc:creator>Paul Dowman</dc:creator>
		
		<category><![CDATA[EC2]]></category>

		<category><![CDATA[Linux]]></category>

		<category><![CDATA[Mail]]></category>

		<category><![CDATA[Software Development]]></category>

		<category><![CDATA[Systems]]></category>

		<guid isPermaLink="false">http://pauldowman.com/2008/02/17/smtp-mail-from-ec2-web-server-setup/</guid>
		<description><![CDATA[(None of this is EC2-centric, but it&#8217;s particularly needed on EC2.)
A frequent topic of discussion on the EC2 forums is how to send email reliably, efficiently, and especially without it being marked as spam. I found that even with a valid SPF record most mail sent from an EC2 instance was marked as spam or [...]]]></description>
			<content:encoded><![CDATA[<p><em>(None of this is EC2-centric, but it&#8217;s particularly needed on EC2.)</em></p>
<p>A frequent topic of discussion on the EC2 forums is how to send email reliably, efficiently, and especially without it being marked as spam. I found that even with a valid <a href="http://www.openspf.org/Introduction">SPF record</a> most mail sent from an EC2 instance was marked as spam or silently discarded.</p>
<p>This is probably partly because of the lack of matching <a href="http://www.spamhaus.org/faq/answers.lasso?section=ISP%20Spam%20Issues#131">reverse DNS records</a>. But spam filters can be a bit arbitrary and the easiest way is to relay outgoing mail through a good smtp provider. (I don&#8217;t recommend relaying outbound mail through Google Apps, they supposedly have a 500 messages/day limit according to many people on their forums, although I couldn&#8217;t find that published anywhere. UPDATE: The info is <a href="http://www.google.com/support/a/bin/answer.py?hl=en-ca&amp;answer=59797">here</a>, thanks John Ward.)</p>
<p>I have tried a couple of SMTP providers, and <strong>I recommend <a href="http://www.authsmtp.com/">AuthSMTP</a></strong>. They are reliable, have good service, and our mail that&#8217;s delivered through them almost never gets marked as spam. Also, they have monthly quotas rather than daily, so you have a chance to increase it before you hit the limit.</p>
<p>Rather than deliver directly to the AuthSMTP mail server from your web app it&#8217;s a good idea to deliver to a local queueing mail server, which will forward via the AuthSMTP gateway. Your web app will deliver mail to localhost (or perhaps a dedicated instance if you prefer), port 25.</p>
<p>This has several advantages:</p>
<ol>
<li>Your web server can finish the request more quickly.</li>
<li>There&#8217;s less chance that the mail server will be unavailable. At least the mail will be queued locally until the remote server becomes available again. AuthSMTP has proven to be quite reliable, but it has been unavailable on a couple of occasions.</li>
<li><a href="http://www.authsmtp.com/faqs/faq-61.html">AuthSMTP limits the number of concurrent connections</a> that you can make. You can easily configure your local mail server to limit the number of outgoing connections to the gateway.</li>
</ol>
<h4>Configuration</h4>
<p>I recommend using <a href="http://www.postfix.org/">Postfix</a>, it&#8217;s fast, reliable and most importantly, easy to configure. Your Linux distribution will definitely have a Postfix <a href="http://packages.ubuntu.com/gutsy/mail/postfix">package</a> available (it comes pre-installed on <a href="http://ec2onrails.rubyforge.org/">EC2 on Rails</a>). On Debian or Ubuntu install with:</p>
<pre>sudo aptitude install postfix</pre>
<p>Here&#8217;s the config file, <code>/etc/postfix/main.cf</code>:</p>
<pre>myhostname = www.YOURDOMAIN.com
mydomain = YOURDOMAIN.com
myorigin = $mydomain

smtpd_banner = $myhostname ESMTP $mail_name
biff = no
append_dot_mydomain = no

alias_maps = hash:/etc/aliases
alias_database = hash:/etc/aliases
mydestination = localdomain, localhost, localhost.localdomain, localhost
mynetworks = 127.0.0.0/8
mailbox_size_limit = 0
recipient_delimiter = +

# SECURITY NOTE: Listening on all interfaces. Make sure your firewall is
# configured correctly
inet_interfaces = all

relayhost = [mail.authsmtp.com]
smtp_connection_cache_destinations = mail.authsmtp.com
smtp_sasl_auth_enable = yes
smtp_sasl_password_maps = static:YOUR_AUTHSMPT_USER_ID:YOUR_AUTHSMTP_PW
smtp_sasl_security_options = noanonymous

default_destination_concurrency_limit = 4

soft_bounce = yes</pre>
<p>How simple is that?! Have you ever seen a sendmail config file?</p>
<p><code>soft_bounce</code> is important because it means that postfix will queue the messages if they&#8217;re bounced by the remote gateway for any reason (this is only if it&#8217;s bounced by the gateway, not if it&#8217;s bounced by the destination server). This would usually be caused by some configuration problem like an authentication failure. If the message is bounced by the eventual destination server (e.g. the mailbox doesn&#8217;t exist or is full), or if the destination server can&#8217;t be contacted, your local server won&#8217;t know about it because the message has already been accepted by the gateway. (It&#8217;s probably a good idea to keep track of bounced messages returned by the eventual destination server, see &#8220;Don&#8217;t spoof the From field&#8221; below.)</p>
<p><code>default_destination_concurrency_limit</code> is so you stay within <a href="http://www.authsmtp.com/faqs/faq-61.html">AuthSMTP&#8217;s concurrent connection limit</a>. If you have Postfix running on multiple instances you&#8217;ll need to adjust this accordingly.</p>
<p>To see mail that&#8217;s stuck in the queue:</p>
<pre>mailq</pre>
<p>Postfix will automatically try to resend it, but you can force it to be sent immediately using:</p>
<pre>sudo postqueue -f</pre>
<h4>Monitoring</h4>
<p>Of course you need to know if anything goes wrong with the mail delivery and it won&#8217;t be in your web app&#8217;s log. I use scripts in /etc/cron.hourly to check logs and mail me the output if there are errors. But when it comes you mail delivery failure you might have a bit of a chicken-and-egg problem: you can&#8217;t use postfix to send the mail if postfix is having problems. Here&#8217;s a simple ruby script to send emergency mail via a different mail server. It&#8217;s configured to use Google Apps (you&#8217;ll need to create a new account to send the mail from), if you don&#8217;t use Google Apps you can easily change this to use a different mail server.</p>
<p>Save this as <code>/usr/local/bin/emergency_mail_sender</code>:</p>
<pre>#!/usr/bin/env ruby

# This is a simple script to send mail via an alternate server when there are
# errors with the normal queueing mail sender
# The subject is the first command-line arg and the body is received on stdin

#################################

from_address             = "admin_mail_sender@YOURDOMAIN.com"
to_address               = "admin@YOURDOMAIN.com"
smtp_server              = "smtp.gmail.com"
smtp_port                = 587
smtp_mail_from_domain    = "YOURDOMAIN.com"
smtp_account_name        = "admin_mail_sender@YOURDOMAIN.com"
smtp_password            = "YOUR_PASSWORD"
smtp_authentication_type = :plain
debug                    = false

#################################

subject = ARGV[0]
body = $stdin.read

require 'rubygems'
require 'net/smtp'
require 'tlsmail'

exit if body.nil? || body == ""

msgstr = &lt;&lt;END_OF_MESSAGE
Subject: #{subject}

#{body}
END_OF_MESSAGE

Net::SMTP.enable_tls(OpenSSL::SSL::VERIFY_NONE)
  smtp = Net::SMTP.new(smtp_server, smtp_port)
  smtp.set_debug_output $stderr if debug
  smtp.start(smtp_mail_from_domain, smtp_account_name, smtp_password, smtp_authentication_type) do |s|
    s.send_message msgstr, from_address, to_address
end<end_of_message></end_of_message></pre>
<p>Here&#8217;s a script that can be run by cron every hour to check for mail delivery problems, it uses the <code>emergency_mail_sender</code> script to notify you of the problem. It works on Ubuntu (but it needs the <a href="http://packages.ubuntu.com/gutsy/admin/logtail">logtail</a> package installed), it might not work on other systems. Save this as <code>/etc/cron.hourly/check_mail_logs</code></p>
<pre>#!/bin/sh
hostname=`hostname -s`
mailer=/usr/local/bin/emergency_mail_sender
/usr/sbin/logtail -f/var/log/mail.warn | $mailer "$hostname: mail warnings"
/usr/sbin/logtail -f/var/log/mail.err | $mailer "$hostname: mail errors"
/usr/sbin/logtail -f/var/log/syslog | grep 'status=' | egrep -v 'status=sent' | $mailer "$hostname: undelivered mail"</pre>
<h4>SPF</h4>
<p>Here&#8217;s your <a href="http://www.openspf.org/Introduction">SPF</a> record:</p>
<pre>v=spf1 include:authsmtp.com include:aspmx.googlemail.com ~all</pre>
<p>If you&#8217;re not using Google Apps to send mail for your domain remove <code>include:aspmx.googlemail.com</code>. If you want to create your own SPF record there&#8217;s a good SPF record generator at <a href="http://spfwizard.com/">spfwizard.com</a>.</p>
<h4>Don&#8217;t spoof the From field</h4>
<p>You should only send mail from somebody@yourdomain.com. If you try to send mail from somebody@pauldowman.com, for example, the receiver will see that pauldowman.com has an SPF record, and that it doesn&#8217;t authorize your mail server. Then into the spam folder you go.</p>
<p>To get around this you can send from something like <em>noreply@yourdomain.com</em>, and set the Reply-To header to <em>somebody@pauldowman.com</em>. You can even set the name in the from field, for example: <em>&#8220;Paul Dowman via yoursite&#8221; &lt;noreply@pauldowman.com&gt;</em>. The Reply-To header will make sure that most people&#8217;s replies go to the correct address, but a few will inevitably end up at noreply@yourdomain.com so it&#8217;s probably a good idea to set up an autoresponder at that address, or at least make sure the message bounces so the user eventually realizes the mistake.</p>
]]></content:encoded>
			<wfw:commentRss>http://pauldowman.com/2008/02/17/smtp-mail-from-ec2-web-server-setup/feed/</wfw:commentRss>
		</item>
		<item>
		<title>RubyFringe, Toronto, July 18-20, 2008</title>
		<link>http://pauldowman.com/2008/02/17/rubyfringe-toronto-july-18-20-2008/</link>
		<comments>http://pauldowman.com/2008/02/17/rubyfringe-toronto-july-18-20-2008/#comments</comments>
		<pubDate>Sun, 17 Feb 2008 20:51:16 +0000</pubDate>
		<dc:creator>Paul Dowman</dc:creator>
		
		<category><![CDATA[Ruby]]></category>

		<category><![CDATA[Ruby on Rails]]></category>

		<category><![CDATA[Toronto]]></category>

		<guid isPermaLink="false">http://pauldowman.com/2008/02/17/rubyfringe-toronto-july-18-20-2008/</guid>
		<description><![CDATA[There&#8217;s going to be a great Ruby conference in Toronto this summer: RubyFringe. Actually, maybe it&#8217;s not a Ruby conference, it&#8217;s &#8220;an avant-garde conference for developers that are excited             about emerging technologies outside of the Ruby on Rails monoculture&#8221;.
 RubyFringe is a single-track [...]]]></description>
			<content:encoded><![CDATA[<p>There&#8217;s going to be a great Ruby conference in Toronto this summer: <a href="http://rubyfringe.com/">RubyFringe</a>. Actually, maybe it&#8217;s not a Ruby conference, it&#8217;s &#8220;an avant-garde conference for developers that are excited             about emerging technologies outside of the Ruby on Rails monoculture&#8221;.</p>
<blockquote><p> RubyFringe is a single-track indie conference with no paid technical               sponsors and a target attendance of 150.</p>
<p class="thing_list">               It will run for two days (plus an opening night), with roughly               10 speakers or panels each day.</p>
</blockquote>
<p class="thing_list">There&#8217;s a kick-ass list of <a href="http://rubyfringe.com/speakers">speakers</a>, including out-of-towners like <a href="http://brainspl.at/">Ezra Zygmuntowicz</a>, <a href="http://www.zedshaw.com/">Zed Shaw</a> (now&#8217;s your chance to <a href="http://www.zedshaw.com/rants/rails_is_a_ghetto.html">fight him</a>! ;-), <a href="http://blog.obiefernandez.com/">Obie Fernandez</a>, and local Torontonians like <a href="http://weblog.raganwald.com/">Reg Braithwaite</a> and <a href="http://hyperbio.net/">Leila Boujnane</a>.</p>
<p>Registration opens tomorrow.</p>
<p>See you there!</p>
]]></content:encoded>
			<wfw:commentRss>http://pauldowman.com/2008/02/17/rubyfringe-toronto-july-18-20-2008/feed/</wfw:commentRss>
		</item>
		<item>
		<title>GigPark is hiring!</title>
		<link>http://pauldowman.com/2007/11/27/gigpark-is-hiring/</link>
		<comments>http://pauldowman.com/2007/11/27/gigpark-is-hiring/#comments</comments>
		<pubDate>Tue, 27 Nov 2007 21:57:49 +0000</pubDate>
		<dc:creator>Paul Dowman</dc:creator>
		
		<category><![CDATA[GigPark]]></category>

		<category><![CDATA[Ruby on Rails]]></category>

		<category><![CDATA[Toronto]]></category>

		<guid isPermaLink="false">http://pauldowman.com/2007/11/27/gigpark-is-hiring/</guid>
		<description><![CDATA[GigPark is a Toronto-based web startup. We&#8217;re just a couple of weeks out of beta, growing fast and looking for a great developer to join us.
The site is built with Ruby on Rails and hosted on EC2.
If this sounds exciting to you, or if you know someone who might be a good fit, please see [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.gigpark.com/">GigPark</a> is a Toronto-based web startup. We&#8217;re just a couple of weeks out of beta, growing fast and looking for a great developer to join us.</p>
<p>The site is built with Ruby on Rails and hosted on EC2.</p>
<p>If this sounds exciting to you, or if you know someone who might be a good fit, please see <a href="http://www.gigpark.com/page/jobs">our jobs page</a> for details.</p>
<p><em> UPDATE January 2008: </em><a href="http://blog.gigpark.com/2008/01/28/five-heads-are-better-than-three/"><em>we&#8217;ve hired two kick-ass developers!</em></a></p>
]]></content:encoded>
			<wfw:commentRss>http://pauldowman.com/2007/11/27/gigpark-is-hiring/feed/</wfw:commentRss>
		</item>
		<item>
		<title>EC2 on Rails now with multiple instance support, Ubuntu 7.10, 64-bit version, Capistrano tasks</title>
		<link>http://pauldowman.com/2007/10/28/ec2onrails-0_9_5/</link>
		<comments>http://pauldowman.com/2007/10/28/ec2onrails-0_9_5/#comments</comments>
		<pubDate>Sun, 28 Oct 2007 18:49:33 +0000</pubDate>
		<dc:creator>Paul Dowman</dc:creator>
		
		<category><![CDATA[EC2]]></category>

		<category><![CDATA[EC2 on Rails]]></category>

		<category><![CDATA[Linux]]></category>

		<category><![CDATA[Ruby on Rails]]></category>

		<category><![CDATA[Software Development]]></category>

		<category><![CDATA[Systems]]></category>

		<category><![CDATA[Virtualization]]></category>

		<guid isPermaLink="false">http://pauldowman.com/2007/10/28/ec2onrails-0_9_5/</guid>
		<description><![CDATA[I&#8217;ve been working hard on EC2 on Rails, version 0.9.5 is now available. Since my last post here there have been some major changes:
Capistrano tasks
There is now a rubygem available that provides Capistrano tasks to manage the instance. There are tasks to set the server&#8217;s timezone,  install packages and rubygems, backup, restore, create and [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve been working hard on <a href="http://ec2onrails.rubyforge.org/">EC2 on Rails</a>, version 0.9.5 is now available. Since my last post here there have been some major changes:</p>
<h3>Capistrano tasks</h3>
<p>There is now a rubygem available that provides Capistrano tasks to manage the instance. There are tasks to set the server&#8217;s timezone,  install packages and rubygems, backup, restore, create and delete the database, set the MySQL root password, and more. To use these in your Rails project type:</p>
<pre>&gt; sudo gem install ec2onrails</pre>
<p>Put <a href="http://ec2onrails.rubyforge.org/svn/trunk/documentation/examples/Capfile">Capfile</a>  in the root of your rails folder, and put <a href="http://ec2onrails.rubyforge.org/svn/trunk/documentation/examples/deploy.rb">deploy.rb</a> in the config folder.</p>
<p>Then, from the root of your project type:</p>
<pre>&gt; cap ec2onrails:setup</pre>
<p>This automatically sets your server&#8217;s timezone, installs any custom rubygems and Ubuntu packages, and creates your database for you. You can now deploy your rails app as you normally would:</p>
<pre>&gt; cap deploy:migrations</pre>
<p>Another useful task for testing is:</p>
<pre>&gt; cap ec2onrails:restore_db_and_deploy</pre>
<p>This recreates the database, restores data from an S3 bucket (specified in your deploy.rb), and deploys the app. I use this to prepare a staging server with the current production data and current production version of the app. After running this task I have an exact copy of my production server. I then deploy the latest version to this server before deploying it to production. This is a good way to be really sure your production deployment won&#8217;t fail (especially your migrations).</p>
<p>To see a list of all available Capistrano tasks:</p>
<pre>&gt; cap -T</pre>
<h3>New Ubuntu version</h3>
<p>It&#8217;s now built with <a href="http://www.ubuntu.com/news/ubuntu-server710">Ubuntu 7.10 &#8220;Gutsy&#8221;</a>.</p>
<h3>Support for new instance types</h3>
<p>There are both i386 and x86_64 versions available to support the new EC2 <a href="http://www.amazon.com/gp/browse.html?node=370375011">instance types</a>. So you can now use large and extra-large instances.</p>
<h3>Multiple instances</h3>
<p>The earlier versions only worked if your rails app was running on a single server. That was lame! Now you can have multiple instances using any combination of these roles: web server, app server, primary database. I&#8217;m working on adding a MySQL slave role and eventually a <a href="http://www.danga.com/memcached/">Memcache</a> role.</p>
<p>For full instructions and details see <a href="http://ec2onrails.rubyforge.org/">the project web site</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://pauldowman.com/2007/10/28/ec2onrails-0_9_5/feed/</wfw:commentRss>
		</item>
		<item>
		<title>FieldHints update</title>
		<link>http://pauldowman.com/2007/09/05/fieldhints-1_0/</link>
		<comments>http://pauldowman.com/2007/09/05/fieldhints-1_0/#comments</comments>
		<pubDate>Thu, 06 Sep 2007 00:05:19 +0000</pubDate>
		<dc:creator>Paul Dowman</dc:creator>
		
		<category><![CDATA[FieldHints]]></category>

		<category><![CDATA[JavaScript]]></category>

		<category><![CDATA[Software Development]]></category>

		<category><![CDATA[Web]]></category>

		<guid isPermaLink="false">http://pauldowman.com/2007/09/05/fieldhints-update/</guid>
		<description><![CDATA[I have released an update to FieldHints. This version fixes a bug with refreshing a FieldHints-enabled form field using AJAX.
]]></description>
			<content:encoded><![CDATA[<p>I have released an update to <a href="/projects/fieldhints/">FieldHints</a>. This version fixes a bug with refreshing a FieldHints-enabled form field using AJAX.</p>
]]></content:encoded>
			<wfw:commentRss>http://pauldowman.com/2007/09/05/fieldhints-1_0/feed/</wfw:commentRss>
		</item>
	</channel>
</rss>
