Saturday, September 02, 2006

Solaris + Lighttpd + FastCGI + SSL HowTo

Update (07-05-18): You might also want to check out CoolStack, an optimized open source software stack for the Sun Solaris Operating System.

I hadn't heard about Lighttpd (Lighty) web server before I started to be interested in Ruby on Rails (RoR). Lighttpd is fast, scalable, secure, flexible and lightweight webserver which in RoR community is preferred production web server. One of the main advantages of Lighttpd compared to Apache, for example, is the built in support for FastCGI and very easy yet flexible configuration.

When I was preparing the production environment for one of the RoR applications I was working on lately, I found that even though there is quite a lot of HowTos for installing lighttpd on linux and MacOS, there is not a single one that I could find that would describe this procedure on Solaris / OpenSolaris OS.

While setting up the production environment I got stuck on some steps, and I hope that this HowTo will help anyone trying to deploy his RoR application on Solaris and to avoid problems I had.

Targeted configuration: Solaris 10 + Lighttpd + FastCGI + SSL

1. Prerequisites I started out with the core installation of Solaris 10, this means that I needed to add some packages. Before you start, make sure you have these Solaris packages installed:
  • SUNWhea >>> needed by lighttpd
  • SUNWtoo >>
  • SUNWlibmr >>> needed by fastcgi
  • SUNWlibm >>
If you plan to use only sun compiler to compile everything you will also need SUNWbtool and SUNWsprot packages.

From blastwave.org via pkg-get get:
  • openssl >>> needed by lighttpd for ssl
And one more thing, you must get Sun C Compiler, otherwise you won't be able to install ruby-fastcgi bindings (explained later). Sun C Compiler is part of Sun Studio, which you can download for free here (a free SDN account is needed). There are two ways described on the website how one can get the compiler:
  • option 1) 202MB - works
  • option 2) 365MB - haven't tried
Once downloaded, follow the "Setup" instructions on the website above.

Now we should be ready to start.

2. Lighttpd
At first we should install Lighttpd which can be downloaded from here. (I used gcc to compile this one)
./configure --with-openssl=/opt/csw --with-ldap --with-bzip2 --with-zlib
The output from the configure command should end like this:
Features:

enabled:
auth-crypt
auth-ldap
compress-bzip2
compress-deflate
compress-gzip
large-files
network-ipv6
network-openssl
regex-conditionals
...
...


Make sure the "network-openssl" is in the list of enabled features, if it is not there, check the output from configure tests and if you see that openssl was found and right below it is:
checking for BIO_f_base64 in -lcrypto... no
check your configure arguments and make sure that --with-openssl=/path/to/openssl is set correctly (if installed via pkg-get it will resided in /opt/csw). If this is not done properly everything will compile correctly but the --with-openssl option will be ignored silently!

Let's finish up the installation:

make
make install
Test if everything went well with -v switch
$ ligttpd -v
lighttpd-1.4.11 (ssl) - a light and fast webserver
Build-Date: Aug 30 2006 15:19:28
If there is no "(ssl)" after the version, something is wrong, check if you set --with-openssl=/path correctly.
3. FastCGI
Now we need to install FastCGI which can be downloaded from here:
./configure   --prefix=/usr/local
make
make install

4. ruby-fcgi

Next step is to install ruby-fcgi bindings. This is where I got really stuck. To be able to install this, you need the Sun C Compiler mentioned earlier. If you installed ruby and ruby gems via pkg-get as I did, it comes preconfigured to use Sun compiler by default, even if one is not installed. And if you don't have this compiler you will see all sorts of weird errors when installing gems with native extensions.

Once you have the compiler, installation is trivial. If you are building it manually, download sources here:
ruby install.rb config -- --with-fcgi-dir=/usr/local
ruby install.rb setup
ruby install.rb install
or when using ruby gems:
gem install fcgi -- --with-fcgi-dir=/usr/local
Note the double "--", that is not a typo, it's simply the way how to send parameters to extconf.rb

