Backup Your Rails App To Amazon S3

May 30th, 2008

Posted by Steve Butterworth

Backup is one of those boring subjects that is really important. Lots of hosts claim to backup your data but where is it? You basically have to trust that they are doing this and trust that you can get hold of it when you ask them. In my book thats a lot of trust with your oh so valuable data so best to do your own backups.

Amazon's S3 service is a great options for data backups and thanks to the brilliant AWS::S3 gem its not difficult to implement either. I thought I'd post some of my work here as it is a nice simple example of using the AWS:S3 gem for backups using rake. After installing the gem with sudo gem i aws-s3 I ran script/console and manually created a couple of S3 buckets for my data (these are kind of like folder). The nice thing about doing this manually is you can check all your S3 credentials are working OK as well as the gem is installed correctly.


AWS::S3::Base.establish_connection!(
      :access_key_id     => 'your key id',
      :secret_access_key => 'your secret key'
  )

AWS::S3::Bucket.create('humble_daily_backup')
AWS::S3::Bucket.create('humble_weekly_backup')

Great now we have our buckets. If something went wrong here you probably need to check your keys and that your bucket names are unique.

Now create a rake file in your rails lib/tasks folder, something like utils.rake and then paste the following code into it. The idea is that it has daily rolling backups so the last 7 days of backups are kept and also persistent weekly backups. For the daily backups I use the week day name as the file name that way I can easily delete the file from 8 days ago and create the new one. For weekly backups we just use the date.


namespace :utils do
  
  desc "Backup the databases to Amazon S3 daily"
  task(:daily_backup) do
    backup_to_s3('humble_daily_backup', Date.today.strftime("%A"))
  end
  
  desc "Backup the databases to Amazon S3 Weekly"
  task(:weekly_backup) do
    backup_to_s3('humble_weekly_backup', Date.today.strftime("%Y-%m-%d"))
  end
    
  private
  
  def backup_to_s3(bucket, backup_name)
    
    require 'yaml'
    require 'rubygems'
    require 'aws/s3'

    app_dir = '/full/path/to/your/app/current'
   
    dump       = "humble_#{backup_name}.sql.gz" 
    config = YAML::load(open(app_dir + '/config/database.yml'))['production']
    cmd    = "mysqldump -u #{config['username']} -p#{config['password']} -h localhost --add-drop-table --add-locks --extended-insert --lock-tables #{config['database']} | gzip -cf9 > #{dump}" 

    puts 'Getting ready to create a backup'
    `#{cmd}`
    
    puts 'Backup created, starting the transfer offsite'
    AWS::S3::Base.establish_connection!(
      :access_key_id     => 'your key id',
      :secret_access_key => 'your secret key'
    )
    
    AWS::S3::S3Object.delete(dump, bucket) if AWS::S3::S3Object.exists?(dump, bucket) 
    AWS::S3::S3Object.store(dump, open(dump), bucket)
    
    puts 'Offsite transfer completed'
    
    cmd       = "rm -f #{dump}" 
    `#{cmd}`
    puts 'Local copy of database dump deleted'
  
  end

So now you have this rake task you can run them manually with


rake utils:daily_backup
rake utils:weekly_backup

To make them run automatically which is obviously what you want for daily and weekly backups we need to add some cron jobs. So here they are...


0 0 * * * bash -c 'cd /full/path/to/your/app/current/; /usr/local/bin/rake utils:daily_backup >> /full/path/to/your/app/current/log/daily_backup.log 2>&1'
0 0 * * 0 bash -c 'cd /full/path/to/your/app/current/; /usr/local/bin/rake utils:weekly_backup >> /full/path/to/your/app/current/log/weekly_backup.log 2>&1'

Now the icing on the cake. If your on a mac try this great little S3 GUI. We can now check that our backups are working properly with this GUI and grab data backups if and when we need to recreate our database.

Sorry, comments are closed for this article.