With the release of Ubuntu 12.04 LTS the time has come - albeit late - for an updated guide on rolling your own Rails production server with a long term supported Ubuntu. This is an updated guide based on an earlier version for Ubuntu 11.10. Most steps are the same, but I've gone through the guide in a fresh virtual machine to make sure everything still works as expected.
The setup
- Ubuntu Server 12.04
- Apache 2
- MySQL
- Passenger (mod_rails)
- RVM
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 12.34.56.78 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).
Installing Apache
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, you've got your basic webserver working!
Installing MySQL
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 and database 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. You can open the mysql console using:
mysql -u root -p
Run the following commands to create a user and database:
create database myrailsapp; grant all privileges on myrailsapp.* to 'myrailsapp'@'localhost' identified by 'correcthorsebatterystaple'; flush privileges; exit;
You can verify the account by running
mysql -u myrailsapp -p
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:
curl -L https://get.rvm.io | sudo bash -s stable
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 a Ruby. You can check the list of available rubies using rvm list known. I have chosen to install ruby 1.9.3-p194, which is the latest stable version at the time of writing. 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, 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), while it provides full separation of gems for your apps
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.
Installing Phusion Passenger
Start by installing passenger. Then install passenger-install-apache2-module using 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 (passenger.load and passenger.conf) in /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/local/rvm/gems/ruby-1.9.3-p194/gems/passenger-3.0.15/ext/apache2/mod_passenger.so #/etc/apache2/mods-available/passenger.conf PassengerRoot /usr/local/rvm/gems/ruby-1.9.3-p194/gems/passenger-3.0.15 PassengerRuby /usr/local/rvm/wrappers/ruby-1.9.3-p194/ruby
Activate the passenger module and restart Apache.
sudo a2enmod passenger sudo service apache2 restart
And voila, you now have Apache running with Passenger 3.
Deploying
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
/var/wwwto/var/www/default. - 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 therubyracer gem to our Gemfile, because we need a javascript interpreter later.
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.3@rails3 --create gem install rails cd /var/www rails new myrailsapp --skip-bundle -d mysql cd myrailsapp echo "gem 'therubyracer'" >> Gemfile bundle install rails generate scaffold todo name:string finished:boolean 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
Now change the ownership to the deploy user:
sudo chown -R deploy:deploy /var/www/myrailsapp
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. rake assets:precompile requires a javascript interpreter, good thing you added therubyracer to the Gemfile. Touching tmp/restart.txt restarts passenger.
rvm use 1.9.3 --default cd /var/www/myrailsapp 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.
Please feel free to notify me iIf anything is not behaving as expected.
Want your own weblog? This on is available on GitHub.
Back to index