天天看點

Deploying to a Public Web Server

Deploying to a Public Web Server

Goals

In this lesson, we finally deploy our application to a public web server.

Please note that, while we’ve tried to make these notes complete, they aren’t the full tutorial; that’s in the screencast, which you can access via the button on the left. We recommend that you right-click on the button and choose Save As to download it to your computer.

The code used in this lesson has all been checked in to the Github repository.

Rails deployment overview

Deploying a Rails application is more complex than for a simple web site or PHP application for two reasons:

  • In general, a separate application server is used to keep the Rails application in memory, and execute requests that come in through the HTTP server. This requires more configuration, and that the application server be restarted when the code is changed.
  • Static and PHP sites are typically deployed by simply uploading files to the server, with FTP or SFTP. Although there is nothing about Rails that requires it, Rails applications are almost universally deployed by having the server check the code out from a version control system. (This is a better practice for all kinds of sites, but it less often used with simpler technologies.)

The flow of a deployment is thus as follows:

  1. Make changes to your code locally
  2. Test the changes
  3. Check the changes in to version control (and push to the main repository, if using Git)
  4. Optionally, display a maintenance page to replace the site while it is being updated
  5. Perform a checkout of the code from the version control system to the web server
  6. Run any migrations that the new code requires
  7. Restart the application server
  8. Disable the maintenance page, if any

Although this may sound complicated, with the right tools it is quite simple once you’re all set up. The key tool is a program called Capistrano, which can automate the entire process (starting with step 4). In the previous few lessons, you’ve been through the first three steps; by the end of this lesson, you’ll have been through the whole process.

Choosing a web and application server configuration

There’s a huge array of choices to be made when it comes to server software selection and configuration. We’ll describe one of many possible approaches in this lesson. You’ll almost surely want to explore other options, and need to learn more about issues specific to your server, to do your own deployments. Here’s where to find some useful resources on our BuildingWebApps site:

  • Linux
  • Rails Hosting
  • Rails Application Servers
  • HTTP Servers
  • Automation

We also highly recommend the book Deploying Rails Applications.

For the past two years or so, the most widely used setup has been Apache 2.2 as the front-end server, which processes HTTP requests, serves static files (including JavaScript, CSS, and p_w_picpaths, as well as any cached HTML pages) and passes (“proxies”) requests that must handled by Rails to the application server(s). Many people have started using Nginx instead of Apache as the front-end server.

Whether Apache or Nginx is the HTTP server, the most widely used application server is Mongrel, which is installed as a gem. Mongrel handles only one request at a time, so most servers use two or more Mongrels (dozens for a system designed to handle high loads), and another gem called mongrel_cluster manages the Mongrels.

Setting this up can be a little complex, and if you’re going to take this route, going with a hosting company that provides a “stock” configuration, and knows how to support it, is usually a good investment.

A relatively new alternative, Passenger (a.k.a. mod_rails), makes all this much simpler by operating as an Apache module. Not only does it eliminate most of the configuration, it shuts down Rails processes that have been idle for a while, freeing the memory they use. This has the disadvantage of a several-second delay the first time an idle site is accessed, but it is a tremendous advantage for a server that is running lots of low-traffic sites, since they don’t always need to sit in memory.

In this lesson, we’ll use Apache 2.2 with Passenger.

Set up database configuration for MySQL

Before we get to the server setup, we need to do a little work on our application.

So far, we’ve used SQLite for our development and test databases, and the production database is set up to use it as well. MySQL is generally a better choice for production, so let’s change the production configuration.

In

config/database.yml

, replace the section under

production

to the following:

adapter: mysql
database: learningrails_production
username: deploy
password: secret
host: localhost
      

The development and test databases can remain set up for SQLite.

We’ve also added a migration) that will create all the pages and a couple of sample resource categories and links, so the application when deployed should look much like the version you have on your development system. This migration won’t do anything unless there are no pages defined in the database.

