Apache 2.2, Rails, and FastCGI on Fedora Core 5
View blog reactions Written on April 6, 2007 by Chris Heald
I’ve managed to get FastCGI running through Apache, and will be testing its performance in the context of Rails in the next few weeks. I haven’t done any formal testing, but it feels faster than my current Apache ProxyLoadBalancer -> Mongrel setup.
The actual setup is relatively painless. You’ll need to compile and install FastCGI itself, and then most people can compile and install modfastcgi. I’m on Fedora Core 5, which modfastcgi doesn’t compile on, so I used a pre-built RPM. That installed a file called fastcgi.conf in my /etc/httpd/conf.d directory, as well.
The contents of this file are relatively basic.
LoadModule fastcgi_module modules/mod_fastcgi.so <IfModule mod_fastcgi.c> AddHandler fastcgi-script .fcgi FastCgiIpcDir /tmp/fastcgi </IfModule>
Do note that you need to ensure that in your http.conf file, you have your User and Group directives before your conf.d includ directive. I had to swap their positions in my httpd.conf file.
It was like this, which meant that since the User hadn’t been defined, Apache didn’t have permissions to write to /tmp/fastcgi
Include conf.d/*.conf User apache Group apache
Swapping them like so gave me the proper permissions:
User apache Group apache Include conf.d/*.conf
I maintain separate conf files for each domain I run, just for my own sanity. In the relevant file, I added the following:
<IfModule mod_fastcgi.c> FastCgiServer /var/www/html/jor/public/dispatch.fcgi -processes 4 -idle-timeout 120 -initial-env RAILS_ENV=development </IfModule>
This doesn’t go inside a VirtualHost or Directory directive - it’s on the top level. I just put it in my domain file because that’s where it’s pertinent to my setup. You could put it in httpd.conf easily enough. This directive starts four Rails processes in the development environment. If you don’t specify this directive, then FastCGI goes into “dynamic mode”, where it spawns a new process for each request, which then dies off after a certain amount of inactivity. Given Rails’ startup time and requirements, this is a pretty bad idea. This method tells it to start up four instances that’ll hang around for as long as the server is running, and they’ll serve requests as necessary without restarting.
Next, I set up my virtual host. Specifically, I need the Directory directive here with the AllowOverride, because Rails uses a .htaccess file in the public/ folder to push traffic around.
<VirtualHost *:80>
ServerName mydomain.com
DocumentRoot /var/www/html/jor/public
ErrorLog /var/log/httpd/error_log.jor.development
<Directory /var/www/html/jor/public>
AllowOverride All
</Directory>
</VirtualHost>
Of note here is the fact that the DocumentRoot cannot have a trailing slash or FastCGI gets all confused.
Once this was done, I saved it and installed the fastcgi gem:
[root@localhost #] gem install fcgi
Next, I opened up /var/www/html/jor/public/.htaccess and changed the rewrite rules a bit.
AddHandler fastcgi-script .fcgi
AddHandler cgi-script .cgi
Options +FollowSymLinks +ExecCGI
RewriteEngine On
# Any file that actually exists will get handled by apache
RewriteCond %{REQUEST_FILENAME} -f
RewriteRule ^(.*)$ $1 [L]
# Any request for a file that doesn't exist is passed to rails for routing
RewriteRule ^(.*)$ dispatch.fcgi [QSA,L]
ErrorDocument 500 "<h2>Application error</h2>Rails application failed to start properly"
Note that I’m passing to dispatch.fcgi, not dispatch.cgi.
Save and reload apache and you’re good to go. If you run into problems, then
- Check and make sure that your FastCgiIpcDir is Apache-writable
- Ensure that your RAILS_ROOT/tmp directory is Apache-writable
- Ensure that your RAILS_ROOT/log directory is Apache-writable
- Check the contents of the apache error_log for more information if things don’t seem to work
Posted in 