Lost while trying to deploy rails app on apache


#1

I need to graft some rails apps onto a website running apache 1.3 and
I must be missing something very obvious because I cannot get things
working properly. Here is what I need:

  1. The server must be running apache 1.3. A very large body of PHP
    content is currently vended by the server through 5 vhosts and I have
    neither the time nor resources to replace apache1 with apache2 or
    lighttpd. Maybe someday, but not right now.
  2. The rails apps cannot be their own vhosts. Basically, my apps must
    be accessible via vhost.server.com/path/to/my/rails/app so they fit in
    seamlessly with the existing server content and structure.
  3. The setup needs to be as transparent as possible. The more stuff
    that gets stuffed in config files and redirected through proxies the
    more unmaintainable the server becomes. “Sysadmin” isn’t in my job
    description, so I don’t need the added job security of a complex and
    opaque setup. :wink: The PHP applications on the server are dirt simple
    to maintain since deployment basically consists of running ‘svn
    update’ somewhere in the server’s directory root. You don’t need to
    read through config files or figure out what’s proxied to which
    server. I’d like a similar setup for the new rails apps I’m trying to
    deploy.

I had hoped those were simple requirements but I’m starting to feel
like such a setup is unachievable. I’ve just spent a great deal of
time over two days digging through this list’s archives and through
the wiki trying to get something working. Briefly, I’ve tried the
following two setups:

  1. Proxying my apps through apache to lighttpd instances. James Duncan
    Davidson’s excellent Apache2 and Rails on Lighty pages served as a
    reference: http://duncandavidson.com/essay/2006/01/railsonapache and
    http://duncandavidson.com/essay/2005/12/railsonlighty
  2. Grafting my apps by symlinking /public to a location in the
    directory root and then building FCGI and configuring Apache. I used
    these two wiki pages as guides:
    http://wiki.rubyonrails.org/rails/pages/FastCGI and
    http://wiki.rubyonrails.com/rails/pages/HowtoUseSymLinksToGraftRailsOntoYourWebsite

I was reluctant to start with the proxy setup since that was in
violation of goal 3, but almost all of the documentation out on the
net strongly encouraged that route if Apache had to be used for legacy
content. It also seemed simple to graft my app into a specific
subdirectory under the document root. Unfortunately, I simply could
not get it to work. Following
http://www.hivelogic.com/articles/2005/12/01/ruby_rails_lighttpd_mysql_tiger,
I built lighty, FCGI and the Ruby FCGI bindings. I then followed
James’ guide to configure, test and deploy Rails on lighty and could
successfully connect to the server on a non-standard port. My app ran
just fine on lighty, so I stuck what I thought would be appropriate
proxy directives in the vhost’s apache conf file

ProxyRequests Off

ProxyPass /path/to/app/ http://lighty.server.com:8001/
ProxyPassReverse /path/to/app/ http://lighty.server.com:8001/

and restarted apache. Things looked great until I clicked on a link. I
was magically redirected from vhost.server.com/path/to/my/rails/app to
vhost.server.com. A bit of research and I discovered that I needed to
add

ActionController::AbstractRequest.relative_url_root =

“/path/to/my/rails/app”

to my config/environment.rb file. A quick lighty restart and my paths
were preserved. (Almost there!) However, whenever I clicked on a link
the server would load
vhost.server.com/path/to/my/rails/app/controller/method/id and never
redirect back to the app’s root as it should. Furthermore, the calls
to my controller’s methods didn’t have any effect: going back to the
root manually would bring things back in the same state. I double
checked all of my settings in apache and lighty, bounced both servers,
dug through the wiki and this list and eventually went to bed. I have
no idea why things don’t work.

Today I decided to take a different route and try the second setup. I
placed the symlink into apache’s document root, built mod_fcgi, added

LoadModule fastcgi_module libexec/httpd/mod_fastcgi.so
AddModule mod_fastcgi.c

FastCgiIpcDir /tmp/fcgi_ipc/
AddHandler fastcgi-script fcgi

to the global apache config file and added

<Directory "/Volumes/Data/WebContent/htdocs/path/to/symlink">
   Options +ExecCGI

    RewriteRule ^$ index.html [QSA]
    RewriteRule ^([^.]+)$ $1.html [QSA]
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteRule ^(.*)$ dispatch.fcgi [QSA,L]
    ErrorDocument 500 "<h2>Application error</h2>The regression

voting Rails application failed to start properly."

to the vhost’s config. (‘RewriteEngine On’ was already in the vhost’s
config.) I restarted apache and didn’t get any love at all. I can get
to the 404.html and 500.html files but the fcgi handler never comes
into play. I turned on +Indexes and could see the contents of /public,
so the symlink is working. The apache error file didn’t contain
anything juicy so I turned on mod_rewrite logging. The best I could
divine from that output was that the rewrite rules specified in the
Directory statement never got parsed… I also tried using the the
.htaccess file in /public by setting the vhost’s AllowOverride to
All, commenting out the Directory statement and restarting apache.
Same result, which didn’t surprise me too much. I have no idea why the
rewrites aren’t having any affect.