Remember that the contents of your local SQLite database aren’t transferred to production, so you’ll need to enter, on the production system, any data you’ve added to the database on your development system (or add a migration to do so, as we’ve done for the basic site contents). This is a bit of a pain for ongoing development—you’ll probably find that you’ll want to copy the database from the production system down to development when you’re doing development work, and sometimes push it back up to production when you’ve added content locally. A GUI tool such as Navicat simplifies this process.

Install Capistrano

Capistrano is a powerful utility for automating any kind of web deployment. It is nearly universally used by Rails developers.

First, install the Capistrano gem if you don’t already have it:

sudo gem install capistrano
      

We’ve used version 2.5 in this lesson. Some details will be different if you’re using an earlier version, and if it is much earlier, it may not work with Git.

Capistrano runs on your development system, not on the server. It performs actions on the server by connecting to it via SSH and issuing commands, just as you would from an SSH terminal session.

To configure the application for Capistrano, the first step is to “Capify” it. From your root application directory, simple enter in a terminal:

capify .
      

(That’s “capify”, space, period.)

This adds two files to your application:

Capfile

at the root of the app, and

deploy.rb

in the config directory. We don’t need to make any changes to

Capfile

.

Set up deploy.rb

The file

deploy.rb

is where you tell Capistrano how to access your code repository, as well as other details of your production server(s). The art of configuring Capistrano is mostly a matter of setting up the

deploy.rb

file.

There’s a guide at github that gives us some guidance about what is needed so Capistrano can fetch our code directly from our github repository. There’s also a lot of tutorial content at capify.org. Here’s the lines we need to add to support checking out from our public Git repository:

default_run_options[:pty] = true
    set :repository,  "git://github.com/mzslater/learning-rails-sample-app.git" 
    set :scm, "git" 
    set :branch, "master" 
    set :deploy_via, :remote_cache
      

The first line ensures that password prompts are passed through. The next three lines tell Capistrano where the repository is, that it is a Git repository, and which branch to use. The last line tells Capistrano to keep a cache of the repository on the web server, so it only has to transfer new code from the repository when deploying a new version.

If you are deploying from your own repository, you’ll need to change the repository URL, and if it isn’t a public repository, you’ll want to set up an SSH key pair, with the private key on your server and the public key added to your Github account; see the help docs on Github for details.

Then we need to tell Capistrano about our servers:

set :application, "learningrails" 
    set :deploy_to, "/var/www/apps/#{application}" 
    set :user, "deploy" 
    set :admin_runner, "deploy" 
    role :app, "sampleapp.learningrails.com" 
    role :web, "sampleapp.learningrails.com" 
    role :db,  "sampleapp.learningrails.com", :primary => true
      

The application name is used to name the folder into which the application code is deployed. The second line allows us to specify where this folder is located on the system, with the application name substituted in as a variable. Then we tell Capistrano what user name to use when logging into the server. (It is customary to use a dedicated user name just for deployments.)

By default, Capistrano uses sudo to execute commands on the server. This won’t work on most shared servers, where you don’t have sudo access, so you might need to add the option

set :use_sudo, false

. If you do so, however, Capistrano might not be able to create the directories for your application. We’ve left sudo enabled, and used the

admin_runner

variable to set the user name under which Capistrano will use the sudo command when creating directories. This is what worked best for us in our server configuration, but your mileage may vary; if in doubt, check with your hosting company. (Versions of Capistrano prior to 2.4 behave somewhat differently.)

The three “role” lines tell Capistrano about our servers. We’re using a very simple configuration, in which the web (HTTP), application (Rails), and database (MySQL) servers are all on the same machine, but they don’t have to be. You can also have a cluster of servers, with more than one server performing each role, and Capistrano will take care of, for example, checking out a copy of the code to each application server, and modifying the setup on each web server to display a maintenance page.

Finally, you need to tell Capistrano how to start and restart the application server. There are standard Capistrano tasks for this that are designed for Mongrel and similar application servers; for Passenger, things are simpler, but we need to tell Capistrano just what to do, with these lines of code:

namespace :deploy do
      desc "Restart Application" 
      task :restart, :roles => :app do
        run "touch #{current_path}/tmp/restart.txt" 
      end
      desc "Start Application -- not needed for Passenger" 
      task :start, :roles => :app do
        # nothing -- need to override default cap start task when using Passenger
      end
    end
      

