There is an updated version of this guide for ubuntu 12.04 LTS
When I started developing in Rails I found that setting up a Rails development environment is fairly trivial. I had expected no different from setting up a Rails production server. However, having setup a Rails production server over the past few days has thought me that setting up a production environment is a lot more complex than a development environment.
Add to this that although the development process is well documented for new programmers, the production people assume that you are experienced and know what you are doing. Otherwise, why would you be running a production environment in the first place? But, there has to be a first time for everything and with this (and upcoming) guides I hope to make the Rails production life a bit easier.
In this guide I'll show how to setup a Rails production server. In part 2 of this guide I show how to deploy to this server using Capistrano, which will make your deployment process a lot easier. During this setup we'll keep that goal in mind.
I'm assuming that you already have installed Ubuntu Server with a non-root user (with sudo rights) and that SSH is setup (e.g. like this.) Use sudo, do not use root, because this is a requirement for rvm. You should setup your hosts file for your server. For example, my server has these settings:
# /etc/hosts 127.0.0.1 localhost 188.8.131.52 server.web-l.nl # /etc/hostname server.web-l.nl
This should prevent any messages from apache saying that it could not determine a fully qualified domain name (fqdn).
We'll be installing apache using
apt-get. You'll need sudo to do this. While we are installing apache, we might just as well include some packages needed later on.
sudo apt-get install apache2 curl git build-essential zlibc zlib1g-dev zlib1g libcurl4-openssl-dev libssl-dev libopenssl-ruby apache2-prefork-dev libapr1-dev libaprutil1-dev libreadline6 libreadline6-dev
Now redirect your web browser to your servers IP. It should show a welcome page saying: "It works!". Good!
Up next is MySQL, our database server. Install MySQL via
apt-get, the installer will ask you for a database root password, make sure to pick a strong password.
sudo apt-get install mysql-server
Let's also create a mysql user for your rails app. I'm naming both the database and the user myrailsapp, but you are free to pick any name you feel appropriate. Make sure the replace the password (correcthorsebatterystaple) with something more secure.
create database myrailsapp; grant all privileges on myrailsapp.* to 'myrailsapp'@'localhost' identified by 'correcthorsebatterystaple'; flush privileges;
Installing RVM and Ruby
We'll get to setting up passenger later, but lets first install RVM and a recent ruby. We'll use the curl command provided on the RVM website. Note: This is the first and only time you will use
sudo to do something with RVM. After this, a user just needs to be in the RVM group to use rvm. If, for any reason, sudo is needed to do something with rvm, you have to use
rvmsudo instead of sudo.
*Note: * The installation script changed location recently, the new command is:
sudo bash -s stable < <(curl -s https://raw.github.com/wayneeseguin/rvm/master/binscripts/rvm-installer )
This should successfully install RVM in a multi-user install. The next step is to add yourself to the RVM user group. Let's also add a deploy user with RVM access while we're doing this. Add yourself to the deploy group for convenience.
Also set the permissions on the
/var/www folder. With these settings every user in the deploy group can modify files in the /var/www folder. Then, log out of your terminal/shell and log back in. (This will update your group permissions)
sudo adduser deploy sudo adduser deploy rvm sudo adduser <yourusername> deploy sudo adduser <yourusername> rvm sudo chown -R deploy:deploy /var/www sudo chmod g+w /var/www
Time to install Ruby. You can check the list of available rubies using
rvm list known. I have chosen to install ruby 1.9.2-p290, but you could (should?) go for 1.9.3 once a stable release is available. Compilation can take some time, so get a caffeinated beverage of your choice while your server is busy compiling. Then, set the new ruby to be your default ruby and install bundler. (We'll need bundler later)
rvm install 1.9.2 rvm --default use 1.9.2 gem install bundler
I've had some issues to get openssl and the readline library working with ruby on the beta of Ubuntu Oneiric. One solution is to use
rvm pkg install openssl and
rvm pkg install readline before installing ruby (you can reinstall ruby using:
rvm reinstall 1.9.2. More info can be found at the rvm website.
RVM, Bundler, Rubygems and management
Basically, there are several good ways to manage our gems with respect to Passenger. There also is a wrong way, which is to install all gems in the same rvm gemset on the same server. Good options (in my opinion):
- Use a single server for each application. This gives the best separation and redundancy, but it can cost you, especially if you have a lot of low traffic apps.
- Using a separate rvm gemset for each application. There are some really good instructions on how to do this in this blog post by Darcy.
- Use Bundlers
--deploymentoption to install all gems into the shared/bundle directory of your app. This is what we'll use in this guide, because it does not require any extra setup (unlike option 2).
You ask why I've installed RVM even if I'm going with option 3? Well, this is because rvm makes it easier to install and maintain your desired ruby on Ubuntu. The apt packages for ruby are usually a bit behind.
Start by installing passenger. Then install
rvmsudo. The module installer is very helpful and will give you directions if anything is missing.
gem install passenger rvmsudo passenger-install-apache2-module
In the end, the installer will show how to configure the apache configuration files in order to use passenger. Instead of editing the configuration files directly, we'll place 2 files (
/etc/apache2/mods-available, so that we can use a2enmod and a2dismod to active/deactivate the module. Use
sudo to edit these files. The contents below are indicative, use what the passenger installer will return to you. (most likely, the version numbers will change with time)
#/etc/apache2/mods-available/passenger.load LoadModule passenger_module /usr/rvm/gems/ruby-1.9.2-p290/gems/passenger-3.0.9/ext/apache2/mod_passenger.so #/etc/apache2/mods-available/passenger.conf PassengerRoot /usr/local/rvm/gems/ruby-1.9.2-p290/gems/passenger-3.0.9 PassengerRuby /usr/local/rvm/wrappers/ruby-1.9.2-p290/ruby
Activate the passenger module and restart Apache.
sudo a2enmod passenger sudo service apache2 restart
And voil, you now have Apache running with Passenger 3.
In a later guide I'll show how to deploy to your server using Capistrano. Capistrano takes some time to setup, but it is very useful because future deployments can then be performed completely automatic with a single command.
In this section we'll deploy a basic rails app by hand.
- Move the default page from
- Create and deploy a new rails app.
- Configure an Apache Virtual host to access your rails app.
1. Moving the default page
We will move de default apache page into a separate directory to prevent unauthorized access to the directories of your Rails app. Failing to do this would make the internals of your application accessible via http://ip.address/railsapp. This could, for example, provide unauthorized access to database passwords.
mkdir /var/www/default mv /var/www/index.html /var/www/default/index.html
Now edit the default apache vhost to point to this directory.
# /etc/apache2/sites-available/default ... DocumentRoot /var/www/default ... <Directory /var/www/default/> ... Options FollowSymLinks # Remove Indexes
2. Deploying a new rails app
We'll scaffold a todo rails app at the server to show the deployment of a rails app. To show how bundler installs gems in production, I'll use a separate gemset that is not accessible by Passenger. This simulates the situation in which you develop on a separate computer. We also run bundle install once to generate a Gemfile.lock that bundler will use when deploying. We'll also add
Note: Bundler is not really setup to both develop and deploy on the same machine. Although the steps below are informative in showing how to deploy an app, I recommend you develop on a separate machine.
rvm use 1.9.2-p290@rails31 --create gem install rails cd /var/www rails new myrailsapp --skip-bundle -d mysql cd myrailsapp rails generate scaffold todo name:string finished:boolean echo "gem 'therubyracer'" >> Gemfile bundle install rvm gemset use global
In the new rails app we have to setup the MySQL database.
# /var/www/myrailsapp/config/database.yml production: adapter: mysql2 encoding: utf8 reconnect: false database: myrailsapp username: myrailsapp password: correcthorsebatterystaple
We'll run bundler as the deploy user to simulate the behavior we'll expect with capistrano in the next guide. Log in as deploy with ssh before continuing.
therubyracer to the Gemfile. Touching tmp/restart.txt restarts passenger.
rvm use 1.9.2-p290 --default bundle install --deployment --without development test bundle exec rake db:migrate RAILS_ENV=production bundle exec rake assets:precompile touch /var/www/myrailsapp/tmp/restart.txt
3. Configure a vhost
The easiest way to check if your rails site is working, is to redirect the default virtual host to your rails app. However, if you have a domain name you could also point the DNS settings to your server and setup a vhost to serve that domain. For simplicity we'll turn off the default vhost and redirect all traffic to our railsapp vhost. Note: the vhost needs to direct to the public folder of your app, everything else is handled by Passenger automagically.
# /etc/apache2/sites-available/myrailsapp <VirtualHost _default_:80> # ServerName www.example.com # Commented out for default DocumentRoot /var/www/myrailsapp/public # be sure to point to public <Directory /var/www/myrailsapp/public/> AllowOverride all Options -MultiViews </Directory> </VirtualHost>
Now, activate the vhost by running
sudo a2ensite myrailsapp, then deactivate the default vhost by running
sudo a2dissite default, and then reload the apache configuration using
sudo service apache2 reload and send your browser to
http://<serverip>/todos. If all went well, you should see your working Rails application.
Continue to part 2 of this guide to learn how to deploy on this setup with capistrano.Back to index