QUICK UPDATE 03-14-2011 – PLEASE READ – This tutorial was written when Rails 3 was in beta. Some of this info may be outdated. This tutorial will be updated soon, but here are a few notes until I get to it: For steps 6 & 7, use RVM and install 1.9.2 using RVM. This should install rubygems, so you can skip #7. For step #8, install without the –pre flag… it will install the current official release (3.0.5 or higher). I am not using Passenger at this time, so I can’t comment on how well that will work. You may need to include the bundler Capistrano recipes with your deploy.rb. This will bundle install with the –deployment flag.
I could not wait patiently for the official release of Rails 3, so I am working on a Rails 3 upgrade now… and part of the process is moving my site from co-location hosting over to Rackspace Cloud. I am a big fan of the Rackspace Cloud and while most of my websites are hosted there now, I was waiting for my co-location contract to run up before I moved over my highest traffic website. Here are the steps I used to set up my server. I will show you how to install all the software and create a blank Rails 3 app. Then I will show how to pull an existing Rails 3 app from github and deploy it with Capistrano.
Note: I am not doing this, but you may want to go the route of installing RVM if you will be running multiple applications or ruby versions on your production server.
My Rails stack looks like this:
- CentOS 5.5
- Ruby 1.9.2 preview 3
- Rubygems 1.3.7
- Rails 3 beta 4
- Passenger 2.2.15 with Nginx
- memcached
- MySQL
Here are the steps I used. Please leave a comment if you have any questions or if something needs to be changed.
1. Login or signup for Rackspace Cloud Servers (not Cloud Sites)
2. Build a new server – Hosting -> Cloud Servers -> Add Server -> Create a CentOS 5.5 server
(YMMV with other linux flavors using my steps)
3. Login and change your root password
4. Create a new user and add them to the sudoers file.
It is important that you create a new user instead of doing everything as root. You will most likely run into permission problems with Passenger and Bundler if you do this as root. Passenger will run as ‘nobody’ if ‘root’ owns the rails app root directory. It will not have access to root’s local gem bundle. Also, go ahead and disable root login from sshd
useradd app_user passwd app_user vi /etc/sudoers #open sudoers in your favorite text edit # add the following line below "root ALL=(ALL) ALL" : # app_user ALL=(ALL) ALL # save file and exit #disable root login from ssh, so nobody is able to brute force a root login vi /etc/ssh/sshd_config #uncomment "PermitRootLogin yes" and change it to "PermitRootLogin no" /etc/init.d/sshd restart #logout and login or su to your new user su app_user cd ~
5. Update EPEL and install linux software dependencies
sudo rpm -Uvh http://download.fedora.redhat.com/pub/epel/5/i386/epel-release-5-4.noarch.rpm sudo yum -y install gcc gcc-c++ make zlib zlib-devel openssl openssl-devel git expect pcre pcre-devel readline-devel mysql mysql-devel libxml2 libxml2-devel libxslt libxslt-devel
6. Install Ruby 1.9.2 preview 3 (compatible with Rails 3 beta 4)
wget ftp://ftp.ruby-lang.org/pub/ruby/1.9/ruby-1.9.2-preview3.tar.gz tar -xvf ruby-1.9.2-preview3.tar.gz cd ruby-1.9.2-preview3 ./configure make sudo make install ruby -v #just checking to make sure it installed.. output = ruby 1.9.2dev (2010-05-31 revision 28117) [x86_64-linux] cd ..
7. Install Rubygems 1.3.7
wget http://production.cf.rubygems.org/rubygems/rubygems-1.3.7.tgz tar -xvf rubygems-1.3.7.tgz cd rubygems-1.3.7 sudo ruby setup.rb cd ..
8. Install Ruby on Rails 3 Beta 4
If the official release is out you can remove the –pre. This should install a bunch of gems related to rails 3 beta 4 (23 gems on my system)
sudo gem install rails --pre --no-ri --no-rdoc
9. Create a new directory for your rails applications and create a blank rails app
In rails 3 you need to use the new parameter after the rails command in order to create a new app
mkdir rails_apps cd rails_apps rails new myapp
10. Install passenger with Nginx
sudo gem install passenger sudo passenger-install-nginx-module # This will guide you thru nginx/passenger install.. hit enter to check dependencies # choose option 1. Yes: download, compile and install Nginx for me. (recommended) # I installed in default /opt/nginx.. just hit enter to install default # hit enter at the end and you should be finished and back to the command line prompt
11. Update your Nginx configuration file so you can run myapp with passenger.
Example Nginx config file: /opt/nginx/conf/nginx.conf
#I found it necessary to change the user in order to have the correct permissions.
user app_user;
worker_processes 1;
#error_log logs/error.log;
#error_log logs/error.log notice;
error_log logs/error.log info;
events {
worker_connections 1024;
}
http {
#Note: rubygems installs gems in the 1.9.1 dir even though I am using 1.9.2... not sure why??
passenger_root /usr/local/lib/ruby/gems/1.9.1/gems/passenger-2.2.15;
passenger_ruby /usr/local/bin/ruby;
# passenger recommends 30 max pool size if you have a 2GB box that is dedicated to app server and
# less than that if you have a DB server running on it
passenger_max_pool_size 30;
include mime.types;
default_type application/octet-stream;
sendfile on;
#tcp_nopush on;
keepalive_timeout 65;
tcp_nodelay on;
gzip on;
gzip_min_length 1100;
gzip_buffers 4 8k;
gzip_types text/plain;
gzip_comp_level 2;
gzip_types text/css application/x-javascript text/xml application/xml application/xml+rss text/javascript;
server {
listen 80;
server_name localhost; #putting in localhost just for testing. You should set this to your domain name: yourdomain.com
root /home/app_user/rails_apps/myapp/public;
passenger_enabled on; #MAKE SURE YOU HAVE THIS LINE OR IT WILL NOT FORWARD TO PASSENGER!
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}
12. Start Nginx, which will also start Passenger
sudo /opt/nginx/sbin/nginx
13. Open up iptables for port 80 and restart iptables.
Also, you might want to look into enable SELinux for some added security on your system.
sudo vi /etc/sysconfig/iptables # Add the following line towards the bottom below the port 22 ACCEPT # -A RH-Firewall-1-INPUT -m state --state NEW -m tcp -p tcp --dport 80 -j ACCEPT # save and close # restart iptables sudo /etc/init.d/iptables restart
You should be able to get to your Rails app now and see the default rails index.html -> Welcome aboard. You’re riding Ruby on Rails! ……
This is great and all, but I am more interested in running my existing app in production, rather than creating a new one. I am guessing you will not be developing on the server, so we need to get things set up with github & capistrano and deploy our app that way. This assumes that you already have a project in github and you have some git knowledge. This also assumes that you already have a database server setup and that your database.yml is pointing to that server. I will not cover database setup here.
Here is what you do:
14. Generate a new ssh key on the server to use with github
ssh-keygen -t rsa -C "youraddress@email.com" #use the default dir and enter a solid password
15. Add the key to github
Full instructions about creating a key and adding to github here: http://help.github.com/linux-key-setup/
16. Add entry into known_hosts file for github
This is necessary to pull with capistrano. I think the easiest way to do this is to clone your github project. It will create the known_hosts file and add the entry for you. Then you can just delete the project right after you clone it. No need to keep it, since you will be using the Capistrano setup.
git clone git@github.com:your_username/your_project.git # type yes to accept the key entry # enter your passphrase # it will clone.. now delete it rm -Rf your_project/
OPTIONAL: Out of habit I have all my rails apps in the same place on my servers.
I have a dir called /rails_apps. I am going to create that now, but you can use what you already have set up if you like. I also need to change the dir to be owned by “app_user”
sudo mkdir /rails_apps sudo chown app_user:app_user /rails_apps/
17. Go ahead and create your project and release directory for Capistrano to use.
mkdir /rails_apps/myapp mkdir /rails_apps/myapp/releases
IMPORTANT! It is necessary to update your nginx configuration if you are using Capistrano. Since cap uses the “current” directory and links to a release directory, your nginx config should change the “root” entry in the server block
open /opt/nginx/conf/nginx.conf and change the “root” entry to “root /rails_app/myapp/current/public;” Then you can restart nginx like this:
sudo killall -9 nginx sudo /opt/nginx/sbin/nginx
18. Capistrano Setup
Now you are ready to move on to Capistrano setup. I do all development locally on my Mac, commit the code with git and push it to my repository at github. In order to use Capistrano to deploy, you will need to “gem install capistrano” on your Mac (or windows box.. say it ain’t so!) and add 2 files to your Rails project. /myapp/Capfile and /myapp/config/deploy.rb. Here are my files:
Capfile
load 'deploy' if respond_to?(:namespace) # cap2 differentiator
Dir['vendor/plugins/*/recipes/*.rb'].each { |plugin| load(plugin) }
load 'config/deploy' # remove this line to skip loading any of the default tasks
deploy.rb – most of this config came from the passenger capistrano recipe.
set :application, "myapp"
#github stuff
set :repository, "git@github.com:your_github_id/myapp.git"
set :scm, :git
set :scm_username, "your_github_id"
set :scm_passphrase, "your_github_passwd"
set :use_sudo, false
set :deploy_to, "/rails_apps/#{application}"
#server login
set :user, "app_user"
set :password, "server_password_here"
ssh_options[:forward_agent] = true
# will be different entries for app, web, db if you host them on different servers
server "123.456.12.34", :app, :web, :db, :primary => true
namespace :deploy do
task :start, :roles => :app do
run "touch #{current_release}/tmp/restart.txt"
end
task :stop, :roles => :app do
# Do nothing.
end
desc "Restart Application"
task :restart, :roles => :app do
run "touch #{current_release}/tmp/restart.txt"
end
end
Now you are ready to deploy. The whole point of using Capistrano is so you don’t have to login to your servers to push code, do restarts, etc.. So on your mac, you will run the “cap” commands for deployment.
This is a 3 step process. Run these from the command line on your development box while in your rails app root directory (dir that contains Capfile):
- cap deploy:check #this will check for dependencies
- cap deploy:setup #this will create your shared directories.. log, pids, system
- cap deploy #this will pull your code from github and put it in a new release directory, create a link to “/rails_apps/myapp/current” directory for that release and restart your passenger server
Now, take a look at your app on the server. If you are lucky it will be running as expected, but I highly doubt it if you have gems that need to be installed. Lets use bundler to get the necessary gems installed. If you are Rails 3 savvy, you know that all your gem dependencies should be in /myapp/Gemfile, and that you can use Bundler (which is awesome BTW.. thnx wycats) to install them easily.
Passenger gives me a real pretty screen that says: “Could not find gem ‘mysql (= 2.8.1, runtime)’ in the gems available on this machine. (Bundler::GemNotFound)”
My Gemfile contains that gem, but it is not on my server. So to get Bundler to install it, you will need to navigate over to your rails app root directory on the server. I mentioned earlier that you should not set up your rails app with the ‘root’ account on your linux box, and this is the problem that I ran into. When I installed with bundler, it put the bundled gems in /root/.bundle/…. and the web server could not access the gems, because passenger runs as ‘nobody’. If you run the server as ‘app_user’ or whatever you account is, then you should bundle install with the same account, so you dont have permission problems.
cd /rails_apps/myapp/current bundle install #no need for sudo here. You want them to install in your user's home dir
19. Memcached Setup
Next on my list was getting memcached working. I use memcached as my cache store. In /myapp/config/environments/production.rb, I have the following line:
config.cache_store = :mem_cache_store
So passenger was complaining about not having memcached -> no such file to load — memcache
First I need to install memcached on the server. You can use a seperate server for memcached but you need to update the line in production.rb, to point to that server. It uses localhost by default.
In order to get memcached to work, you have to install libevent first
cd
wget http://www.monkey.org/~provos/libevent-1.4.13-stable.tar.gz
tar -xvf libevent-1.4.13-stable.tar.gz
cd libevent-1.4.13-stable
./configure && make
sudo make install
cd ..
wget http://memcached.googlecode.com/files/memcached-1.4.5.tar.gz
tar -xvf memcached-1.4.5.tar.gz
cd memcached-1.4.5
./configure && make
sudo make install
#you will get errors if you do not do the next 2 steps. Create libevent config file, add a line to it, and then run ldconfig
sudo vi /etc/ld.so.conf.d/libevent-i386.conf #create this file and add one line ->
# /usr/local/lib/
sudo /sbin/ldconfig
#start your memcached server up
sudo /usr/local/bin/memcached -u nobody &
#you should add this last command to /etc/rc.local so the memcached server starts if there is a reboot
Now your memcached server is running, but you still have to install the gem. Let’s add it to our Gemfile, git commit, & git push on our Mac, run “cap deploy” and then bundle install again on the server
group :production do
gem “memcache-client”
end
One note of caution here.. if you are already in /rails_apps/myapp/current, you need to cd again. If I remember correctly I ran into the problem of being in an old release directory. I guess when the link was update, my shell did not catch the update and was pointing current to the previous release directory.
cd /rails_apps/myapp/current bundle install
You should have a working Rails app with memcached now. I did run into one gotcha when I was doing this. I had a legacy Rails app that I was upgrading and the following line was in environments/production.rb:
This line needs to be removed if you get the following error -> “undefined method `cache_template_loading=’ for ActionView::Base:Class”
Now open up your app in your browser and feel all the Rails 3 goodness! You are a rock star!
Hopefully YMDNV
Everything seems to be working so far on Rails 3 and I have a fairly complex app with quite a few plugins. I think the hardest part about adopting Rails 3 is the fact that plugins are not ready. I spent a good bit of my time troubleshooting and patching (yeah.. some monkey stuff) plugins. You can read more about my upgrade experiences in this post.




#1 by Chris on September 9, 2010 - 8:13 pm
Quote
Thanks for this info, its a lifesaver to me. One question for you, in step #7, with the release of ruby 1.9.2 (ruby-1.9.2-p0) does anything have to change? After successfully doing step #6 with ruby-1.9.2-p0, the rubygems are bugging out during the build with the following error
/home/app_user/rubygems-1.3.7/lib/rubygems/source_index.rb:68:in `installed_spec_directories’: undefined method `path’ for Gem:Module (NoMethodError)
Any insight/help would be greatly appreciated.
#2 by cowboycoded on September 10, 2010 - 4:32 am
Quote
Ruby 1.9.2 installs rubygems for you so that step is probably not necessary. Just to check, run “gem -v” to see if there is a version installed. Also, remove the –pre flag from the rails install, since Rails 3 is now an official release. I think everything else in this tutorial should work with the latest version of 1.9.2 and Rails 3 official release. I actually stopped using passenger because it takes so long to spawn threads with Rails 3. Passenger 3 solves this problem, but in the meantime you may want to use Thin if you find spawning to be a problem. My app was frozen for 30 seconds when it spawned a new thread, but I have alot of plugins that need to be loaded.
Pingback: Setting up a Ruby on Rails stack on Rackspace Cloud « Cowboy Coded
Pingback: RVM + nginx + passenger + Rails 3 | Big Rock Software
#3 by Dirk on January 12, 2011 - 1:33 pm
Quote
This was a life saver, thank you so much, I ran into the gems / root issue and was about to tear my hair out.
#4 by Sean Crowe on February 9, 2011 - 8:43 am
Quote
I’m thinking of moving my client’s rails application to RackSpace but i’ve been told they don’t “officially” support Rails. Have you had any negative experiences or problems running your Rails apps on the RackSpace cloud?
Thanks.
#5 by cowboycoded on February 9, 2011 - 9:12 am
Quote
Rackspace Cloud Sites does not support Rails, but Rackspace Cloud Servers supports anything you want. You have root access to the server instance and you have the choice of several different linux distros. If you want to set the server up and have total control over it, then Cloud Servers would work fine. If you want something that is easy to deploy and doesn’t require you administrating the server, then I would go with something like Heroku. I have about 30 server instances running on Rackspace and I have only had 2 short outages in the last year (server reboots). Its just as reliable as any other hosting company I have used. Your other choice is Amazon EC2. It costs more and has worse performance for things like disk IO (according to some benchmarks I have seen). But I hear that the API is better and it is more powerful than Rackspace servers in terms of customization and extra features.
#6 by Karl on February 28, 2011 - 5:27 pm
Quote
Heyhey, would this work for me too, if i fetched a rackspace servers account now, or did something changed?
I’m asking because I am not the born sysadmin and just need a remote place to play around with some rails3-app. Nothing which would require speed optimization or stuff.
I tried hostingrails, but I got frustrated many times already because the tutorials there are too old/inconsistent and I really can’t google around for hours just to find out why this or that is failing.
I’m not dumb or something but I really don’t have teh nerves to fuck around with these bitches FOR DAYS
#7 by Karl on February 28, 2011 - 6:02 pm
Quote
Ah btw, I saw you use github and wondered why. Just because it’s so comfortable? I had planned to push directly to my rackspace “server”.. Would you disagree on that? As I stated I am quite new to this kind of stuff, for now i used eclipse with subversion for committing my work. But maybe I will switch to gedit, to get a clue of the mysterious textmate feeling
And I completely forgot to thank you for your very nice tutorial: Thank you
#8 by cowboycoded on February 28, 2011 - 7:10 pm
Quote
@Karl – Although I wrote this while Rails 3 was in beta, but most of it should still work… but I really do need to update this tutorial with the latest and greatest.
Just some quick notes based on what I have seen lately… You don’t need the –pre flag when installing rails now. It will install the latest Rails 3 version without the –pre flag. I would recommend installing RVM and learning it if you plan on doing any Ruby development in the future.
If you just want to play around with things, you don’t really need to install nginx/passenger. You can just move into the rails project directory and type “rails s” and it will start the webrick server. Then you can access the app on port 3000… note that you may need to open up that port in the iptables.
Git beats the shit out of subversion in about every way possible. Learning git and using github has helped me tremendously. Just about all the open source libraries are hosted there now. You can even install plugins directly from github in Rails 3 with bundler. You can deploy your stuff with subversion & capistrano (I think??), if you don’t feel like learning git, but I promise you will never go back to subversion once you git’r done with git.
Textmate is really pretty simple compared to eclipse, which is way too bulky for Rails in my opinion (although I do miss the debugger). The power of textmate lies in the snippets, macros and file finder… the rest is really basic stuff. Check out this editor if you are on windows or linux.. very similar to textmate (and some say its better), but it is cross platform:
http://www.sublimetext.com/2
I will hopefully get around to updating this tutorial sometime soon. In the meantime, leave a comment if you have a question about any of this stuff.. odds are I have already banged my head against the wall for hours working on the same problem.
#9 by Karl on February 28, 2011 - 7:49 pm
Quote
Thanks for your answer
I got in touch with rvm already but must admit that I was sceptical from the beginning (this multiple ruby versions voodoo must cause conflicts I thought) but I will sure take a second look now.
Capistrano supports svn, that’s right. But I will try git for sure!
I feel a new era begining in my personal development, haha. You should be a bit proud of that.
#10 by Karl on February 28, 2011 - 11:15 pm
Quote
wow my server is running! (on hostingrails, with thin. seems as if your tutorial has to wait for some weeks or so.. but great anyway). lucky me.
even git works… i thought of the following “tactics”:
local programming, local testing, push to server, hoping that it would work otherwise rollback. proceed from point one.
I got one problem though: In the past I often had to “try&error” because of server configuration issues, which got me to revision 98 before the server was running (with svn and a fcgi-approach which is is not supported for rails3 by hostingrails as the support wrote a few hours ago btw).
How do you handle your commits when working/testing on “one feature” for several days? Only commits when the “feature” is ready?
I’m thinking of a situation like locally making substantial changes, adding gems and stuff, and then online: bam, error, nothing works because one of the three gems you added probably dislikes the current ruby version or your local rvm version is newer or stuff…
you would have to roll back the git and then recommit in smallest possible parts, wouldn’t you? That would definately screw up the commit history :/
#11 by cowboycoded on March 1, 2011 - 8:16 am
Quote
Good to hear you are up and running! I use Thin on most of my apps and it works well.
When you are creating a new feature, you can create a new branch in git and work on the code from that branch without affecting the master branch (or other branches). Check out how Rails does this. They have a separate branch for each new minor release -> https://github.com/rails/rails (Switch Branches dropdown). That way, they can work on the latest and greatest in the master branch and still have branches for any patches or features that need to be added to the older versions.
You can work in the branch and make your changes, and even deploy from that branch if you want to. Or you can merge the changes into the master branch after you are done. Also, look into creating tags for each milestone so you can rollback to one of the tags if you need to. Branching and tagging keeps you from having to make changes and then do a rollback. You can simply re-deploy with a different tag or branch.
More info here:
Branching and merging
http://www.gitready.com/beginner/2009/01/25/branching-and-merging.html
SVN to git
http://yehudakatz.com/2010/05/13/common-git-workflows/
#12 by Karl on March 1, 2011 - 9:21 am
Quote
Okay, I will have to play around a bit. I like the idea of branching, it may be cool to “branch” the (until now) linear developement process (okay, i guess that’s the idea behind…)
Maybe my question from last post was a bit “dumb” so you misinterpreted it, but as I now understand one would commit locally every now and then and only push if a “usable” (no syntax errors, finished methods) version.
I guess local commit messages are then not merged into the head branch but only the changes from the push, but I will study the rails repo and stuff for myself now…
#13 by cowboycoded on March 1, 2011 - 9:50 am
Quote
I totally misread your question… so it was me being the dummy
It is really personal preference and I guess depends on what kind of team you are working on when it comes to git workflows. I commit often locally and I usually prefer a commit for each file, unless they are closely related and I can describe it in one message. I like to describe what I did to each file so I have a nice history with description, but some people probably just commit a bunch of files at once with a general commit message. On some larger open source projects I think they prefer that you fork the repo, make your changes and issue all of the changes in a single commit, so there is a single “diff” that the repo owner can anlalyze without having to pick through a ton of files.
As far as pushing goes, its also personal preference. Most of the time, I will only push when a change is complete, tests are passing, and I know its not going to break something else in master (or whatever feature branch I am using). Every now and then I push half-complete changes if I am going from work computer to home laptop, but thats really the only time. If you are working with a team, I would assume the only want you to push when it is complete and tests are passing.
Local commit messages ARE added when you merge a branch. In github, they will be inserted into the timeline on the day you made the commit/push (not necessarily same day as merge). There is also a separate commit message for the merge.
Again, I probably don’t use git the way most people do since most of my projects are solo, and I am by no means a git expert… I know enough about it to make it work for my workflow. Google something like “git workflows” and you will probably find a workflow that fits your project/style
#14 by Karl on March 10, 2011 - 5:42 pm
Quote
In the meanwhile I am having kind of fun with rails and like how everybody is testing, at least in the big repos on github.
I guess tests can make you much more confident and are worth the work they cause. Just have tested some forms manually and am now thinking “why did you do that, write tests moron”
Too bad I have to figure most things out for myself. The coding until rails has been a matter of precisely drawing a big picture, now it’s more like searching for gems, apis and tutorials and get everything running.
This would be exactly how the buddies in the car shops feel. A few years ago they could get every engine running with their metal tools and now they are most of the time phoning after the right diagnosis tools or the manufacturers experts without getting dirty at all. Times are changing, that’s for sure.
#15 by aniket on March 14, 2011 - 11:33 am
Quote
thanks a lot, your writeup was a life saver.it was so smooth and easy to follow.i had problems earlier with the deployment process but i now feel more confident deploying my application.thank you once again and keep up the good work.cheers.
#16 by Francis Potter on March 29, 2011 - 10:40 pm
Quote
Step 5 gave an error for me.
sudo rpm -Uvh http://download.fedora.redhat.com/pub/epel/5/i386/epel-release-5-3.noarch.rpm
Retrieving http://download.fedora.redhat.com/pub/epel/5/i386/epel-release-5-3.noarch.rpm
error: skipping http://download.fedora.redhat.com/pub/epel/5/i386/epel-release-5-3.noarch.rpm – transfer failed – Unknown or unexpected error
warning: u 0×1768540 ctrl 0×17698b0 nrefs != 0 (download.fedora.redhat.com http)
#17 by cowboycoded on March 30, 2011 - 5:22 am
Quote
It looks like epel 5.4 has been released and they deleted the old RPM from the server. Try the 5.4 URL instead:
http://download.fedora.redhat.com/pub/epel/5/i386/epel-release-5-4.noarch.rpm
Trackback: Webguide for you
Trackback: VDS sunucu