e42.uk Circle Device

 

Quick Reference

nginx with cgit

nginx with cgit

cgit is a plain CGI executable for viewing git repositories. nginx is a web server that does not support plain CGI. This is a quick walkthrough on how to get them working together.

Required Packages

  • nginx
  • cgit
  • spawn-fcgi
  • fcgiwrap

On Gentoo (my distribution of choice) just emerge:

emerge nginx spawn-fcgi fcgiwrap

Download and compile cgit (it could be emerged but that would probably take the fun out of it).

Configure nginx with FastCGI

When a request comes in for a file in /cgi-bin/ that request must be forwarded to the fastcgi daemon... in this case fcgiwrap which is wrapping cgit spawned by spawn-fcgi. Yes, you are correct, it is a bit clunky.

http {
... stuff ...
server {
    listen 80;
    server_name localhost;
    access_log /var/log/nginx/localhost.access_log main;
    error_log/var/log/nginx/localhost.error_log info;
    root /var/www/localhost/htdocs;

    location /cgi-bin/cgit {
        root /var/www/localhost;
        include /etc/nginx/fastcgi_params;
        fastcgi_param SCRIPT_FILENAME /var/www/localhost/cgi-bin/cgit;
        fastcgi_split_path_info "^(/cgi-bin/cgit/?)(.+)$";
        fastcgi_param PATH_INFO $fastcgi_path_info;
        fastcgi_param SCRIPT_NAME "/cgi-bin/cgit";
        fastcgi_pass unix:/tmp/cgi.sock;
    }
}
... maybe more stuff ...
}

In another terminal execute create the fcgiwrap daemon:

spawn-fcgi -s /tmp/cgi.sock -P /var/run/cgiwrap.pid -u nginx -g nginx -- /usr/sbin/fcgiwrap -f

To see that it is working attempt to access http://hostname/cgi-bin/cgit. You should be presented with your git repositories.

fastcgi_param

For completeness this is the fastcgi_param file referenced from the nginx.conf file.

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  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  REQUEST_SCHEME     $scheme;
fastcgi_param  HTTPS              $https if_not_empty;

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;

# PHP only, required if PHP was built with --enable-force-cgi-redirect
fastcgi_param  REDIRECT_STATUS    200;

# httpoxy mitigation (https://httpoxy.org/ https://www.nginx.com/blog/?p=41962)
fastcgi_param  HTTP_PROXY         "";

Background Note

fcgiwrap uses DOCUMENT_ROOT and SCRIPT_NAME (concatenated together) or SCRIPT_FILENAME (exclusively) to determine the CGI executable. In the above example fcgiwrap will try to execute: /var/www/localhost/cgi-bin/cgit when a reqest is made to /cgi-bin/cgit (see SCRIPT_FILENAME). DOCUMENT_ROOT is taken from $document_root which is defined on the line root /var/www/localhost and script name is /cgi-bin/cgit. PATH_INFO is the bit after cgit/ (the name of the repo) in /cgi-bin/cgit/sqlite3.git PATH_INFO would be sqlite3.git (see the regular expression for fcgi_split_path_info).

The cgit binary takes note of many environment variables, PATH_INFO, DOCUMENT_ROOT and SCRIPT_NAME are especially important. Look at the source code for fcgiwrap to clear up any confusion.

Important Note

In the above configuration there is a socket created in /tmp for some modern distributions this will not work as the nginx service may be executed in a namespace that provides a private /tmp. To avoid this try placing the socket in /var/run for example:

spawn-fcgi -s /var/run/spawn-fcgi.fcgiwrap.sock -P /var/run/cgiwrap.pid -u nginx -g nginx -- /usr/sbin/fcgiwrap -f

Cleaning up

Naturally this will not work across re-boots, you should make a script to start cgit.

Starting Automatically

Gentoo and Alpine Linux provide start-up scripts for spawn-fcgi under openrc... which is great.

To configure spawn-fcgi to start fcgiwrap at boot make a link for the service in /etc/init.d

cd /etc/init.d
ln -s spawn-fcgi spawn-fcgi.fcgiwrap

Then create a configuration called spawn-fcgi.fcgiwrap file in /etc/conf.d/ (this is the normal way to work with openrc).

FCGI_SOCKET=/var/run/spawn-fcgi.fcgiwrap.sock
FCGI_ADDRESS=
FCGI_PORT=
FCGI_PROGRAM="/usr/bin/fcgiwrap -f"
FCGI_CHILDREN=1
FCGI_CHROOT=
FCGI_CHDIR=/var/www/localhost
FCGI_USER=nginx
FCGI_GROUP=nginx
ALLOWED_ENV="PATH"

Of course you should modify this to taste but as long as your repositories are readable by nginx then you should be fine.

fcgiwrap may now be started by openrc at boot, please note that this service does not depend on nginx and can be started and keep running when nginx is not.

/etc/init.d/spawn-fcgi.fcgiwrap start
rc-update add spawn-fcgi.fcgiwrap default

References

Quick Links: Techie Stuff | General | Personal | Quick Reference