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