The namespace block tells Capistrano what name prefix to use for these tasks. Namespaces help avoid unintentional name conflicts in complex setups.

To restart Passenger, you only need to update the modification date of the

restart.txt

file, which is done with the

touch

command. Note that you can simply write

run

and then the command, and Capistrano knows to open an SSH terminal to the app server (as specified on the

task

line) and issue this command.

current_path

is a variable that provides the path to the current version of the application.

With Passenger, you don’t need to do anything to start the app server, but we need to define an empty start task to override the one that is part of the default Capistrano tasks.

These tasks give you a hint of what’s possible with Capistrano—you can use it to automate nearly everything you’d want to do on your server. Keep in mind, though, that if you use the

:use_sudo, false

setting, you can’t do things that require a privileged user.

We’re done changing code now, so if you’re working in your own repository, commit your changes now. We’ve already made all these changes in the public Github repository.

Install Passenger

Now we’re ready to set up the server. There’s a vast array of options here, depending on whether you’re on a shared or dedicated server, what operating system is installed, and so forth. To avoid a lot of system-specific discussion and keep this lesson to a reasonable length, we’re going to assume you have a Linux server with Apache 2.2, MySQL 2, and Git installed. If not, see the links at the start of this article for pointers to some resources, or check with your hosting company.

To install Passenger, simply enter in an SSH terminal window connected to your server:

sudo gem install passenger
      

And then:

passenger-install-apache2-module
      

The Passenger installer will check for any required dependencies and give you specific instructions if there’s anything else you need to set up first.

Configure Apache

Now we need to configure Apache. Your system should have a base Apache configuration already, often in

/etc/httpd/conf/httpd.conf

, though this varies depending on the Linux variant and system configuration.

We need to add a few lines to the Apache configuration file to tell Apache to use the Passenger module:

LoadModule passenger_module /usr/lib/ruby/gems/1.8/gems/passenger-2.0.3/ext/apache2/mod_passenger.so
PassengerRoot /usr/lib/ruby/gems/1.8/gems/passenger-2.0.3
PassengerRuby /usr/bin/ruby
      

The Passenger installer will provide these lines for you; the paths and other details may be different for your system configuration.

Then we need a virtual host configuration for our site. We put this is a separate file, which is included by reference at the end of the main Apache config file. Here’s what we used:

<VirtualHost *:80>
       ServerName sampleapp.learningrails.com
       DocumentRoot /var/www/apps/learningrails/current/public 
       <Directory "/var/www/apps/learningrails/current/public">
            Options FollowSymLinks
            AllowOverride None
            Order allow,deny
            Allow from all
      </Directory> 
    </VirtualHost>
      

The first line identifies the root URL for your site. We’ve used the URL for our demonstration server, but you’ll want to use your own server URL here. You’ll need to set up a DNS record to point this name to the IP address of your server.

The second line must point to the

public

directory of your Rails application. We told Capistrano to put the application in

/var/www/apps/learningrails

, and as we’ll see shortly,

current

is a symlink that points to the currently active version.

The Directory directives ensure that Apache is allowed to access the public directory. This may or may not be necessary, depending on what the rest of your Apache config file looks like.

Now restart Apache, and make sure there are no errors reported. On our server, this can be done with:

sudo /sbin/service httpd restart
      

Once again, the command may be different for your server configuration.

Set up MySQL

We have just one more thing we need to do on the server: create the empty database. You can do this with a MySQL GUI application, if it can connect to your server (typically using an SSH tunnel), or you can do it from the command line in a SSH terminal session. To use the latter approach, first create the database with the following command at the shell prompt:

mysqladmin -u root -p create learningrails_production
      

This command assumes that you have a user configured for MySQL named root, and you’ll be prompted for root’s database password after you enter this command.

Then, start the mysql monitor program by entering

mysql -u root -p
      

and create the deploy user by entering the following command at the mysql prompt:

mysql> grant all privileges on *.* to 'deploy'@'localhost' identified by 'secret';
      

