nginx/Catalyst/cgit/FastCGI configuration for tommystanton.com
Getting nginx, Catalyst, and cgit (a web-based Git repository viewer) to work together was an absolute nightmare, but I prevailed. :)
nginx: Running cgit and a Catalyst application via FastCGI
$ sudo mkdir /var/log/nginx/tommystanton.com/
Here is most of my nginx configuration (from /etc/nginx/nginx.conf), which is inside of a 'server' block:
listen 80; server_name tommystanton.com; # I don't like URLs that start with "www." :) if ($host = 'www.tommystanton.com') { rewrite ^/(.*)$ http://tommystanton.com/$1 permanent; } # Redirect requests for '/git' to '/cgit' rewrite ^/git(/.+)?$ /cgit$1 permanent; location /cgit { root /var/www/htdocs/cgit; # /cgit/ doesn't work rewrite ^/cgit/$ /cgit permanent; # Use the FastCGI Unix socket provided by spawn-fcgi(1) fastcgi_pass unix:/var/www/spawn-fcgi/tommystanton_com-cgit; include fastcgi_params-cgit; } # Fix the paths for cgit's few image and style files location ~* ^/cgit/((?:img|css)/[^/]+\.(?:css|png|ico))$ { alias /var/www/htdocs/cgit/$1; } location / { # Use the FastCGI Unix socket provided by Catalyst fastcgi_pass unix:/var/www/htdocs/tommystanton.com/blog/fastcgi.socket; include fastcgi_params-Catalyst; }
The include'd /etc/nginx/fastcgi_params-cgit file (based on Haering's 'server' section):
fastcgi_read_timeout 5m; # XXX Not sure why two slashes are necessary, but one didn't quite do it fastcgi_index //; fastcgi_param DOCUMENT_ROOT /var/www/htdocs/cgit; fastcgi_param SCRIPT_FILENAME /var/www/htdocs/cgit/cgit; fastcgi_param QUERY_STRING $query_string; fastcgi_param REQUEST_METHOD $request_method; fastcgi_param CONTENT_TYPE $content_type; fastcgi_param CONTENT_LENGTH $content_length; fastcgi_param GATEWAY_INTERFACE CGI/1.1; fastcgi_param SERVER_SOFTWARE nginx; ## XXX 'cgit' without the leading forward slash doesn't work #fastcgi_param SCRIPT_NAME /cgit; fastcgi_param SCRIPT_NAME $fastcgi_script_name; fastcgi_param REQUEST_URI $request_uri; fastcgi_param DOCUMENT_URI $document_uri; fastcgi_param DOCUMENT_ROOT $document_root; fastcgi_param SERVER_PROTOCOL $server_protocol; fastcgi_param REMOTE_ADDR $remote_addr; fastcgi_param REMOTE_PORT $remote_port; fastcgi_param SERVER_ADDR $server_addr; fastcgi_param SERVER_PORT $server_port; fastcgi_param SERVER_NAME $server_name;
The include'd /etc/nginx/fastcgi_params-Catalyst file (taken from a Catalyst Advent article):
fastcgi_param QUERY_STRING $query_string; fastcgi_param REQUEST_METHOD $request_method; fastcgi_param CONTENT_TYPE $content_type; fastcgi_param CONTENT_LENGTH $content_length; # Catalyst requires setting PATH_INFO (instead of SCRIPT_NAME) to $fastcgi_script_name fastcgi_param PATH_INFO $fastcgi_script_name; fastcgi_param SCRIPT_NAME /; fastcgi_param REQUEST_URI $request_uri; fastcgi_param DOCUMENT_URI $document_uri; fastcgi_param DOCUMENT_ROOT $document_root; fastcgi_param SERVER_PROTOCOL $server_protocol; fastcgi_param GATEWAY_INTERFACE CGI/1.1; fastcgi_param SERVER_SOFTWARE nginx/$nginx_version; fastcgi_param REMOTE_ADDR $remote_addr; fastcgi_param REMOTE_PORT $remote_port; fastcgi_param SERVER_ADDR $server_addr; fastcgi_param SERVER_PORT $server_port; fastcgi_param SERVER_NAME $server_name;
cgit: Configuration
/etc/cgitrc needs to be updated in a few small places, to account for the '/cgit/' URI:
diff --git a/cgitrc b/cgitrc index 81ef1f0..7ad1353 100644 --- a/cgitrc +++ b/cgitrc @@ -9,7 +9,7 @@ cache-size=1000 #clone-prefix=git://example.com ssh://example.com/pub/git http://example.com/git # Specify the css url -css=/cgit-data/cgit.css +css=/cgit/css/cgit.css # Show extra links for each repository on the index page enable-index-links=1 @@ -24,7 +24,7 @@ enable-log-linecount=1 #favicon=/favicon.ico # Use a custom logo -logo=/cgit-data/cgit.png +logo=/cgit/img/cgit.png # Set the title and heading of the repository index page #root-title=example.com git repositories
fcgiwrap and spawn-fcgi: Funneling CGI to FastCGI
cgit is only designed to be run as a CGI application. nginx doesn't do CGI (only FastCGI), so another set of programs must be used (in this case, fcgiwrap and spawn-fcgi) to act as a wrapper to be able to run a CGI application under FastCGI.
Luckily, I had some hints on how to go about this after going through a blog post by Russell Haering, but it still took me countless hours of trial and error to get everything to work.
fcgiwrap is only available via compiling the source from its Git repository on GitHub. Here is the way I had to go about it, since I'm on CentOS and I can't get the newest libraries needed to compile the current source; I had to use the source tree at a specific commit state:
$ git clone https://github.com/gnosek/fcgiwrap.git $ git checkout 28ac6f9aa5e7dadf9aaf2062ab003a0fb4c82ad8 $ make && sudo cp -v ./fcgiwrap /usr/local/bin/
There seem to be two projects/programs out there called "spawn-fcgi": one is simply a Perl script (I think it's from the nginx community) and the other is a compiled binary (written in C). I used the spawn-fcgi binary, which I could easily install via yum(1).
/etc/sysconfig/spawn-fcgi (initially provided by the RPM package via yum; here is where I make use of fcgiwrap):
# You must set some working options before the "spawn-fcgi" service will work. # If SOCKET points to a file, then this file is cleaned up by the init script. # # See spawn-fcgi(1) for all possible options. # # Example : #SOCKET=/var/run/php-fcgi.sock #OPTIONS="-u apache -g apache -s $SOCKET -S -M 0600 -C 32 -F 1 -P /var/run/spawn-fcgi.pid -- /usr/bin/php-cgi" DIR=/var/www/spawn-fcgi SOCKET="$DIR/tommystanton_com-cgit" OPTIONS="-d $DIR -u nginx -g nginx -s $SOCKET -S -M 0777 -F 1 -P /var/run/spawn-fcgi.pid -- /usr/local/bin/fcgiwrap"
Galuga: Create a user with its own perl
In order to make the Catalyst application (Galuga) a self-sufficient service on the GNU/Linux box, it is best to create an account for it and to give it its own Perl-related resources.
The two tools used for the Perl part are perlbrew (used to install a local perl) and cpanminus (used to install CPAN modules).
$ /bin/su - Password: # useradd galuga # exit $ sudo /bin/su - galuga $ curl -L http://xrl.us/perlbrewinstall | bash # Bootstrap perlbrew $ echo source ~/perl5/perlbrew/etc/bashrc >> ~/.bashrc $ exit $ sudo /bin/su - galuga $ perlbrew install perl-5.12.1 # This will take a while... $ perlbrew switch perl-5.12.1 $ curl -L http://cpanmin.us | perl - App::cpanminus # Bootstrap cpanminus $ cd /var/www/htdocs/tommystanton.com/blog/ # Where my Galuga resides $ cpanm Module::Install::Catalyst && \ cpanm --installdeps . # This will also take a while...
Galuga: Setup the init script
Use galuga_fastcgi_server.sh as an init script, via a symlink:
$ cd /etc/init.d/ && \ sudo ln -sv ./galuga /var/www/htdocs/tommystanton.com/blog/script/galuga_fastcgi_server.sh
Checking init
Now that all is setup, make sure that the required services automatically start on the standard runlevels (alternatively, use something like update-rc.d(8) on a Debian-based machine):
$ for service in nginx galuga spawn-fcgi; do sudo chkconfig --level 2345 $service on done