Call us Toll-Free:
Email us


How to serve Mercurial HG repository over NGinx

Adrian Singer, 09-03-2009
Mercurial server can be setup in two modes:

* hg serve - a built in lightweight web server that is provided as part of the Mercurial package. hg serve can be used to quickly serve a single repository, but it's not a good choice for production systems.

hg serve doesn't support user authentication, multiple repositories and is limited to handling a single connection at a time.

* hgweb.cgi - a Python script that is faster, supports user authentication, multiple repositories, styles and web console.

As part of this post I'll walk you through setting up hgweb.cgi on an NGinx web server.

Step 1 - Install Python

cd /usr/ports/lang/python25
make all install

Step 2 - Install hgweb.cgi

Save this file under your web server main direcory.

#!/usr/bin/env python

import cgitb
from mercurial.hgweb.hgwebdir_mod import hgwebdir
from mercurial.hgweb.request import wsgiapplication
from flup.server.fcgi import WSGIServer


def make_web_app():
return hgwebdir("/home/admin/htdocs/hgweb.config")


Replace /home/admin/htdocs/ with your web server folder

Step 3 - Configure hgweb

Save this config file under your web server main directory.

username = root
editor = vim

changegroup = hg update >&2

baseurl =/.
style= gitweb
push_ssl = false
allow_push = *

Clients = /home/
SPI = /home/admin/htdocs/

Replace mydomain with your web server url

Create this global settings file under /etc/mercurial/hgrc:

style= gitweb

Step 4 - Install Spawn-fcgi

Before we can tell NGinx to handle the hgweb.cgi Python script, we have to install spawn-fcgi

Follow these steps:
wget ""
tar -xvf spawn-fcgi-1.6.2.tar.gz
cd spawn-fcgi-1.6.2
make all
make install

Start spawn-fcgi:
/usr/local/bin/spawn-fcgi -f /home/code/hgweb.cgi -a -p 8081

Try running hgweb.cgi by issuing: python hgweb.cgi
If you get a message about missing flup, you'll have to download flup and install it:

wget ""
tar -xvf flup-1.0.1.tar.gz
cd flup-1.0.1
python install


Now create a new file under /usr/local/etc/rc.d/ to start spawn-fcgi automatically after a reboot.

Save the same line above under /usr/local/etc/rc.d/

Step 5 - Configure NGinx

Add this to your nginx.conf, replacing with your web server domain name and with the dedicated ip address:

server {

server_name_in_redirect off;

auth_basic "Restricted";
auth_basic_user_file /home/hg/.htpasswd;

gzip on;

location / {

root /home/hg/;
index index.php index.html index.htm;

fastcgi_param SCRIPT_FILENAME /home/hg/$fastcgi_script_name;
include /etc/nginx/fastcgi_top.conf;
fastcgi_param DOCUMENT_ROOT /home/hg/;
include /etc/nginx/fastcgi_bottom.conf;

fastcgi_param QUERY_STRING $query_string;
fastcgi_param REQUEST_METHOD $request_method;
fastcgi_param CONTENT_TYPE $content_type;
fastcgi_param CONTENT_LENGTH $content_length;


Note that we are password protecting the repository by using an .htpasswd file. You can generate one using publicly available htpasswd generators like this one.

Tell NGinx to reload its configuration file:
kill -HUP `cat /usr/local/nginx/logs/`

If all goes well, you should be able to point your browser to and see a list of Mercurial repositories.

Mike Peters, 10-29-2009
While you can force your developers to always go through Mercurial when uploading changes, from time to time, engineers may connect to the server directly via FTP/SSH and update files.

If the server is a client website, chances are the client's engineers and graphic designers will upload changes directly to the server via FTP.

When this happens, we'd like to ensure the new files are stored in Mercurial, just as if someone uploaded a new revision. This way, nothing gets overwritten and you always have a history of all changes.

The way to do this automatically, is to install a cronjob that wakes up every 30 minutes and commits any new changes automatically.

Add this line to your cronjob:
# Commit local file changes, every 30 minutes
*/30 * * * * /home/

Contents of
cd /home/myfolder/
/usr/local/bin/hg add
/usr/local/bin/hg commit -u "root" -m "Local File Changes"

Update with your folder names and you'd be all set. Now even when files are updated outside of Mercurial, they will be picked up and stored so that nothing ever gets lost.

Dawn Rossi, 10-29-2009
The script below will install Mercurial HG, hgweb.cgi, Python flup and hg config files. Just enter your repository name and full path under repName,repFolder and run this script.

### Update this section with the folder and name of your repository
repName = "My Stuff"
repFolder = "/home/mystuff"

# Install Mercurial
cd /usr/ports/devel/mercurial
make all
make install

# Install spawn-fgi
cd /usr/home
mkdir temp
cd temp
wget ""
tar -xvf spawn-fcgi-1.6.2.tar.gz
cd spawn-fcgi-1.6.2
make all
make install

# Install Python Flup
cd /usr/home/temp
wget ""
tar -xvf flup-1.0.1.tar.gz
cd flup-1.0.1
python install

# Install hgweb.cgi
mkdir /home/hg
cd /home/hg
echo "#\!/usr/bin/env python" >> hgweb.cgi
echo "" >> hgweb.cgi
echo "import cgitb" >> hgweb.cgi
echo "from mercurial.hgweb.hgwebdir_mod import hgwebdir" >> hgweb.cgi
echo "from mercurial.hgweb.request import wsgiapplication" >> hgweb.cgi
echo "from flup.server.fcgi import WSGIServer" >> hgweb.cgi
echo "" >> hgweb.cgi
echo "cgitb.enable()" >> hgweb.cgi
echo "" >> hgweb.cgi
echo "def make_web_app():" >> hgweb.cgi
echo " return hgwebdir('/home/hg/hgweb.config')" >> hgweb.cgi
echo "" >> hgweb.cgi
echo "WSGIServer(wsgiapplication(make_web_app)).run()" >> hgweb.cgi
chmod a+x hgweb.cgi

echo "[ui]" >> hgweb.config
echo "username = root" >> hgweb.config
echo "editor = vim" >> hgweb.config
echo "" >> hgweb.config
echo "[hooks]" >> hgweb.config
echo "changegroup = hg update >&2" >> hgweb.config
echo "" >> hgweb.config
echo "[web]" >> hgweb.config
echo "baseurl =/." >> hgweb.config
echo "style= gitweb" >> hgweb.config
echo "push_ssl = false" >> hgweb.config
echo "allow_push = *" >> hgweb.config
echo "" >> hgweb.config
echo "[paths]" >> hgweb.config
echo "$repName = $repFolder" >> hgweb.config

mkdir /etc/mercurial
echo "[web]" >> /etc/mercurial/hgrc
echo "style= gitweb" >> /etc/mercurial/hgrc

# Start spawn-fcgi
/usr/local/bin/spawn-fcgi -f /home/hg/hgweb.cgi -a -p 8081
echo "/usr/local/bin/spawn-fcgi -f /home/hg/hgweb.cgi -a -p 8081" >> /usr/local/etc/rc.d/

# Install cronjob
echo "# Commit local file changes, every 30 minutes" >> /var/cron/tabs/root
echo "*/30 * * * * /home/hg/" >> /var/cron/tabs/root

# Install update file and run it
echo "cd '$repFolder'" >> /home/hg/
echo "/usr/local/bin/hg add" >> /home/hg/
echo "/usr/local/bin/hg commit -u 'root' -m 'Local file changes'" >> /home/hg/
chmod a+x

Mike Peters, 12-05-2009

Make sure you install the Forbid_2head hook on your live repository, or you'll have major issues merging changes locally.

falko, 10-25-2010
>Start spawn-fcgi:
>/usr/local/bin/spawn-fcgi -f /home/code/hgweb.cgi -a -p 8081

I get the following error
spawn-fcgi: child exited with: 2

chmod +x /home/code/hgweb.cgi

alecs, 11-22-2010
Especially cool lines :

include /etc/nginx/fastcgi_top.conf;

fastcgi_param DOCUMENT_ROOT /home/hg/;

include /etc/nginx/fastcgi_bottom.conf;
Enjoyed this post?

Subscribe Now to receive new posts via Email as soon as they come out.

Post your comments

Note: No link spamming! If your message contains link/s, it will NOT be published on the site before manually approved by one of our moderators.

About Us  |  Contact us  |  Privacy Policy  |  Terms & Conditions