(Note that you don’t enter

mysql>

; that’s the prompt.) The user name (deploy) and password (secret) must correspond to those in your database.yml file’s production section.

Your first deploy

Now, on to Capistrano tasks. First, to get an overview of all the Capistrano commands available, enter (in a terminal on your development system):

cap -T
      

Remember, Capistrano always runs on your development system, even though it is issuing commands to your server.

Now there’s some one-time-only setup:

cap deploy:setup
      

Capistrano will connect to your server, and will prompt you for the server password if don’t have an SSH key set up. Capistrano will then create some directories to hold your application code.

To make sure everything is ok, enter:

cap deploy:check
      

Hopefully, this tells you that everything looks good; if not, read the error messages carefully and correct any problems. If there are permissions issues, Capistrano may not be able to create the directories it needs. You may need to log into the server and create the

/var/www

directory manually. For our server, the owner of this directory is set to

deploy

, and the group to

apache

Now, just enter:

cap deploy:cold
      

And you should see lots of lines fly by, as Capistrano tells the server to check out the code from Github and sets up some symlinks. At the end, all the migrations should be run.

If all has gone well, you should now be able to browse to your server and see the application running. (You can visit [url]http://sampleapp.learningrails.com[/url] to see the copy that we deployed.)

Troubleshooting

There’s a lot that can go wrong in this process, and unless everything works, your app won’t. So watch the Capistrano scripts carefully while they’re running. If there were no errors there, but it hangs on checking out the code, then there’s a problem with the authentication with Github (if you’re using a private repository) or the Git URL.

If you get no response when you try to access the application, make sure your DNS is set up correctly and has propagated to your computer, and that Apache is running. The Apache error log file may be helpful (the location varies depending on the system configuration; on our system, it is

/var/log/httpd/error_log

). If you get a Rails error page (error 500), then check the Rails log on the server for clues (

/var/www/apps/learningrails/shared/log/production.log

).

Because of the wide range of issues that can come up, it’s unlikely that we’ll be able to answer all your questions here. Here’s some resources to try:

  • Google group for Capistrano
  • Google group for Rails Deployment
  • Google group for general Rails issues
  • Google group for Passenger
  • RailsForum
  • LinuxQuestions forum

And, of course, there’s always the tutorials, FAQs, and support staff at your hosting company.

Deploy, and deploy again

Once this is all set up and working, deploying new versions is gloriously simple. First, be sure to commit your changes and push them to Github. Then, just:

cap deploy
      

Or, if you’ve added any migrations:

cap deploy:migrations
      

If you want to put up a maintenance page during deployments, first issue this command:

cap deploy:web:disable
      

And then do the deployment. When it’s done, just:

cap deploy:web:enable
      

Something wrong? Just roll back

Another great thing about Capistrano is that it maintains multiple versions of your application on your web server. In the directory

/var/web/apps/learningrails

, you’ll find three directories:

shared

,

releases

, and

current

  • shared

    is for information that doesn’t change with each deployment. Log files, for example are stored in

    shared/log

    . If you have assets that are uploaded to the server and don’t go in the database or the repository, then they should go here, and you’ll want to add a Capistrano task (which can be automatically executed after each deployment) to symlink to the shared location from the current

    public

    directory.
  • releases

    has a directory for each deployed version. By default, Capistrano keeps the most recent four versions.
  • current

    isn’t a real directory; it’s a symlink to the current release directory. So you can always refer to the current version as

    /var/www/apps/learningrails/current

    , and you’ll really be accessing one of the directories inside

    releases

So what’s the use of all these releases directories? If you deploy a version and then find that your application has a serious problem, just roll back:

cap deploy:rollback
      

This task takes only a moment to execute, because all it has to do change the

current

symlink to point to the previous

releases

And there’s more…

We’ve just scratched the surface in this lesson, as deployment is a very complex topic. There’s much more you can do with Capistrano, and more that you should know to create a secure production deployment. Check out the links early in this lesson page to dive deeper.

Next lesson, we’ll look at how to evaluate the performance of your deployed application and find performance troublespots using New Relic’s RPM service.