Nginx and Mercurial setup

Some weeks ago I switched to Nginx and quit Apache and was quite happy with it. I was so happy that completely forgot about my Mercurial repositories hosted on same server. This happen when I was in hurry and needed to push and pull some changes,  damn. At first I quickly restored Apache, did all needed changes and switched back to Nginx. For sure, I did not like this way and explored how I can connect Mercurial directly to Nginx. I was quite surprised how easy it is and how flexible.

Mercurial via Apache setup

I had Mercurial setup through Apache in a very standard way. /var/hg - Holding all my repositaries /var/hg/hgweb.config
[collections]
repos/ = repos/
/var/hg/hgwebdir.cgi - For Apache CGI support /var/hg/hguser - for user passwords in htpasswd format Apache configuration was the following
ScriptAliasMatch ^/hg(.*) /var/hg/hgwebdir.cgi$1
<Directory /var/hg>
  Options ExecCGI FollowSymLinks
  AllowOverride None
</Directory>
<Location /hg>
   AuthType Basic
   AuthName "Mercurial repositories"
   AuthUserFile /var/hg/hgusers
   Require valid-user
</Location>
Switch to Nginx was really painless.

Nginx and Mercurial setup

Prepare Mercurial

First step I switched to FastCGI instead of CGI. To do this I copied file hgwebdir.fcgi to my repo root /var/hg and made it executable
copy /usr/share/doc/mercurial-common/examples/hgwebdir.fcgi /var/hg
chmod +x /var/hg/hgwebdir.fcgi
Or grab the file here
wget http://selenic.com/repo/hg/raw-file/tip/contrib/hgwebdir.fcgi
Next step is to install something that can spawn FastCGI processes, sine Nginx can not do this by itself.  This is easy with spawn-cgi
#apt-get install spawn-fcgi
I configured it via local unix socket instead of TCP port, it seems to me this way it is more secure. Run it like this:
#spawn-fcgi -u www-data -g www-data -s /tmp/mercurial.sock -d /var/hg/ -- /var/hg/hgwebdir.fcgi
At first start I've run into the problem
spawn-fcgi: child exited with: 1
After running with "-n" switch to see debug output, I  realised that I was missing one python module needed for a setup.
Traceback (most recent call last):
 File "/var/hg/hgwebdir.fcgi", line 25, in
 from flup.server.fcgi import WSGIServer
 File "/usr/lib/pymodules/python2.6/mercurial/demandimport.py", line 106, in _demandimport
 mod = _origimport(name, globals, locals)
 ImportError: No module named flup.server.fcgi
To fix this I installed missing python packages and issue was fixed.
#apt-get install python-flup

Configure Nginx

Edit file /etc/nginx/sites-available/mercurial.conf and add the following server definition:
server {
   listen 80;
   server_name YOUR_MERCURIAL_DOMAIN;
   location / {
     auth_basic "Secure Login";
     auth_basic_user_file /var/hg/hgusers;
     include fastcgi_params;
     fastcgi_param PATH_INFO $uri;
     fastcgi_param REMOTE_USER $remote_user;
     fastcgi_intercept_errors on;
     fastcgi_pass unix:/tmp/mercurial.sock;
  } 
}
The above settings will setup a new virtual host, where all traffic is redirected to the Mercurial FastCGI wrapper. It is important that you forward the PATH_INFO and REMOTE_USER variables. Mercurial will not work correctly without these. Be sure that file /var/hg/hgusers contains all your Mercurial users with passwords, it can be created using htpasswd tool shipped with Apache. Restart Nginx and try to to push pull. In case you have a big push load you may get an 413 Request Entity Too Large error. Just add client_max_body_size 20M; to "server" part of config, like this:
server {
   listen 80;
   server_name YOUR_MERCURIAL_DOMAIN;
   client_max_body_size 20M;

Misc

One thing that changed was repositary path. Before it has /hg/ in path line
http://a32.me/hg/project1
Now it become a full virtual host and changed to:
http://hg.a32.me/project1
I have to reconfigure all my projects, but it is not a pain like it was with CVS. Next thing I though about, I can move repositories under its own uid:gid and not run it under www-data, this can improve security. Do not forget to include running spawn-fcgi into /etc/rc.local for automatically start on system boot.

Links

My story is based on these links.
  • http://www.opennet.ru/base/dev/mercurial_http.txt.html
  • http://geeksharp.com/2010/01/20/mercurial-web-with-fastcgi-nginx/
  • http://fosswire.com/post/2009/08/hosting-mercurial-repositories-with-nginx/
  • http://www.softwareprojects.com/resources/programming/t-how-to-serve-mercurial-hg-repository-over-nginx-1856.html
  • http://www.dikant.de/2009/07/29/running-mercurial-with-fastcgi-in-nginx/

413 Request Entity Too Large

1 comment

  1. Hey A32, what made you change from Apache? I’m still struggling to get my setup working and am still using Apache. I am a little tempted to try this with Nginx, but at the same time I don’t changing just because I can’t fix my apache issue (push auth is denied).

Leave a Reply

Your email address will not be published.