So, here I am at the end of two days of trying to deploy one rails
app. I’m starting to feel pretty stupid since I feel what I’m trying
to do would be fairly common and should be simple. Can anyone out
there help me out?


Ryan


#2

“…my config/environment.rb file. A quick lighty restart and my
paths
were preserved. (Almost there!) However, whenever I clicked on a link
the server would load
vhost.server.com/path/to/my/rails/app/controller/method/id and never
redirect back to the app’s root as it should. Furthermore, the calls
to my controller’s methods didn’t have any effect: going back to the
root manually would bring things back in the same state. I double
checked all of my settings in apache and lighty, bounced both servers,
dug through the wiki and this list and eventually went to bed. I have
no idea why things don’t work.”

the link has to point to /path/to/rails/app since your app is in a
subdirectory of a vhost. What you need is to manipulate the rails
routes.rbfile to look like something like

map.connect ‘path/to/rails/app/:controller/:action/:id’

this shouldl resolve your issues. You can not hide the
/path/to/rails/app
as long as it is a subdirectory of a parent vhost, however you can make
rails recognize the controller and actions you need.

-adam

On 2/15/06, Ryan N. removed_email_address@domain.invalid wrote:

seamlessly with the existing server content and structure.

  1. Grafting my apps by symlinking /public to a location in the
    directory root and then building FCGI and configuring Apache. I used
    these two wiki pages as guides:
    http://wiki.rubyonrails.org/rails/pages/FastCGI and
    <
    http://wiki.rubyonrails.com/rails/pages/HowtoUseSymLinksToGraftRailsOntoYourWebsite

I was reluctant to start with the proxy setup since that was in
violation of goal 3, but almost all of the documentation out on the
net strongly encouraged that route if Apache had to be used for legacy
content. It also seemed simple to graft my app into a specific
subdirectory under the document root. Unfortunately, I simply could
not get it to work. Following
<
http://www.hivelogic.com/articles/2005/12/01/ruby_rails_lighttpd_mysql_tiger


#3

On 2/15/06, Adam D. removed_email_address@domain.invalid wrote:

no idea why things don’t work."

the link has to point to /path/to/rails/app since your app is in a
subdirectory of a vhost. What you need is to manipulate the rails routes.rb
file to look like something like

map.connect ‘path/to/rails/app/:controller/:action/:id’

this shouldl resolve your issues. You can not hide the /path/to/rails/app
as long as it is a subdirectory of a parent vhost, however you can make
rails recognize the controller and actions you need.

I think changing the default route to
‘path/to/rails/app/:controller/:action/:id’ would fix my problems if I
able to successfully run using fcgi in apache. Unfortunately, I cannot
get the rewrite rules to take effect so the dispatch.fcgi script never
gets called and the routes are never processed.

How can I debug this failure? I’d love to get fcgi working in apache
so that I can drop all of this proxy stuff.

Changing the default route wouldn’t help my proxy issues since lighty
is calling dispatch.fcgi with the proper ‘:controller/:action/:id’. In
fact, setting a default route of
‘path/to/rails/app/:controller/:action/:id’ breaks path recognition.
This makes sense since apache is proxying
http://vhost.server.com/path/to/rails/app/:controller/:action/:id’ to
http://lighty.server.com/:controller/:action/:id’.

As far as I can tell, proxying and url generation is working as it
should. For example, when I go to
http://vhost.server.com/path/to/rails/app” the request is proxied to
http://lighty.server.com” and I see the index that I expect. All
links on the page are prefixed properly and appear as
http://vhost.server.com/path/to/rails/app/:controller/:action/:id”.
The problem is that nothing happens when I click on those links, even
though it seems as though all of the back-end magic is working
correctly.


Ryan


#4

I think changing the default route to
‘path/to/rails/app/:controller/:action/:id’ would fix my problems if I
able to successfully run using fcgi in apache. Unfortunately, I cannot
get the rewrite rules to take effect so the dispatch.fcgi script never
gets called and the routes are never processed.

How can I debug this failure? I’d love to get fcgi working in apache
so that I can drop all of this proxy stuff.

Since the recommended “proxy from apache -> lighty” setup isn’t
working, I’m trying to work out the problems with the “running under
fcgi in Apache” setup.

Here’s what should be the relevant excerpt from the global apache 1.3
conf file:

LoadModule fastcgi_module libexec/httpd/mod_fastcgi.so
AddModule mod_fastcgi.c
<IfModule mod_fastcgi.c>
	FastCgiIpcDir /tmp/fcgi_ipc/
	AddHandler fastcgi-script fcgi
</IfModule>

This is my vhost configuration:

<VirtualHost *:80>
	ServerName vhost.server.com
	DocumentRoot "/var/vhost"
	DirectoryIndex "index.html" "index.php"

	RewriteEngine On
	RewriteLog /var/tmp/rewrite.log
	RewriteLogLevel 9

	<Directory "/var/vhost/htdocs">
		Options All -Indexes -Includes +ExecCGI +FollowSymLinks +MultiViews
		AllowOverride All
	</Directory>
</VirtualHost>

This is the .htaccess file:

AddHandler fastcgi-script .fcgi
AddHandler cgi-script .cgi
Options +FollowSymLinks +ExecCGI

RewriteEngine On
#Alias /rails /var/vhost/htdocs/rails
#RewriteBase /rails
RewriteRule ^$ index.html [QSA]
RewriteRule ^([^.]+)$ $1.html [QSA]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ dispatch.fcgi [QSA,L]
ErrorDocument 500 "<h2>Application error</h2>Rails application failed

to start properly

Most, if not all, of this should be the default setup, minus comments.
Why do I still get 500 errors when I try to access the site?

It took me less time to learn Ruby and Rails and write this app than
it’s taken me to get this far in deployment… I’m sorry, but it
really shouldn’t be this hard. I’ve tried so many different variations
of this over the past couple of days that I think I’m starting to go
mad.

All I want to do is seamlessly deploy my fancy new app in on a server
that has a bunch of legacy content.


Ryan


#5

Ok, I’ve returned from mod_rewrite hell. In order to get this setup
working I had to basically rewrite the mod_rewrite directives. The
following fails:

RewriteRule ^$ index.html [QSA]
RewriteRule ^([^.]+)$ $1.html [QSA]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ dispatch.cgi [QSA,L]

while the following works:

RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^(.)[^/]$ %{REQUEST_URI}/ [R=301,L]
RewriteCond %{REQUEST_FILENAME}/index.html -f
RewriteRule ^([^.]
)$ %{REQUEST_URI}/index.html [L]
RewriteCond %{REQUEST_FILENAME}.html -f
RewriteRule ^([^.]+)$ %{REQUEST_URI}.html [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ dispatch.fcgi

For a period of time I even had to set RAILS_ROOT manually… now that
I’ve finally converged on a set of rewrite directives that actually
work, though, the explicit RAILS_ROOT doesn’t seem to be needed.
Hopefully that remains the case.

I do have a question, though: Why have all of the [QSA] flags on the
original RewriteRule directives? It seems to me that we don’t want to
append anything to the original query string – we just want to
redirect. Right?

In the meantime, I’m going to file a ticket on this.

In summary: all of the documentation on getting rails to work when
symlinked into a Apache document root failed miserably for me. Here’s
what worked:

  1. Follow the instructions for building the fastcgi API on
    http://www.hivelogic.com/articles/2005/12/01/ruby_rails_lighttpd_mysql_tiger.
  2. Also download the mod_fcgi sources from
    http://www.fastcgi.com/dist. Follow the INSTALL file’s instructions
    for compiling and installing an Apache DSO.
  3. Open up apache’s global config file (on Mac OS X:
    /etc/httpd/httpd.conf) and make sure the appropriate FCGI goop’s in
    place. Namely:
    LoadModule fastcgi_module libexec/httpd/mod_fastcgi.so
    AddModule mod_fastcgi.c

    FastCgiIpcDir /tmp/fcgi_ipc/
    AddHandler fastcgi-script fcgi

Make sure the LoadModule and AddModule directives are grouped with the
file’s other LoadModule and AddModule directives. The LoadModule
directive must come before and ClearModuleList directives, while the
AddModule should be after.
4) Bounce httpd. sudo apachectl graceful will do the trick.
5) If you are using a vhost config (I believe that, by default, this
is the case on Mac OS X. If you have a file in /etc/httpd/sites/ then
you should be.) then make sure that there is an “AllowOverride All”
directive somewhere in there and is wrapped in the correct Directory
directive. If all hosts should be able to run rails apps then go ahead
and change the global conf file’s setting from “AllowOverride None” to
“AllowOverride All”. This lets the .htaccess files take affect.

[As an aside, it would be wonderful to restrict the AllowOverride to a
specific filesystem directory outside of the document root, like
/var/www/rails when the doc root is /var/www/htdocs. Unfortunately,
this doesn’t seem to be possible. You can only restrict it to a set of
paths in /var/www/htdocs, as far as I can tell. If anyone knows of a
way around this, I’d love to hear it.]

  1. Create your rails app. Write your fancy code. Test.
  2. Make sure all files and directories are readable by the web server.
    Make sure the public/dispatch* files are executable by the server.
  3. Create the symlink from /public to /path/to/final/url
  4. Edit .htaccess and replace the current mod_rewrite voodoo with my
    (hopefully correct) voodoo listed above.
  5. Profit.

Feedback is welcome. I wouldn’t be surprised if I’ve done something
wrong…


Ryan