As you probably noticed I have been messing around with mercurial and saw 502, 404, 403, etc. errors everywhere on hg.x64architecture.com. It took me a while to figure out how to setup mercurial and a lot of tutorials were outdated and they were for fast-cgi, cgi, proxying, etc. which are slower then uWSGI so I wanted to use uWSGI, I figured i’d make a tutorial to help someone out.

I’m using Ubuntu 12.04 as my Linux Distribution.

First off we have to fetch the required packages:

$ sudo apt-get install python-software-properties     (Optional)
$ sudo add-apt-repository ppa:kurtcancemi/nginx       (Optional)
$ sudo apt-get update
$ sudo apt-get install mercurial python-pygments nginx nginx-common nginx-full uwsgi uwsgi-plugin-python apache2-utils

You can optionally make a hg user and group:

$ sudo /usr/sbin/groupadd hg
$ sudo /usr/sbin/useradd -g hg -s /bin/false hg
$ sudo chown hg:hg /var/hg
$ sudo /usr/sbin/usermod -G hg www-data

Create a directory for the hgweb configuration file. Change the path to whatever you would like.

$ sudo mkdir -p /var/hg

The mercurial package ships with a WSGI file which we will use.

$ sudo cp /usr/share/doc/mercurial/examples/hgweb.wsgi /var/hg/

Edit hgweb.wsgi and set the path of the hgweb configuration file. You could apply this patch if you want by saving it as hgweb.patch and entering $ patch -p1 < hgweb.patch

--- hgweb.wsgi 2013-05-27 01:36:28.835575809 -0400
+++ hgweb.wsgi 2013-05-27 01:37:49.023575136 -0400
@@ -2,7 +2,7 @@
 # See http://mercurial.selenic.com/wiki/modwsgi for more information

 # Path to repo or hgweb config to serve (see 'hg help hgweb')
-config = "/path/to/repo/or/config"
+config = "/var/hg/hgweb.config"

Uncomment and adjust if Mercurial is not installed system-wide (consult “installed modules” path from ‘hg debuginstall’): Change the configuration to your needs:

/var/hg/hgweb.config

[web]
; allow push
allow_push = *
; Base url
baseurl = /
; makes it easier to serve static assests via nginx instead of python
staticurl = /static
; allow archive download
allow_archive = gz bz2 zip

[paths]
; the path to your mercurial repository
repo = /var/hg/YOURREPO
; repo1 = /var/hg/YOURREPO

[extensions]
; pretty colors (optional)
hgext.highlight =

Create a uwsgi application configuration file.

/etc/uwsgi/apps-available/hgweb.ini

[uwsgi]
processes = 2
socket = unix:/run/hgweb.sock
chdir = /var/hg
wsgi-file = hgweb.wsgi
uid = hg
gid = hg

Enable the uwsgi hg application.

$ sudo ln -s /etc/uwsgi/apps-available/hgweb.ini /etc/uwsgi/apps-enabled/`

Start uWSGI.

$ sudo service uwsgi restart

Now we have to configure a virtual host for Nginx.

/etc/nginx/sites-available/hgweb

server {
    # server name
    server_name hg.example.com;

    # logs(optional)
    access_log /var/hg/log/access.log;
    error_log /var/hg/log/error.log;

    location / {
        limit_except GET HEAD {
      auth_basic                  "Mercurial Repository";
      auth_basic_user_file        /var/hg/mercurial_users;
      }
      include     uwsgi_params;
      uwsgi_param REMOTE_PORT     $remote_port;
      uwsgi_param SERVER_PORT     $server_port;
      uwsgi_param SERVER_PROTOCOL $server_protocol;
      uwsgi_param UWSGI_SCHEME    $scheme;
      uwsgi_param SCRIPT_NAME     /;
      uwsgi_param AUTH_USER       $remote_user;
      uwsgi_param REMOTE_USER     $remote_user;
      uwsgi_pass  hg;
    }

    # serve static assests through nginx(faster) and not python.
    location /static {
        alias /usr/share/mercurial/templates/static;
    }
}
upstream hg {
  server unix:/run/uwsgi/app/hgweb/socket;
}

Enable the Nginx virtual host.

$ sudo ln -s /etc/nginx/sites-available/hgweb /etc/nginx/sites-enabled/

Generate user and password for pushing to the repo

$ sudo htpasswd -c /var/hg/mercurial_users YOURUSERNAME

Check for errors in /etc/nginx/sites-available/hgweb:

$ sudo service nginx configtest

If there are no errors then reload Nginx:

$ sudo service nginx reload