Skip to main content

Ruby on Rails Apache Deployment

Setting up apache + passanger to serve a RoR app on Ubuntu/Debian (VPS Linode)

I'm a Django/Python developer that was tasked with transitioning a Heroku hosted app to a Linode VPS running stock Ubuntu. This turned to be a two day adventure with a lot of dead ends and a fair share of frustration. I had the app running relatively quickly using the `rails server` built in command but could not get apache + mod_passanger to serve it.

I must say that in my opinion RoR cummunity is doing it's self a disservice by not having solid easy to follow deployment instructions - doing a search on ruby on rails deployment returns outdated noise and official page that is of no help.

Below is a quick summary of what I have learned and how I deployed a Ruby on Rails site with Apache on a Ubuntu system running on a Linode VPS. If this blog does help you out I ask that you do +1 or share it; so now let's begin.

Do not use the Ubuntu/Debian system packages

I mean do NOT, this is the route I went which turned out to be like going down a rabbit's hole. The system packages are outdated and even if you get your app working using the build in `rails server` command chances are apache + mod_passnger will still complain with "no such file to load -- bundler/setup" or "Valid types are [:development, :runtime], not nil"


Use the 'Rails Ready' script and follow it to the letter

I forget how I eventually found this but I am soooo glad that I. This magical script compiles and installs the latest version of RoR and either a Ngnix or Apache passenger module. So run it and it will automatically take care of the entire setup process for you. However in the instructions it states to run `passenger-install-apache-module` but it's actually `passenger-install-apache2-module`.

$ wget --no-check-certificate https://raw.github.com/joshfng/railsready/master/railsready.sh && bash railsready.sh
...
- I picked the build from source option
...
$ passenger-install-apache2-module
... 

Test and Deploy your RoR Application

In summary: clone or copy your Ruby on Rails application, install it's required gems, test it, then setup the apache configuration as advised after running `passenger-install-apache2-module`.

$ git clone git@github.com:danielsokolowski/<your rails application>.git <your rails application>.ca
$ cd <your rails application>.ca/<your rails application>-form/
$ bundle install
$ rails server
=> Booting WEBrick
=> Rails 3.2.8 application starting in development on http://0.0.0.0:3000
=> Call with -d to detach
=> Ctrl-C to shutdown server
=> Ctrl-C to shutdown server
[2012-12-09 00:40:34] INFO  WEBrick 1.3.1
[2012-12-09 00:40:34] INFO  ruby 1.9.3 (2012-11-10) [i686-linux]
[2012-12-09 00:40:34] INFO  WEBrick::HTTPServer#start: pid=6993 port=3000
^C[2012-12-09 00:40:41] INFO  going to shutdown ...
[2012-12-09 00:40:41] INFO  WEBrick::HTTPServer#start done.
Exiting

Now that we know the app runs on the built in development server we can setup apache using the information provided when we installed passenger; below is an example of the site I was moving over that is a PHP site with a RoR application that is run under a sub url directory.

# /srw/www/<your rails application>.ca/apache-httpd.conf but linked as /etc/apache2/sites-avaiable/<your rails application>.ca

# RoR as per the `passenger-install-apache2-module` https://github.com/joshfng/railsready/blob/master/README.md
LoadModule passenger_module /usr/local/lib/ruby/gems/1.9.1/gems/passenger-3.0.18/ext/apache2/mod_passenger.so
PassengerRoot /usr/local/lib/ruby/gems/1.9.1/gems/passenger-3.0.18
PassengerRuby /usr/local/bin/ruby

