Screencast: Deploying to AWS/EC2, Part 2

November 23rd, 2009 Leave a comment Go to comments

The screencast link is at the bottom; read the screencast “script” first!

In this screencast, we’ll set up a server with all of the necessary software for Apache2, MySQL, and building Ruby.

Note that for the course, I will be supplying a pre-built AMI, so you can skip this step if you just want to deploy to EC2.

Note as well that to follow this screencast, you must edit some files; in the screencast, I use vi (or vim). If you don’t know how to edit files on Linux, this will be a problem. If it is a problem, let me know and I can suggest ways to get this done without an editor.

Here we go:

  1. In the previous screencast, I advised you to open up port 3000 for the “basic” security group. Make sure you’ve done this.
  2. Create an instance using AMI image ami-1515f67c, in the us-east-1a availability zone (see the prior screencast for more on how to do this). And do not forget to include the “basic” security group!
  3. Log in with your key. For a public key named id-jgn-demo and a public DNS name of ec2-174-129-169-212.compute-1.amazonaws.com (to get the public instance name, right click on the instance in Elasticfox, and you will see a menu item to copy it to the clipboard), it would look like this:
    ssh -i id-jgn-demo ubuntu@ec2-174-129-169-212.compute-1.amazonaws.com
    
  4. You’re logged in as ubuntu. For the installation process, you will need to be root. So . . .
    sudo bash
    
  5. apt-get is the Ubuntu utility for managing installed packages. First, update your package system:
    apt-get update
    

    Then install a selection of packages (to find out what each package is for, you can check this list: http://packages.ubuntu.com/karmic/allpackages?format=txt.gz):

    apt-get -y install libc6-dev libssl-dev libmysql++-dev libsqlite3-dev make build-essential libssl-dev libreadline5-dev zlib1g-dev mysql-server mysql-client libmysqlclient15-dev apache2-mpm-prefork apache2-prefork-dev libapr1-dev libaprutil1-dev postfix
    

    When you are asked multiple times for a password for the MySQL root user, I would recommend that you press return for an empty password. This is not especially secure, but it will make some later setup easier. This is not a course in system management or security. You will also be asked some questions about Postfix (SMTP server); take the defaults.

  6. Download, compile, and install Ruby 1.9:
    cd /tmp
    wget ftp://ftp.ruby-lang.org/pub/ruby/1.9/ruby-1.9.1-p243.tar.gz
    tar xzf ruby-1.9.1-p243.tar.gz
    cd ruby-1.9.1-p243
    ./configure --enable-shared
    make
    make install
    
  7. Download and install RubyGems:
    cd /tmp
    wget http://files.rubyforge.vm.bytemark.co.uk/rubygems/rubygems-1.3.5.tgz
    tar xzf rubygems-1.3.5.tgz
    cd rubygems-1.3.5
    ruby setup.rb
    
  8. Download, compile, and install the native MySQL driver:
    cd /tmp
    wget http://rubyforge.org/frs/download.php/51087/mysql-ruby-2.8.1.tar.gz
    tar xzvf mysql-ruby-2.8.1.tar.gz
    cd mysql-ruby-2.8.1
    sudo ruby extconf.rb
    make
    sudo make install
    
  9. Now, a few Gems. We’ll want the Sqlite3 Gem, which may be handy if you decide not to use MySQL, the Gem for Passenger (Rails/Apache2 integration), and the Rails Gem (for 2.3.3). We are specifying “–no-ri –no-rdoc” to suppress the installation of the docs, since we shouldn’t need them on our production system.
    gem install rake sqlite3-ruby passenger --no-ri --no-rdoc
    gem install rails -v 2.3.3 --no-ri --no-rdoc
    
  10. Remember that you’re currently root. Press Control-D to end your sudo session, and return to being the “ubuntu” user.
  11. Now let’s create a quick test application. Notice that we’re going to run our migrations a second time in production mode:
    rails myapp
    cd myapp
    script/generate scaffold Publication title:string description:text
    rake db:migrate
    RAILS_ENV=production rake db:migrate
    

    For a quick verification, we’re just going to run the server in development mode on port 3000:

    script/server
    

    And browse into your server from your own computer, and try out the Publications scaffold. For the public name given above, it would be: http://ec2-174-129-169-212.compute-1.amazonaws.com/publications

    By the way, the main reason to run your server at this point in development mode is so that you can see exception traces. If you ran it in production mode, and there was an error, the browser would just give you a standard error page. To be sure, we could look at the server output, but at this stage it is convenient to see any error that a single request generates.

  12. Works? Great. Control-C. Now take note of the directory in which you’ve created your application; we’re going to need that directory for the next step. For example, if you’ve followed these instructions scrupulously, your test app is in /home/ubuntu/myapp. You can check with the “pwd” command.
  13. To set up Passenger, we’ll need to be root again. So sudo bash, and then install the Passenger module for Apache2:
    sudo bash
    passenger-install-apache2-module
    

    During this install, some instructions were displayed regarding the configuration of Apache2. Here they are:

    Please edit your Apache configuration file, and add these lines:
    
       LoadModule passenger_module /usr/local/lib/ruby/gems/1.9.1/gems/passenger-2.2.7/ext/apache2/mod_passenger.so
       PassengerRoot /usr/local/lib/ruby/gems/1.9.1/gems/passenger-2.2.7
       PassengerRuby /usr/local/bin/ruby
    
    After you restart Apache, you are ready to deploy any number of Ruby on Rails
    applications on Apache, without any further Ruby on Rails-specific
    configuration!
    

    and

    Suppose you have a Rails application in /somewhere. Add a virtual host to your
    Apache configuration file and set its DocumentRoot to /somewhere/public:
    
       <VirtualHost *:80>
          ServerName www.yourhost.com
          DocumentRoot /somewhere/public    # <-- be sure to point to 'public'!
          <Directory /somewhere/public>
             AllowOverride all              # <-- relax Apache security settings
             Options -MultiViews            # <-- MultiViews must be turned off
          </Directory>
       </VirtualHost>
    

    Additional configuration for Apache2 goes into files in /etc/apache2/conf.d, so we are going to put the first set of configurations i /etc/apache2/conf.d/passenger. Mine looks like this:

    LoadModule passenger_module /usr/local/lib/ruby/gems/1.9.1/gems/passenger-2.2.7/ext/apache2/mod_passenger.so
    PassengerRoot /usr/local/lib/ruby/gems/1.9.1/gems/passenger-2.2.7
    PassengerRuby /usr/local/bin/ruby
    

    Next, we’re going to put the second block of configuration into /etc/apache2/sites-available/default — there is already a file there, but you can overwrite it.

    Mine looks like this:

    <VirtualHost *:80>
      ServerName ec2-174-129-169-212.compute-1.amazonaws.com
      DocumentRoot /home/ubuntu/myapp/public
      <Directory /home/ubuntu/myapp/public>
         AllowOverride all
         Options -MultiViews
      </Directory>
    </VirtualHost>
    

    (There is also a directory called under /etc/apache2 called sites-enabled/ — the files here are symlinked to the files in sites/available. If you look, you’ll see a file in /etc/apache2/sites-enabled/000-default; that’s symlinked to /etc/apache2/sites-available/default)

  14. Regrettably, there is a nasty bug in the version of Rack (server layer) that ships with Passenger. You must edit the file /usr/local/lib/ruby/gems/1.9.1/gems/passenger-2.2.7/vendor/rack-1.0.0-git/lib/rack/rewindable_input.rb and change the line
    if filesystem_has_posix_semantics?
    

    to

    if filesystem_has_posix_semantics? && "#{RUBY_VERSION}.#{RUBY_PATCHLEVEL}" < "1.9.1.152"
    
  15. To restart Apache2, make sure you’re currently root, and enter
    /etc/init.d/apache2 restart
    

    Now browse in again to verify. Apps running under Passenger are running in production mode, and production apps will run on port 80. So you would browse to (changing your host name with mine) http://ec2-174-129-169-212.compute-1.amazonaws.com/publications

  16. Everything work? Great. On to the Capistrano! (Next screencast.)

Click for screencast

  1. Ken
    December 5th, 2009 at 21:21 | #1

    On Windows, using the cmd as the shell, the windows that pop up during the MySQL installation are not nicely rendered. An upper ASCII problem. Maybe this is better from Cygwin bash?

  2. December 5th, 2009 at 21:24 | #2

    @Ken

    Hmm . . . you might try switching into bash first, and see if that helps.

    Another possibility would be to use putty (google for the download) as your ssh client; but this requires converting the Unix-style ssh key to a format compatiblity with putty; still, putty is very, very good. And free).

  3. Ken
    December 5th, 2009 at 21:58 | #3

    In the screencast on step 14, you neglect to paste the && into the altered line. You only paste "#{RUBY_VERSION}.#{RUBY_PATCHLEVEL}" < "1.9.1.152".

  4. December 6th, 2009 at 07:24 | #4

    @Ken

    I think I added a comment to that effect a bit further in the screencast (when I go in and fix the wrongly-pasted code).

  5. Ken Busch
    December 6th, 2009 at 16:09 | #5

    This instructions were easy to follow -- even on Windows.

  6. DavidL
    December 14th, 2009 at 23:57 | #6

    Is there a pre-built ami instances for the class yet?

    I saw it mentioned above that one was comming but haven't been able to find it.

  7. December 15th, 2009 at 12:06 | #7

    @DavidL

    Here's the AMI id for the pre-built instance: ami-c045a7a9

    This has all of the software and the sample project in the ubuntu user's root dir. It is tweaked so that I or the staff can log into it (if you give us your public DNS name).

    I'll add a bit to the screencast script that talks about this -- later.

  1. No trackbacks yet.