If you see an error like this:
install.rb: entering config phase...
---> lib
<--- lib ---> ext
---> ext/fcgi
/opt/csw/bin/ruby /root/ruby-fcgi-0.8.6/ext/fcgi/extconf.rb
checking for fcgiapp.h... yes
checking for FCGX_Accept() in -lfcgi... no
<--- ext/fcgi <--- ext
Note this part:
checking for fcgiapp.h... yes
checking for FCGX_Accept() in -lfcgi... no
It most likely means that you are using GCC and not Sun C Compiler, check if cc in your path is pointing to Sun C Compiler, you might also check if the environmental variable CC is not set to gcc. Let's test if fcgi and ruby-fcgi bindings were correctly installed by these commands in irb:
irb(main):001:0> require 'fcgi.so'
=> true
irb(main):001:0> require 'fcgi'
=> true
If both "require" calls return true, you have successfully installed FastCGI and ruby is able to invoke it. 5. SSL Certificate
If you don't have your server certificate yet, you can create a self signed one like this:
openssl req -new -x509 -keyout server.pem -nodes -out server.pem -days 1000
6. Configuring Lighty
Create lighttpd.conf
server.port = 443
server.bind = "0.0.0.0"
server.modules = ( "mod_rewrite", "mod_fastcgi", "mod_accesslog" )
url.rewrite = ( "^/$" => " index.html", "^([^.]+)$" => "$1.html" )
server.error-handler-404 = "/dispatch.fcgi"
server.document-root = "/path_to_your_app/public"
server.errorlog = "/path_to_your_app/log/server.log"
accesslog.filename = "/path_to_your_app/log/access_log"
ssl.engine = "enable"
ssl.pemfile = "/path_to_your_pem_file/server.pem"

fastcgi.server = (".fcgi" =>
( "localhost" =>
(
"min-procs" => 10,
"max-procs" => 10,
"socket"    => "/tmp/yourapp.fcgi.socket",
"bin-path"  => "/path_to_your_app/public/dispatch.fcgi",
"bin-environment" => ( "RAILS_ENV" => "production" )
))
)

mimetype.assign = (
".css"        =>  "text/css",
".gif"        =>  "image/gif",
".html"       =>  "text/html",
".jpeg"       =>  "image/jpeg",
".jpg"        =>  "image/jpeg",
".js"         =>  "text/javascript",
".pdf"        =>  "application/pdf",
".png"        =>  "image/png",
".txt"        =>  "text/plain",
)

7. Ta-da!
Let's start the server

lighttpd -f lighttpd.conf

I hope that these instructions helped you to get Lighty on Solaris.

If you have other recommendations or have problems with the installation, feel free to leave a comment.

Enjoy..

PS: A big thanks to my friend J who helped me figure out that you need Sun C compiler for ruby-fcgi to compile.

UPDATE: added reference to SUNWbtool and SUNWsprot packages in case you want to compile everything with Sun's compiler.

18 comments:

J Irving said...

Note you can avoid the requirement for the dev pro compiler by building your own ruby with gcc.

I'm not saying you should, but some people aren't keen on the Sun compiler for various reasons.

Igor Minar said...

Correct. If you don't use ruby from blastwave (which comes compiled with sun compiler), then you should be able to use gcc to compile ruby-fcgi bindings.

Dick said...

Thanks a lot Igor!

Personally, I'd go for the Sun Compiler - it knows more about your solaris box than gcc does.

All the solaris guys I know insist it produces better/faster code, so you might want to try it before falling back to gcc.

When in Rome... :)

Dick said...

Has anyone got ldap auth working with this setup (lighty 14.11, SXCR b46)?

I'm getting

(mod_auth.c.631) no ldap support available

although mod_auth seems to have linked against it ok:

LD_LIBRARY_PATH=/opt/csw/lib/ ldd /usr/local/lib/mod_auth.so

libldap-2.3.so.0 => /opt/csw/lib//libldap-2.3.so.0

liblber-2.3.so.0 => /opt/csw/lib//liblber-2.3.so.0

Igor Minar said...

Dick, it seems that you are right. Just for curiosity sake I tried to configure LDAP with lighttpd and I got exactly the same error.

So far I haven't been able to fix this, if you figured out something please let me know.

Originally I put the --with-ldap flag to the configure option just for the future use.

Anonymous said...

Hi,

i did all the steps without lighttpd, because i want to run on a Apache.
I set at the beginning:
export CC=/opt/SUNspro/bin/cc

I did not get any error you mentioned with fcgi.

Running the application show the following error:

[Thu Mar 29 13:24:46 2007] [error] [client 10.0.0.120] [ecid: 1175167484:10.0.0.169:22386:0:1,0] FastCGI: incomplete headers (0 bytes) received from server "/var/www/dispatch.fcgi"
[Thu Mar 29 13:24:46 2007] [warn] FastCGI: (dynamic) server "/var/www/dispatch.fcgi" (pid 22387) terminated due to uncaught signal '6' (Abort), a co
re file may have been generated
/opt/csw/lib/ruby/1.8/timeout.rb:52: [BUG] Segmentation fault
ruby 1.8.5 (2006-12-25) [sparc-solaris2.8]

Any hint is welcome....

Igor Minar said...

Have you tried to check what the "/var/www/dispatch.fcgi" looks like?

does that file exist? is it empty?

I haven't seen error like yours while I was playing with this, so I'm not sure if I can help you. :-/

Are you sure that there were no error during compilation? try to recompile the code from scratch again.

James Dasher said...

I've seen this on several tutorials, and I'm getting stuck on it...

The directions say:

irb > require 'fcgi.so'

When I do that I get this error:

LoadError: libfcgi.so.0: cannot open shared object file: No such file or directory - /usr/lib/ruby/site_ruby/1.8/i386-linux/fcgi.so
from /usr/lib/ruby/site_ruby/1.8/i386-linux/fcgi.so
from (irb):1

Now the other one works

irb > require 'fcgi'

Several sites have said that this means the "native bindings" aren't happy with something, but I'm not sure how to fix it...I have been searching A LOT to try and find a fix, any suggestions are appreciated!

Thanks!

P.S. from what I can tell the file fcgi.so is in the folder the error says it isn't, if that helps any.

Igor Minar said...

James,

were there any errors during the compilation of the fcgi code?

Anonymous said...

>Have you tried to check what the >"/var/www/dispatch.fcgi" looks like?
>does that file exist? is it empty?
>Are you sure that there were no >error during compilation? try to >recompile the code from scratch >again.

Hi, i recompiled it several time. There was no error. ;-(
The dispatch.fcgi looked right. I think i have to change from Apache to mongrel or lighttpd.

Thanks...

Anonymous said...

Hi,

I am trying to get Solaris + Apache + mod_fcgid to work. You can read about my progress so far here: http://groups.google.com/group/rubyonrails-talk/browse_thread/thread/a31513b4d432643b/b2977ec222a498e1

I am using gcc. Why do I need Sun's CC compiler?

/Kevin

Anonymous said...

Hi,

I am trying to get Solaris + Apache + mod_fcgid to work. You can read about my progress so far here: http://groups.google.com/group/
rubyonrails-talk/browse_thread/
thread/a31513b4d432643b/
b2977ec222a498e1

I am using gcc. Why do I need Sun's CC compiler?

/Kevin

Igor Minar said...

Kevin,

The reason to use Sun's CC (according to people who know more about it than I do) is that CC creates better optimized code than gcc.

I haven't run any benchmarks so if you want to be sure that this is true, you should google for some benchmarks or create your own.

cheers,
i

Anonymous said...

What's the easiest way to install the sun packages? Anything like apt-get or yum?

Shanti said...

Optimized versions of Openssl, OpenLDAP, Apache etc. for Solaris are all now available in Cool Stack (http://cooltools.sunsource.net/coolstack).
We don't have lighttpd yet (working on it).
For --with-ldap to work (for any app) ,please install the CSKamp package.

And yes - if you're building on SPARC, it is highly recommended that you use the Sun Studio compilers. You'll see a dramatic improvement in performance (anywhere from 30-200%).

Shanti
http://blogs.sun.com/shanti

Igor Minar said...

Shanti, thanx for the reminder. I updated the blog entry to point readers to Cool Stack.

cheers,
i

J Irving said...

How come coolstack doesn't use SMF? Even blastwave supports SMF for mysql, lighttpd, etc.

What's the compelling argument for coolstack?

sparcdr said...

J Irving:

http://blogs.sun.com/shanti/entry/smf_support_for_mysql_in
http://blogs.sun.com/shanti/entry/smf_support_for_apache_in

Shanti posted these for integration with SMF. I just tested it and it works. You need to make sure permissions are right because SMF is more picky about permissions as it operates on least privileges needed. It drops down from root right after the port is binded. Use webservd on logs directory, and if you use ssl, you must make sure it's in the right format, or it complains about it being invalid.