<VirtualHost *:80>
 ServerAdmin support@danols.com
 ServerName <your rails application>.ca
 ServerAlias www.<your rails application>.ca development.<your rails application>.ca
 # Answering to server alias `development.domain.tld` allows one to develop the site on a development server utilizing 
 # same apache-conf file that will be used on live server. To make this work one only needs to update domain DNS 
 # records for `development.domain.tld` to point a development server and `www.domain.tld` and `domain.tld` to a
 # production server.

 # Canonical - prefix www to `domain.tld` but not `something.domain.foo` - however www prefix is no longer popular
 #RewriteEngine on
 #RewriteCond %{HTTP_HOST} ^w+.w+(:d+|)$
 #RewriteRule !"" http://www.%{HTTP_HOST}%{REQUEST_URI} [R=301,L,NC]

 # Authenticated access to this project, this is only used during development server to prevent unauthorized access. 
 # As a fallback you should have default auth requirement enabled in the global Apache `/etc/apache/conf.d` settings.
 # We also prevent serving of the password logins file however again this is only used for development client access.
 Redirect /apache-logins.htpasswd /
 <Location />
     AuthType basic
        AuthName "Development Area"
        AuthBasicProvider file
        AuthUserFile /srv/www/<your rails application>.ca/apache-logins.htpasswd
        Require user jeremy
 </Location>

 # DocumentRoot where PHP / HTML Files are served from.
 DocumentRoot /srv/www/<your rails application>.ca/        

 # Ruby and Rails application form module - to find your GEM_HOME run 'gem list -d bundler' 
 <Location /<your rails application>-form/>
  RailsEnv development
  #RailsEnv production
  RailsBaseURI /<your rails application>-form
  PassengerAppRoot /srv/www/<your rails application>.ca/<your rails application>-form/
 </Location>
 
 # Apache log file location and settings; keeping log within project is not recommended as site can be on many servers
 ErrorLog /var/log/apache2/<your rails application>.ca-errors
 CustomLog /var/log/apache2/<your rails application>.ca combined
 
 # common redirects
  #Redirect permanent /gapps/ https://www.google.com/a/<your rails application>.ca/
 #Redirect permanent /analytics/ http://www.google.com/analytics/

</VirtualHost>


Comments

  1. Daniel, I can't thank you enough, I was truggling like you to make it work on a VPS linode , and your posted saved me days of pains !
    Those stackscript are useless for Rails deployment :(

    ReplyDelete
  2. I am glad Vincent this post helped and thank you for posting :) .

    ReplyDelete

Post a Comment

Popular posts from this blog

Opera SOCKS Proxy Setup Issues

SOCKS error: Connection closed by remote server When setting up SOCKS only proxy in Opera web browser make sure to specify the IP address instead of your fully qualified domain name (FQDN). Using a host name will not work and Opera simply fails to connect to the proxy server. Sample working setup screen shot with a Dante proxy server , note that HTTP, HTTPS, FTP, SSH options are left blank. Bug DSK-364301 has been filled with Opera, if it has been a while since this post and the issue still not fixed feel free to add your word of encouragement by emailing DSK-364301@bugs.opera.com :)

How to child proof a fireplace

DIY - Do it yourself fireplace child guard Our wonderful 8.5 month old Sofia has become a crawling race car with an untamed thirst for exploration. And so with the cold nights approaching we needed to child proof the fireplace. This however proved to be more difficult than would reasonably expect, I've checked the local Toys "R" Us, Walmart, and even a Canadian Tire with no success for a ready to use product. Internet search was more fruitful and returned a few online stores one could order from, however in all honestly they didn't look too sturdy to me. So I build my own relatively quickly and inexpensively. Materials needed is a privacy plastic lattice - the smallest hole pattern - a few screws and anchors; tools needed are a drill, and a handsaw if you don't have the lattice cut at the store - that’s it. The construction consits of screwing the lattice into the wall and the final product is easiest explained through following pictures. Feel free to +1 this po…

Duplicate value found: duplicates value on record with id: <unknown>.

System.DmlException: Insert failed. First exception on row 0; first error: DUPLICATE_VALUE, duplicate value found: <unknown> duplicates value on record with id: <unknown>.The above error is triggered in the database layer and caused by a trigger or workflow outside of your main code of block that is bubbling this exception. This is rather difficult to track down especially if you are unfamiliar with the code, I am sharing my procedure in the hopes this saves you time - if you find this helpful drop me a line or follow me on twitter @danielsokolows. This error is caused by unique field constraint on the object, so the first step is to examine the object and locate the API names of all unique fieds. You can do this through SF direclty 'Setup < Customize &lt <object being inserted> &lt Fields' or by downloading the `src/objects` metadata information and searching for <unique>; I preffer the latter and actually download ALL matadata information f…