HOWTO Install Typo on FreeBSD with Lighttpd, FastCGI, and Apache2 Proxy
Okay, I've spent some time configuring one of my FreeBSD servers to host multiple instances of Typo running via FastCGI processes ala Lighttpd, proxied by Apache2, each as a dedicated user. Like everything, there's more than one way to do it and somebody else probably has figured out a more better, more slicker way, but this is how I'm doing it at present. Your mileage may vary. Caveat emptor, etc.
Installing Required Software
The easiest way to install all of the required software on FreeBSD is to install them via the FreeBSD Ports Collection. If you need to learn how to use Ports, visit the FreeBSD Handbook page on Using the Ports Collection.
Note: Ken just spent a lot of time tracking down an issue w/help of pdcawley (thanks bunches bud!). If you encounter ruby dumping core, bus errors and error.log entries looking like this:
2006-03-18 15:30:50: (mod_fastcgi.c.2430) unexpected end-of-file (perhaps the fastcgi process died): pid: 27650 socket: unix:/tmp/typo-yourblog.socket-1 2006-03-18 15:30:50: (mod_fastcgi.c.3172) child signaled: 4 2006-03-18 15:30:50: (mod_fastcgi.c.3215) response not received, request sent: 982 on socket: unix:/tmp/typo-youblog.socket-1 for /dispatch.fcgi , closing connection
then use the ruby-nopthreads port.
Install Apache2 with mod_proxy modules built in (the port disables this by default, so it needs to be implicitly called)cd /usr/ports/www/apache2 make WITH_PROXY_MODULES=yes install clean
Then, to insure that Apache2 is automatically built with mod_proxy modules in the future
echo "WITH_PROXY_MODULES=yes" >> /etc/make.conf
Install Ruby On Rails
cd /usr/ports/www/rubygem-rails; make install clean
If you want Textile formatting (if you don't know, you do) install Redcloth
cd /usr/ports/www/rubygem-redcloth; make install clean
Install FastCGI library for Ruby
cd /usr/ports/www/ruby-fcgi; make install clean
Install FastCGI Development Kit
cd /usr/ports/www/fcgi; make install clean
Install mod_fcgid
cd /usr/ports/www/mod_fcgid; make install clean
in /usr/local/etc/apache2/httpd.conf add the following to the 'LoadModule' section:
LoadModule fcgid_module libexec/apache2/mod_fcgid.so <IfModule mod_fcgid.c> AddHandler fcgid-script .fcgi </IfModule>
Restart apache2
apache2ctl restart
If there were no errors written to screen, ensure that none were written to log
tail -n 50 /var/log/http-*
If there are no errors, continue on to Installing Typo.
Installing Typo
Install Typo Stable
or
Install Typo Current from Trunk using Subversion (NOTE if you need subversion, install it with 'cd /usr/ports/devel/subversion; make install clean')
svn checkout svn://typosphere.org/typo/trunk typo
Configure a directory scheme. I use the follwoing:
/home/username/websites/typo.somedom.tld
Copy Typo to your target directory
cp -R typo /home/username/websights/typo.somedom.tld
Set ownership to your user
chown -R username:username /home/username/websites/typo.somedom.tld
Configuring Typo
There are some Typo files needing modification. FreeBSD's bash port is installed in /usr/local/bin/bash rather than /usr/bin/bash.
Later versions of Typo use /bin/sh but you should double check.
I also had to modify some other paths of a few files in public to get my statup scripts to work during reboot.
It was a bit perplexing for a while there, as I could run them manually from command line, but they failed upon actual reboot.
/usr/bin/env ruby
with
/usr/local/bin/ruby
in public/dispatch.fcgi and public/dispatch.rb.
_(This is because /usr/local/bin isn't in your path when lighttpd runs. Try explicitly appending it to your path in the
lighttpd init script)_
Database
Assume you can create database and set access as appropriate. I'm using MySQL, e.g.:
mysql -p create database username_typo; grant all on username_typo.* to 'username'@'localhost' \ identified by 'somekillerpassword'; flush privileges; use username_typo; source /path/to/db/schema.mysql.sql;
Edit config/database.yml as appropriate to mesh with above.
Lighttpd
Edit config/lighttpd.conf. Specify bind address and port, username, groupname, etc., e.g.:
server.pid-file = "/var/run/typo-username.pid"
server.port = 3000
server.bind = "127.0.0.1"
server.event-handler = "freebsd-kqueue"
server.name = "typo.username.com"
server.username = "username"
server.groupname = "username"
server.modules = ( "mod_rewrite", "mod_fastcgi", )
server.indexfiles = ( "dispatch.fcgi" )
server.document-root = "/home/username/websites/typo.username.com/public/"
server.error-handler-404 = "/dispatch.fcgi"
server.errorlog = "/home/username/websites/typo.username.com/log/error.log"
url.rewrite = ( "^/$" => "index.html", "^([^.]+)$" => "$1.html" )
#### fastcgi module
fastcgi.server = (
".fcgi" => (
"typo" => (
"min-procs" => 4,
"max-procs" => 4,
"socket" => "/home/username/tmp/typo-username.socket",
"bin-path" => "/home/username/websites/typo.username.com/public/dispatch.fcgi",
"bin-environment" => ("RAILS_ENV" => "production" ),
"idle-timeout" => 120
)
)
)
Test Your Configuration
./script/lighttp & netstat -na | grep 3000 kobuk# netstat -an | grep 300 tcp4 0 0 127.0.0.1.3000 *.* LISTEN
Open a browser to !http://127.0.0.1:3000
Note fro Ken: Above was edited from original author's text. Original author does not run a web browser on the server running their blogs. Initial text assumed you have access to the port, e.g. 3000 on the server in question. So I stand by my original instructions:
Point your web browser to typo.username.com. Or whatever your server is named;-)
If you're not seeing your bright shinny new blog, enable vebose logging in your my.cnf and make sure typo is actually connecting to MySQL. Assuming you've gotten this far and all is well, I move config/lighttp.conf to /usr/local/etc/username_typo.conf because I don't want my end users tweakig their config and doiong lame things like setting min-procs to 2000....
Apache2 mod_proxy
To get Apache2 set up to proxy incoming requests on port 80 you need to modify /usr/local/etc/apache/httpd.conf
<VirtualHost xxx.xxx.xxx.xxx:80>
ServerAdmin webmaster@username.tld
ServerName typo.username.tld:80
ProxyRequests Off
ProxyPreserveHost On
RewriteEngine On
RewriteRule ^/(.*) http://127.0.0.1:3000/$1 [P,L]
ProxyPassReverse / http://127.0.0.1:3000/
</VirtualHost>
Don't forget the ProxyPreserveHost else everything will look like it's working but routes will see 127.0.0.1:3004 as incoming hostname and use it to write all the internal rss links.
Restart Apache2
apache2ctl restart
You should now be able to access your Typo site via port 80.
Start up script
Now we need to get a start up script happening to start/stop Typo on system srtart/shudown.
There's lots of ways to do this but I took a stab at doing it at least minimally conrrectly for FreeBSD by using /usr/local/etc/rc.d and /etc/rc.conf.local. You could do lots better than this, but here's my modified lighttpd.sh:
#!/bin/sh # # $FreeBSD: ports/www/lighttpd/files/lighttpd.sh.tmpl,v 1.3 2005/02/06 16:30:35 sem Exp $ # # PROVIDE: lighttpd # REQUIRE: DAEMON # BEFORE: LOGIN # KEYWORD: FreeBSD shutdown # kg rc.d script to start instance of typo running under FastCGI via lighttpd # as dedicated user on dedicated port, e.g. 3000. Then proxy via Apache # # copy lighttp.conf included with typo distribution to /usr/local/etc # and modify as necessary to suit your setup # # Add the following lines to /etc/rc.conf or /etc/rc.conf.local # #typo_${blogname}_enable="YES" #typo_${blogname}_conf="/usr/local/etc/typo${blogname}.conf" #typo_${blogname}_chdir="/path/to/the/typo/instance/you/wish/to/run/" # # . /etc/rc.subr name=typo_username rcvar=@set_rcvar@ # specify here just incase we space out and forget to put it in lighty config. RAILS_ENV=production export RAILS_ENV command=/usr/local/sbin/lighttpd pidfile=/var/run/typo-username.pid required_files=${typo_username_conf} stop_postcmd=stop_postcmd stop_postcmd() { rm -f $pidfile } # set defaults typo_username_enable=${typo_username_enable:-"NO"} typo_username_conf=${typo_username_conf:-"/usr/local/etc/typo_username.conf"} typo_username_chdir=${typo_username_chdir:-"/nonexistent/"} load_rc_config $name command_args="-f ${typo_username_conf}" run_rc_command "$1"
Then in /etc/rc.conf.local:
typo_username_enable="YES" typo_username_chdir="/home/username/websites/typo.username.tld/"
I just create a separate typo_username.sh for each blog. It would be much slicker to have this all in one .sh file and loop through the typo instances, e.g. the way FreeBSD's /usr/local/etc/rc.d/zope.sh does but I'm not a rc.d scripting guru so it will have to wait until I have more time....
Conclusion
And that's about it. Repeat as necessary. End result is multiple instances of Typo, each running as separate user, on dedicated high numbered port via FastCGI all being proxied by an Apache front end. This is quick and dirty wiki page. I'm sure I made a typo here or there (no pun intended) but xal asked me to post it and I wanted to give something back. Please give it some scrutiny and use some common sense.... Questions? Comments?? Author is Ken Gunderson and can be reached via kgunders at don't spam me unless you want my mail server to blacklist you forever teamcool.net. Happy Typo'ing on FreeBSD. Now I really must get some sleeep...;-)
Benchmarks
Okay, had a couple requests for some benchmarks so here's some quick and dirty ab's. Apache2 is straight out of the ports collection and no effort whatsoever invested in tuning and tweaking for performance. Typo version is also pre new and improved and way cool admin interface. Lighty is configured to spawn a dozen FastCGI procs. Machine hardware:
dual AMD Operon 246 4GB DDR400 ECC Registered Memory
System: 5.4-RELEASE-p5 FreeBSD amd64 (could probably increase perf by running in 32 bit mode).
Relevant Ports:
ruby-1.8.2_4 An object-oriented interpreted scripting language ruby18-bdb1-0.2.2 Ruby interface to Berkeley DB revision 1.8x with full featu ruby18-fcgi-0.8.6 FastCGI library for Ruby ruby18-gems-0.8.11 Package management framework for the Ruby language ruby18-iconv-1.8.2 An iconv wrapper class for Ruby mysql-client-4.1.13 Multithreaded SQL database (client) mysql-server-4.1.13 Multithreaded SQL database (server) apache-2.0.54_2 Version 2 of Apache web server with prefork MPM.
1. Start out w/concurrency of 1:
ab -n 10000 -c 1 http://192.168.1.177:80/
Server Software: lighttpd/1.3.15
Server Hostname: 192.168.1.177
Server Port: 80
Document Path: /
Document Length: 2822 bytes
Concurrency Level: 1
Time taken for tests: 1216.168115 seconds
Complete requests: 10000
Failed requests: 0
Write errors: 0
Total transferred: 30380000 bytes
HTML transferred: 28220000 bytes
Requests per second: 8.22 [#/sec] (mean)
Time per request: 121.617 [ms] (mean)
Time per request: 121.617 [ms] (mean, across all concurrent requests)
Transfer rate: 24.39 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 0 0.1 0 4
Processing: 18 120 14.2 118 235
Waiting: 17 120 14.0 117 234
Total: 18 120 14.2 118 235
Percentage of the requests served within a certain time (ms)
50% 118
66% 118
75% 118
80% 118
90% 118
95% 172
98% 175
99% 176
100% 235 (longest request)
Now let's jack concurency up a bit....
$ ab -n 10000 -c 10 http://192.168.1.177:80/
Concurrency Level: 10
Time taken for tests: 146.104187 seconds
Complete requests: 10000
Failed requests: 0
Write errors: 0
Total transferred: 30380000 bytes
HTML transferred: 28220000 bytes
Requests per second: 68.44 [#/sec] (mean)
Time per request: 146.104 [ms] (mean)
Time per request: 14.610 [ms] (mean, across all concurrent requests)
Transfer rate: 203.05 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 0 0.1 0 2
Processing: 18 145 50.9 126 601
Waiting: 18 143 47.5 125 601
Total: 18 145 50.9 126 601
Percentage of the requests served within a certain time (ms)
50% 126
66% 141
75% 157
80% 169
90% 204
95% 237
98% 293
99% 352
100% 601 (longest request)
And some more...
$ ab -n 10000 -c 100 http://192.168.1.177:80/
Concurrency Level: 100
Time taken for tests: 129.502056 seconds
Complete requests: 10000
Failed requests: 0
Write errors: 0
Total transferred: 30383038 bytes
HTML transferred: 28222822 bytes
Requests per second: 77.22 [#/sec] (mean)
Time per request: 1295.021 [ms] (mean)
Time per request: 12.950 [ms] (mean, across all concurrent requests)
Transfer rate: 229.11 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 0 1.4 0 18
Processing: 52 1286 205.9 1275 2403
Waiting: 51 1285 205.5 1274 2402
Total: 69 1286 205.5 1275 2403
Percentage of the requests served within a certain time (ms)
50% 1275
66% 1342
75% 1390
80% 1424
90% 1536
95% 1645
98% 1777
99% 1854
100% 2403 (longest request)
For sake of comparison, on a more modest legacy machine, PIII-700 w/1GB Ram, FBSD-5.4-p5 i386, and max-proc=4:
$ ab -n 1000 -c 1000 http://typo.mydom.tld/
Document Path: /
Document Length: 7951 bytes
Concurrency Level: 1000
Time taken for tests: 7.122140 seconds
Complete requests: 1000
Failed requests: 0
Write errors: 0
Total transferred: 8750272 bytes
HTML transferred: 8493032 bytes
Requests per second: 140.41 [#/sec] (mean)
Time per request: 7122.140 [ms] (mean)
Time per request: 7.122 [ms] (mean, across all concurrent requests)
Transfer rate: 1199.78 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 2 434 1091.0 2 6205
Processing: 133 1036 295.6 1034 2152
Waiting: 130 788 209.6 805 1381
Total: 287 1471 1126.9 1108 7076
Percentage of the requests served within a certain time (ms)
50% 1108
66% 1288
75% 1378
80% 1451
90% 3872
95% 4146
98% 4394
99% 4517
100% 7076 (longest request)
Hmmm.... 140 requests/sec from 4 FastCGI procs doesn't look too shabby to me, eh? But then what do I know....;-P
Am I reading this wrong, or does the PIII look to be much faster than the amd 246?
I guess you'd need to have -c 1000 on the amd to get a more direct comparison.
Response from Ken on 11/25/2005-- Yes, the lowly PIII 700 aoutperformed the dual opteron in these tests. Obviously the Opteron machine is going to scale far beyond the PIII 700. I'm not sure about they precise reasons but I've heard some discussion that the 32 bit code has been highly optimized over time compared to the 64 bit stuff. Don't quote me on it though. The 64 bit stuff really comes into it's own when you need more tha 4 GB of ram. Hence they absolutely rock as database and application servers.
Added by gjw:
on fbsd6, minor additions.. in httpd.conf, also make sure that mod_proxy,
mod_proxy_connect, and mod_proxy_http are uncommented in the loadmodule section, and at the very end of the file (beginning of the VirtualHost settings), uncomment NameVirtualHost *:80 and make sure you have an initial virtual host set up to take all other requests (see http://httpd.apache.org/docs/2.0/vhosts/name-based.html)... unless you're doing IPbased vhosting, in which case, see same document.
Response from Ken on 11/25/2005-- Yes, that goes w/o saying... I was making assumption that anyone doing vhosting had the Apache basics. Correct me if I'm wrong but I don't think you need mod_proxy_connect though unless you're proxying ssl connects.
wac 12/2/2005-- I wrote up instructions for running Typo (or any other Rails app) with Apache httpd with MPM worker and FastCGI. Performance has been really good. http://www.carrel.org/articles/2005/11/21/rails-with-apache-mpm-worker
