Differences between revisions 15 and 201 (spanning 186 versions)
Revision 15 as of 2006-08-17 14:05:03
Size: 6510
Comment: change hg.cgi to hgwebdir.cgi, acording to the previous example
Revision 201 as of 2017-01-30 09:29:36
Size: 49337
Comment: interwiki links don't like dots
Deletions are marked like this. Additions are marked like this.
Line 1: Line 1:
[[TableOfContents]]
(this page ought to be merged with ServerInstall)

== Publishing Mercurial repositories ==

The easiest way to share changes with other people using Mercurial is to publish them on the Web. Mercurial lets people pull changes using HTTP.

There are four (!) ways to publish a repository over HTTP, of which the two below are most worth considering:

 * Use the `hgweb.cgi` CGI script. This is a simple way to quickly publish a single repository.
 * Use the `hgwebdir.cgi` CGI script. This lets you publish multiple repositories easily, but initial setup can be a bit of work.
#pragma section-numbers 2
= Publishing Mercurial Repositories =
This document focuses on public publication of repositories over the Internet, although private/internal sharing of repositories is mentioned below.

<<TableOfContents(3)>>

== Quick recommendations ==
The easiest way to share changes with other people using Mercurial is to publish them on the Web. The recommended method for self-publishing repositories over HTTP is to use the [[#hgweb|hgweb]] scripts with a dedicated Web server such as [[#ConfiguringApache|Apache]] or [[HgWebInIisOnWindows|IIS]].
Line 15: Line 12:
 * Use the {{{hg serve}}} command. This is a multithreaded server since version 0.9. It is not recommended except for temporary situations where you need to publish a repository for a few minutes, for example to pull changes from a laptop.
 * Make the plain repository available. This uses a much slower, less reliable protocol, called `old-http`. We won't cover it here.

== Publishing a single repository ==

The `hgweb.cgi` CGI script is simple to use. You will find it in the root of your Mercurial tree. Copy it to a directory that your web server will handle CGI scripts in, rename it to `index.cgi` if you want, then edit its contents, and you're done.

While you could use this mechanism to publish multiple repositories, it requires a little work to configure each copy of the script to have slightly different paths.

== Publishing multiple repositories ==

The `hgwebdir.cgi` CGI script takes some work to initially set up, but once it's working, it lets you publish new repositories easily and cheaply. Its advantage is that to publish a repository, you simply place a clone in a particular directory, then add one line to a config file to tell the CGI script that it is allowed to publish that repository.

I will describe the setup that BryanOSullivan (me) and ThomasAH use. To mimic our configurations, you will need the following:

 * Control over the web server you use.
 * Use the `hg serve` command. This is hgweb, but running within Mercurial's [[hgserve|built-in Web server]]. It is not really recommended except for temporary situations where you need to publish a repository for a few minutes, for example to pull changes from a laptop.

 * Make the plain repository available. This uses a much slower 'serverless' protocol called `static-http`. We won't cover it here, see [[StaticHTTP]] instead.

The table in the next section gives a comprehensive overview of the different repository publishing options.

== Choosing a publishing method ==
There are a variety of different ways to publish your Mercurial repositories. Some are more powerful than others but may require more effort to set up and administer.

For private or restricted-access repositories, aside from the solutions explicitly marked as "private/internal" in the table below, authentication measures (certificates, logins) can be applied to many of the "public" solutions in order to restrict access. See also AuthorizingUsers.

{i} Note that starting with version 1.6 of Mercurial, the `hgwebdir.cgi` script no longer exists, and its functionality has been merged into the `hgweb.cgi` script which in most cases can be used with the same configuration.

{i} Python has an [[http://bugs.python.org/issue13703|issue]] with hash collisions that potentially can allow denial of service when exposed to untrusted input. It is thus recommended to use Python 2.7.3 or higher (or 2.6.x, x>=8) and set the environment variable `PYTHONHASHSEED=random` when hgweb or other applications are exposed to the internet.
|| ||'''Solution''' ||'''Mechanism''' ||'''Push?''' ||'''Browsable''' ||'''Advantages''' ||'''Disadvantages''' ||
||<#cccccc style="&quot;text-align:center; &quot; " |13>'''Web-based''' ||[[MercurialHosting|third-party hosting]] ||<style="&quot;text-align:center; &quot;" |13>HTTP/HTTPS ||yes ||yes ||minimal setup ||not locally administered, may have fees ||
||[[#hgweb|hgweb]] ||off by default ||yes ||can use existing web server (CGI, WSGI, [[http://www.aventinesolutions.nl/mediawiki/index.php/Quick_Tip:_Getting_Started_with_Mercurial#hgwebdir.py|mod_python]], [[HgWebInIisOnWindows|IIS]]), including authentication ||web server config can be hard to debug ||
||[[hgserve|hg serve]] ||off by default ||yes ||simple and built-in ||push has no authentication, so can only be used on trusted internal networks ||
||[[HgServeNginx|hg serve behind a proxy (Nginx)]] [[HgServeNginxWindows|(Windows setup)]] ||yes ||yes ||multiple repos, permits authentication, no CGI ||requires proxy (Nginx, HAProxy) ||
||[[Deveo]] ||yes ||yes ||projects that can contain mercurial, git or svn repos, permits authentication, permissions system, code-review and commenting ||not open source ||
||[[Kallithea]] ||yes ||yes ||supports both Mercurial and Git, permissions system, code-review, add/edit files from web interface, full text search, code statistics, users actions journal, easy templating, server-side forking and repository creation, API, open source ||requires more resources, longer setup than hg-web ||
||RhodeCode ||yes ||yes ||supports Mercurial, GIT and SVN, easy to use installer, advanced permissions system, code-review (chat & comments), pull-requests, add/edit/delete files from web interface, advanced full text search, auditing journal, unlimited nested groups, API, open-source community edition ||requires more resources, longer setup than hg-web ||
||[[https://github.com/phacility/phabricator|Phabricator]] ||yes || yes||many features||...||
||[[http://www.fogcreek.com/kiln/|Kiln for Your Server]] ||yes ||yes ||easy setup, integrated code review support, commercial support, permissions system, full text search, server-side forking and repository creation ||server is Windows-only, not open source ||
||[[SCM-Manager]] ||yes ||yes ||permissions system, server side repository creation, zero-configuration startup, open source ||depends on Java ||
||HgLab ||yes ||yes ||easy setup, multiple repositories support, authentication and authorization, Active Directory integration ||server is Windows-only, not open source ||
||[[SharedSSH|hgadmin]] ||yes ||yes ||ssh access included ||requires hgweb and ssh server ||
||[[StaticHTTP|static HTTP]] ||no ||no ||does not require hg or CGI support on the server ||very slow ||
||<#999999 style="&quot;text-align:center; &quot; " |3>'''Private/internal''' ||ssh ||SSH ||yes ||no ||no additional setup ||requires Unix server, per-user accounts and repositories ||
||[[SharedSSH|shared SSH]] ||SSH (but with shared accounts) ||yes ||no ||easy key management, fine-grained permissions ||requires Unix server, not built in ||
||shared disk ||NFS/Samba etc. ||yes ||no ||can use existing setup ||generally restricted to intranets, '''not generally recommended''' due to general issues with network filesystem reliability ||
||virtual ||[[https://forge.camijo.de/projects/dvcsauth|dvcsauth]] ||HTTPS/SSH ||yes ||yes ||virtual users (database), public and restricted access, also provides git access and access to webspace ||requires Unix server, python and twisted, requires apache for https, requires own port for ssh access (can be 22) ||




(!) See also [[#SeeAlso|various other guides]] about configuring Mercurial's Web interface using various technologies.

<<Anchor(hgweb)>>

== hgweb ==
<<Anchor(introduction)>>

=== hgweb - introduction and prerequisites ===
In this document we assume that repositories reside in the `/home/user/hg` directory. For example, a repository called `myproject` would reside in `/home/user/hg/myproject`. This is merely a convention used to give the reader an additional way of understanding the examples.

==== Python and Mercurial ====
First of all, you need to have a Python installation that can access the `mercurial` package. Verify this by running `python` and typing the following:

{{{#!python numbers=disable
import mercurial
}}}
If an `ImportError` appears, you will need to install the Mercurial libraries for Python on your platform. This problem mostly affects Windows where tools like TortoiseHg provide Mercurial (and have their own Python installation), but where a standard Python installation does not have access to these already-installed libraries. See the [[Download|downloads page]] for installers and archives providing Mercurial libraries for existing Python installations.

==== Web servers and domains ====
To implement the mechanisms described in this document, you will need the following:

 * Some control over the behaviour of the Web server you use.
Line 33: Line 72:
== Miscellaneous details ==

=== Is virtual hosting necessary? ===

Using virtual hosting is entirely optional, and not worth it in the majority of cases. It simply makes URLs a little tidier.

For example, I can serve repositories at http://hg.serpentine.com/mercurial/hg instead of http://www.serpentine.com/hg/hgwebdir.cgi/mercurial/hg.

To do this, I simply have {{{hg.serpentine.com}}} CNAMEd to my web server.

=== Setting up the CGI script ===

Choose a directory you want to publish from. On my systems, I use {{{/home/bos/hg/share}}}, which you will see below.

Copy `hgwebdir.cgi` in there. Read and edit it, then create a file called `hgweb.config`.

=== Setting up the hgweb.config file ===

Here are the contents of my `hgweb.config` file:
{{{#!wiki tip
With control over DNS, such as that provided with various Web hosting service control panels, you should be able to set up a subdomain; this makes the URL of your repositories a little tidier, so that `http://hg.example.com/myproject` can be used instead of `http://www.example.com/hgweb.cgi/myproject`, for example.

Such an approach, known as virtual hosting, is entirely optional. To implement it for the fictional `example.com`, a CNAME record for `hg.example.com` would be defined for the same address as that already used by the Web server.
}}}
To setup hgweb to publish a single repository or multiple repositories, perform the following steps:

 1. Find the necessary script in the root of your Mercurial source tree.
 1. Copy it to a directory where your Web server can access it. This will be illustrated below using `/home/user/webdir` as this directory.

 1. Edit its contents. In particular, you will need to edit it so that it is reading the correct config file.
 1. Make sure the Web server (such as [[#ConfiguringApache|Apache]]) is configured and can execute the script.

These steps are now described in more detail.

=== Getting the hgweb script ===
The hgweb script is provided in more than one form:

 * `hgweb.cgi` is a script for deployment using CGI and is provided in the top-level directory of the source distribution of Mercurial.

 * `hgweb.wsgi` is a script for deployment using WSGI and is provided in the `contrib` directory in the distribution.

(!) Much better performance can be achieved by using WSGI instead of CGI.

If you should find yourself without such a script, perhaps because you are using a binary installation of Mercurial, you can do one of the following:

 * Download a [[Download#Source_packages|source package]] corresponding to the version of Mercurial you are using, unpack it, and extract the script of your choice. This can be useful if you have other reasons for looking at the source or the [[Theming|templates]].

 * Browse or clone a repository containing the Mercurial sources (see the [[DeveloperInfo|developer information]] for details), and download or extract the appropriate version of the script directly from that repository.

 * If you're using a recent Mercurial release, just download the latest version of [[Source:hgweb.cgi|hgweb.cgi]] or [[Source:contrib/hgweb.wsgi|hgweb.wsgi]] from the official repository.

{i} If your Mercurial installation is provided by a package which does not include the `hgweb.cgi` or `hgweb.wsgi` files, please consider filing a bug report or feature request with the package maintainer.

=== Customizing the hgweb script ===
The most basic configuration is done by editing `hgweb.cgi` or `hgweb.wsgi`. Whichever file is chosen must be edited before it can be used, especially to define which configuration file is to be used to find the repositories, or to indicate which single repository is to be served.

==== Mercurial location ====
If Mercurial is not installed system-wide, uncomment and edit the Python path in `hgweb.cgi` or `hgweb.wsgi` as indicated:

{{{#!python numbers=disable
# Uncomment and adjust if Mercurial is not installed system-wide:
import sys; sys.path.insert(0, "/home/user/mercurial")
}}}
The above example assumes that Mercurial has been installed locally in the `/home/user/mercurial` directory.

{i} It is recommended to use the `hgweb.cgi` or `hgweb.wsgi` script originating from the version of Mercurial that is installed on your system. If you are using Debian and installed the Mercurial package, you can find the `hgweb.cgi` script in `/usr/share/doc/mercurial-common/examples/` or `/usr/share/doc/mercurial/examples/` (depending on your version).

/!\ If you choose to create a symbolic link to the `hgweb.cgi` script in your Mercurial source tree instead of copying it, you might run into Python library problems as it might try to use the libraries from the source tree instead of the ones already installed on your system.

==== Configuration file location ====
hgweb reads global and repository-specific configuration files like Mercurial does - see [[Topic:config|hg help config]]. Note that it will read the `.hgrc` of the user the web server runs as.

It is also possible to specify a configuration file that is specific to hgweb. It is referred to as `hgweb.config` in this document (although another name can be chosen), and it needs to be created and referenced in the `hgweb.cgi` or `hgweb.wsgi` script. This can be done by changing the script as follows:

{{{#!python numbers=disable
# Path to repo or hgweb config to serve (see 'hg help hgweb')
config = "hgweb.config"
}}}
Here, a file called `hgweb.config` will be read from the same directory as the script. You may instead choose to place the file in another directory, and to avoid confusion an absolute path is recommended. For example:

{{{#!python numbers=disable
config = "/home/user/hgweb.config"
}}}
Even if you only want to publish a single repository, but expect the repository name to appear as part of the URL (perhaps because you intend to publish more repositories later and will need to distinguish between them), specifying a configuration file in the script is the most appropriate solution. You may then specify the details of the single repository in the configuration file as described below.

<<Anchor(Setting_up_the_hgweb.config_file)>><<Anchor(multiple)>>

=== Configuration of hgweb ===
==== [paths] ====
The repositories and trees of repositories that are served by `hgweb` can be configured in the `[paths]` section in the configuration file. (See also [[Topic:hgweb|hg help hgweb]].)

For example, create `/home/user/webdir/hgweb.config` like this:
Line 55: Line 148:
mercurial/bos = mercurial/bos
mercurial/hg = mercurial/hg
mercurial/crew = mercurial/crew
mercurial/tah = mercurial/tah
}}}

The duplication above looks a little silly, but it's telling the CGI script which repositories it is allowed to publish.
myproject = /home/user/hg/myproject
otherproject = /home/user/hg/otherproject
}}}
The `paths` setting in this file tells the CGI script which repositories it is allowed to publish and how their published locations map to their actual locations in the filesystem.

 * The keys (on the left) are ''URL'' paths which can incorporate `/` characters - these paths appear as part of the URL used to access a repository

 * The values (on the right) are ''filesystem'' paths which can be relative to the CGI directory - note that it is typically preferable to keep the repositories ''outside'' the CGI directory

The `paths` setting can also contain wildcards. If all your repos are in the `/home/user/hg` directory, use the following to expose repositories within this directory:

{{{
[paths]
/ = /home/user/hg/*
}}}
The `**` wildcard exposes subrepositories (repositories within repositories) whereas `*` merely finds repositories within a directory. However, this behaviour is modified by the `descend` setting as described below.

===== The descend setting =====
The `descend` setting resides in the `[web]` section of the configuration:

{{{
[web]
descend = True
}}}
When set to `True`, the repositories exposed may change in the Web interface as `hgweb` will now descend into the directory hierarchy described by each of the path settings. Where a wildcard of `*` has been used, directories which are not themselves repositories will be navigated, with repositories added to the display as they are found. Where `**` has been used, repositories will also be inspected for subrepositories.

The principal difference between the default behaviour and the "descend" behaviour is that, with `descend` enabled, `hgweb` will look beyond a single directory level to find repositories. It will then present all these repositories in a single list, showing the path to each of them in the directory hierarchy. For example, consider the following directory layout:

{{{
/home/user/hg/active/
  activeproject
    subrepo
  LATEST/
    verynewproject
/home/user/hg/abandoned/
  abandonedproject
  OLD/
    veryoldproject
      subproject
}}}
And consider the following path settings:

{{{
[paths]
/active = /home/user/hg/active/*
/abandoned = /home/user/hg/abandoned/*
/all_active = /home/user/hg/active/**
/all_abandoned = /home/user/hg/abandoned/**
}}}
With descend mode not activated, visiting the given URL paths (making full URLs such as `http://example.com/active`) should display the following repositories:
||'''URL path''' ||'''Repositories''' ||'''Wildcard used''' ||
||`/active` ||`activeproject` ||`*` ||
||`/abandoned` ||`abandonedproject` ||`*` ||
||`/all_active` ||`activeproject`, '''`activeproject/subrepo`''' ||`**` ||
||`/all_abandoned` ||`abandonedproject` ||`**` ||




Here, the subrepository is emphasised.

With descend mode activated, visiting the same paths should display the following repositories:
||'''URL path''' ||'''Repositories''' ||'''Wildcard used''' ||
||`/active` ||`activeproject`, '''`LATEST/verynewproject`''' ||`*` ||
||`/abandoned` ||`abandonedproject`, '''`OLD/veryoldproject`''' ||`*` ||
||`/all_active` ||`activeproject`, `activeproject/subrepo`, '''`LATEST/verynewproject`''' ||`**` ||
||`/all_abandoned` ||`abandonedproject`, '''`OLD/veryoldproject`''', '''`OLD/veryoldproject/subproject`''' ||`**` ||




Here, the newly exposed repositories and subrepositories are emphasised.

===== The collapse setting =====
With descend mode activated, the `collapse` setting gathers together repositories inside their common locations, giving a directory navigation kind of interface.

{{{
[web]
descend = True
collapse = True
}}}
The above example directory layout should look like the following with both `descend` and `collapse` enabled:
||'''URL path''' ||'''Repositories''' ||
||`/active` ||`activeproject`, '''`LATEST`''' ||
||`/abandoned` ||`abandonedproject`, '''`OLD`''' ||
||`/all_active` ||`activeproject`, `activeproject/subrepo`, '''`LATEST`''' ||
||`/all_abandoned` ||`abandonedproject`, '''`OLD`''' ||




Here, the directory names have been emphasised. These can be navigated in the interface to reach the following URL paths, showing the expected listings of repositories:
||'''URL path''' ||'''Repositories''' ||
||`/active/LATEST` ||`verynewproject` ||
||`/abandoned/OLD` ||`veryoldproject` ||
||`/all_active/LATEST` ||`verynewproject` ||
||`/all_abandoned/OLD` ||`veryoldproject`, `veryoldproject/subproject` ||




In short, the `collapse` setting collapses collections of repositories found in a directory structure into a single entry bearing the name of the common directory leading to them all. If you want a multi-level navigable directory hierarchy showing only the repositories in each directory, this setting should be enabled together with descend mode.

==== [collections] ====
{i} There is no longer any reason to use `collections` - just use `paths` instead.

The above `hgweb.config` file could be rewritten with `collections` as follows:

{{{
[collections]
/home/user/hg = /home/user/hg
}}}
The `collections` setting in this file tells the CGI script where to look for repositories.

 * The keys (on the left) and the values (on the right) are both ''filesystem'' paths

 * The keys should be prefixes of the values and are "subtracted" from the values in order to generate the ''URL'' paths to each repository

Consider two repository collections given in the `hgweb.config` file:

{{{
[collections]
/home/user/private = /home/user/private
/home/user/official = /home/user/official
}}}
Where both `/home/user/private` and `/home/user/official` contain repositories using the same names (`myproject` and `otherproject`), a combined list will then be shown by the Web interface containing two entries for each of `someproject` and `otherproject`: one from the `private` collection and one from the `official` collection. This may be confusing to the end-user, so we may modify the configuration file as follows:

{{{
[collections]
/home/user = /home/user
}}}
This will now produce entries for `private/someproject`, `private/otherproject`, `official/someproject` and `official/otherproject`. Unfortunately, it will also find other repositories outside the `private` and `official` directories. It is therefore recommended that repositories are located in suitably organised directory hierarchies if exported in this way.

<<Anchor(single)>>

==== Publishing a single repository ====
It is possible to configure hgweb to publish a single repostiory - like `hg serve` does by default. This emulates the behaviour of the old `hgweb.cgi` found in older versions of Mercurial.

Edit the call to `hgweb()` in `hgweb.cgi` or `hgweb.wsgi` to specify the path to the repository instead of a configuration file. You can also specify a descriptive name for the repository. For example:

{{{#!python numbers=disable
application = hgweb("/home/user/hg/myproject", "My Project")
}}}
==== Public and Private Repositories ====
If you want to serve both public and private repositories, you'll need to put them under different web URIs, like `http://hg.example.com/hg-public` and `http://hg.example.com/hg-private`. You will also need two different configuration files for `hgweb.cgi` or `hgweb.wsgi`, which in turn means two different copies of the script itself.

The actual public/private distinction will mostly be enforced by your web server configuration. Since the two repositories (or collections of repositories) have different paths, you can require different levels of authentication for each path.

<<Anchor(ConfiguringLighttpd)>>

=== Configuring Lighttpd ===
==== Configuring CGI Lighttpd ====
Put `hgweb.cgi` and `hgweb.config` to root of repositories dir (`/srv/hg` in example). With URL rewriting `hgweb.config` look like:

{{{
[paths]
/ = /srv/hg/*

[web]
style = gitweb
encoding = "UTF-8"

baseurl = /hg

deny_push = *
allow_archive = bz2, gz, zip
}}}
`/etc/lighttpd/conf-available/92-mercurial.conf` (note that `url.rewrite` work inside `$HTTP["url"]` with Lighttpd >= 1.4.34):

{{{
$HTTP["url"] =~ "^/hg(/|$)" {
  alias.url = ( "/hg/" => "/srv/hg/" )
  cgi.assign = ( "/hgweb.cgi" => "" )
  url.rewrite-once = ("^/hg/?(.*)$" => "/hg/hgweb.cgi/$1" )
}
}}}
Under Debian enable config:

{{{
sudo lighttpd-enable-mod mercurial
}}}
and restart server:

{{{
sudo service lighttpd restart
}}}
and visit http://localhost/hg/!

==== Configuring FastCGI Lighttpd ====
Install packages:

{{{
sudo apt-get install lighttpd spawn-fcgi python-flup mercurial
}}}
Fill Lighttpd config `/srv/hg/lighttpd.conf`:

{{{
  server.pid-file = "/srv/hg/lighttpd.pid"
  server.document-root = "/srv/hg/"
  server.port = 8888
  server.username = "www"

  server.modules += ( "mod_rewrite" )
  url.rewrite-once = (
    "^/?$" => "/hgweb.fcgi",
  )

  server.modules += ( "mod_fastcgi" )
  fastcgi.server += (
    "hgweb.fcgi" => ( (
       "bin-path" => "/srv/hg/hgweb.fcgi",
       "socket" => "/srv/hg/hgweb.fcgi.sock",
       "min-procs" => 1,
       "max-procs" => 2
    ) )
  )
}}}
Put to `/srv/hg/` [[Source:contrib/hgweb.fcgi|hgweb.fcgi]] script. Fix path to `hgweb.config`:

{{{
  config = "/srv/hg/hgweb.config"

  from mercurial import demandimport; demandimport.enable()
  from mercurial.hgweb import hgweb
  from flup.server.fcgi import WSGIServer
  application = hgweb(config)
  WSGIServer(application).run()
}}}
Fill hgweb.config:

{{{
  [collections]
  /srv/hg/ = /srv/hg/

  [web]
  encoding = "UTF-8"
  style = gitweb

  allow_push = *
  push_ssl = False
}}}
Put repositories to `/srv/hg/*`:

{{{
  $ hg clone -U ~/devel/proj1 /srv/hg/proj1
  $ hg clone -U ~/devel/proj2 /srv/hg/proj2
}}}
Start Lighttpd:

{{{
lighttpd -d -f /srv/hg/lighttpd.conf
}}}
Clone repository:

{{{
  $ hg clone http://$USER:$PASS@$HOST:$PORT/hg/hgweb.fcgi/proj1
}}}
==== Configuring LDAP auth with Lighttpd ====
Add to your Lighttpd config:

{{{
  server.modules += ( "mod_auth" )
  auth.backend = "ldap"
  auth.backend.ldap.hostname = "ldap.evil.com"
  auth.backend.ldap.base-dn = "ou=XXX,o=YYY"
  auth.backend.ldap.filter = "(uid=$)"
  auth.require = (
      "" => (
          "method" => "basic",
          "realm" => "Enter your LDAP auth",
          "require" => "valid-user",
      ),
  )
}}}
Check for user name that allowed to push by `/srv/hg/proj/.hg/access.bash`:

{{{#!text
#!/bin/bash
users='LDAP1 LDAP2 LDAP3'

# Allow non-http connections (ssh).
[[ -z "$HTTP_AUTHORIZATION" ]] && exit 0

for user in $users; do
  [[ $user = $REMOTE_USER ]] && exit 0
done

echo "Your name is '$REMOTE_USER'"
echo "You are not in a list of allowed users:"
echo $users | fmt -w 60 | sed 's=^= ='
exit 1
}}}
Register check script at `/srv/hg/proj/.hg/hgrc`:

{{{
  [hooks]
  prechangegroup.access = /srv/hg/proj/.hg/access.bash
}}}
<<Anchor(ConfiguringApache)>>
Line 64: Line 449:

Here's the Apache config I use. Description below.
There are many ways of configuring Apache to run scripts, and a few of the possibilities are provided below. Where the main configuration files are mentioned, you should use the appropriate conventions for your system in defining such files in the `conf.d` and/or `sites-available` directories.

{i} To ensure that a script is executable by the Web server, the following command is typically used:

{{{
chmod u+x hgweb.cgi
}}}
{i} The preferred mechanism for persuading Apache to use updated configuration information can vary from platform to platform and from distribution to distribution. Please consult your distribution's documentation, if appropriate, or the more general Apache documentation (for example, the [[http://httpd.apache.org/docs/2.2/programs/apachectl.html|apachectl documentation]]) for details.

{{{#!wiki caution
'''Note''' that only the `hgweb.cgi` or `hgweb.wsgi` script should be "published" by the Web server.

This script is perfectly capable of serving repositories once it knows where these repositories are. You '''do not''' need (or even want) the actual repositories to be published by the Web server itself: the CGI script will, when run, read from the repositories and output the necessary content itself.

In short, '''do not''' put the actual repositories under some kind of "document root" or "public HTML" directory - this is the [[StaticHTTP|static HTTP]] approach and is completely different from what is being documented here. Here, we are using a ''script'' to serve up repositories, not the Web server itself.
}}}
<<Anchor(script)>>

==== Using httpd.conf ====
''This example requires access to the main configuration files.''

===== CGI =====
The easiest way to serve the `hgweb.cgi` script is to use a `ScriptAlias` directive:

{{{
ScriptAlias /hg "/home/user/webdir/hgweb.cgi"
}}}
This actually exports the repository browser at the URL path `/hg` (for example, `http://www.example.com/hg`) and doesn't expose the name of the script at all.

{i} See the [[http://httpd.apache.org/docs/2.2/mod/mod_alias.html#scriptalias|Apache httpd documentation]] for `ScriptAlias`.

===== WSGI =====
The equivalent way to serve the `hgweb.wsgi` script is the `WSGIScriptAlias` directive:

{{{
WSGIScriptAlias /hg "/home/user/webdir/hgweb.wsgi"
}}}
Again, this actually exports the repository browser at the URL path `/hg` (for example, `http://www.example.com/hg`) and doesn't expose the name of the script at all.

{i} See the [[http://code.google.com/p/modwsgi/wiki/QuickConfigurationGuide|Quick Configuration Guide]] for mod_wsgi for more information.

<<Anchor(htaccess)>>

==== Using an .htaccess file ====
''This example can be used with pre-configured CGI directories.''

If you may not change the main Apache configuration files, you may still be able to use `.htaccess` file to make URLs nicer, as suggested in the previous section. Here is an `.htaccess` file which sits in the published `webdir` directory on the Web server and redirects `http://www.example.com/hg/*` URLs to the `hgweb.cgi` script inside that folder. As a result it would no longer be not necessary to mention the CGI script name in URLs: one could use `http://www.example.com/hg/myproject` instead of `http://www.example.com/hg/hgweb.cgi/myproject`.

{{{
# Taken from http://www.pmwiki.org/wiki/Cookbook/CleanUrls#samedir
# Used at http://ggap.sf.net/hg/
Options +ExecCGI
RewriteEngine On
#write base depending on where the base url lives
RewriteBase /hg
RewriteRule ^$ hgweb.cgi [L]
# Send requests for files that exist to those files.
RewriteCond %{REQUEST_FILENAME} !-f
# Send requests for directories that exist to those directories.
RewriteCond %{REQUEST_FILENAME} !-d
# Send requests to hgweb.cgi, appending the rest of url.
RewriteRule (.*) hgweb.cgi/$1 [QSA,L]
}}}
A corresponding change in `hgweb.config` can be made to make sure that the nicer urls are used in the HTML produced by the CGI and WSGI scripts:

{{{
[web]
baseurl = /hg
}}}
Where the scripts are made to appear at the server root (for example, `http://hg.example.com/`), leave the `baseurl` setting blank:

{{{
[web]
baseurl =
}}}
Generally, the value specified should not end with a `/` character.

==== Adding authentication ====
''The following configurations requires access to the main configuration files. They can be combined with the [[#script|script]] or [[#directory|directory]] declarations to impose authentication and access restrictions on repositories.''

''To use these configurations with the [[#htaccess|pre-configured CGI directories]], the `Location` directive start and end tags can be omitted, leaving the bare authentication-related directives.''

===== Restrict to known users =====
This configuration restricts access to a known set of users as defined in the `/home/user/hg/hgusers` password file:

{{{
<Location /hg>
    AuthType Basic
    AuthName "Mercurial repositories"
    AuthUserFile /home/user/hg/hgusers
    Require valid-user
</Location>
}}}
<!> Since the `AuthType` directive is set to `Basic`, passwords are communicated as plain text, and it is therefore recommended that this only be used with a server configured for HTTPS. See the [[http://httpd.apache.org/docs/2.2/ssl/|Apache SSL documentation]] for more information.

{i} To set up the password file, use the `htpasswd` tool as described in the relevant [[http://httpd.apache.org/docs/2.2/programs/htpasswd.html|Apache documentation]].

This alternative configuration employs digest authentication and thus offers an alternative to basic authentication and HTTPS:

{{{
<Location /hg>
    AuthType Digest
    AuthName "Mercurial repositories"
    AuthDigestProvider file
    AuthUserFile /home/user/hg/hgusers
    Require valid-user
</Location>
}}}
{i} To set up the password file, use the `htdigest` tool as described in the relevant [[http://httpd.apache.org/docs/2.2/programs/htdigest.html|Apache documentation]].

{i} See the [[http://httpd.apache.org/docs/2.2/mod/mod_auth_digest.html|Apache mod_auth_digest documentation]] for more information on digest authentication and its limitations.

<<Anchor(pushing)>>

===== Restrict pushing to known users =====
To exercise finer control and to provide global read-only access to the repositories, but require authentication for pushing, a `LimitExcept` directive can be added. Here are the previous examples with such a directive in use. First with basic authentication:

{{{
<Location /hg>
    AuthType Basic
    AuthName "Mercurial repositories"
    AuthUserFile /home/user/hg/hgusers
    <LimitExcept GET>
        Require valid-user
    </LimitExcept>
</Location>
}}}
And with digest authentication:

{{{
<Location /hg>
    AuthType Digest
    AuthName "Mercurial repositories"
    AuthDigestProvider file
    AuthUserFile /home/user/hg/hgusers
    <LimitExcept GET>
        Require valid-user
    </LimitExcept>
</Location>
}}}
{i} See the [[http://httpd.apache.org/docs/2.2/mod/core.html#limitexcept|Apache documentation]] for `LimitExcept` for more information.

Now consult the instructions on [[#push|allowing the push operation]] in Mercurial to complete this configuration task.

===== Using groups =====
Apache also provides support for user groups through the `AuthGroupFile` directive. Here it is in context:

{{{
    AuthUserFile /home/user/hg/hgusers
    AuthGroupFile /home/user/hg/hggroups
}}}
Instead of a `Require` directive involving users, the following directive can be used in its place. Here it is in context:

{{{
    <LimitExcept GET>
        Require group hobbits
    </LimitExcept>
}}}
Here, the `hobbits` group is defined in the nominated file as described in the relevant [[http://httpd.apache.org/docs/2.2/mod/mod_authz_groupfile.html#authgroupfile|Apache documentation]] for `AuthGroupFile`, connecting users who will authenticate themselves with groups such as `hobbits`.

===== Public and Private Repositories =====
As was mentioned earlier, public versus private is mostly enforced by the web server configuration. In this case, we will assume that we have made two copies of the `hgweb.cgi` script under `/home/user/webdir`. One will be named `hgweb-public.cgi` and the other `hgweb-private.cgi`. These scripts will in turn each load a different configuration file. The public configuration will serve our public repositories, and the private configuration will serve our private repositories.

{{{
ScriptAlias /hg-public /home/user/webdir/hgweb-public.cgi

<Location /hg-public>
    AuthType Basic
    AuthName "Mercurial repositories"
    AuthUserFile /home/user/hg/hgusers

    <LimitExcept GET>
        Require user valid-user
    </LimitExcept>
</Location>

ScriptAlias /hg-private /home/user/webdir/hgweb-private.cgi

<Location /hg-private>
    AuthType Basic
    AuthName "Mercurial repositories"
    AuthUserFile /home/user/hg/hgusers
    Require valid-user
</Location>
}}}
With this configuration, the public repositories are read-only without authentication.

{i} Note that the above configuration is built from details given in previous sections, combining the different activities of publishing, authentication and access control.

==== Using virtual hosts ====
''This example requires access to the main configuration files.''

Here is an example Apache configuration for publishing repositories at `http://hg.example.com/`:

{{{
<VirtualHost *>
  ServerName hg.example.com

  ServerAdmin webmaster@example.com
  CustomLog logs/access_log.example combined
  ErrorLog logs/error_log.example

  ScriptAlias / "/home/user/webdir/hgweb.cgi"
</VirtualHost>
}}}
The `ScriptAlias` directive is taken from the [[#script|script]] example; all other directives support the virtual host `hg.example.com`.

{i} Note that the `CustomLog` and `ErrorLog` directives may need to be changed to refer to files in standard locations such as `/var/log/apache2` or `/var/log/httpd`, depending on how Apache is configured.

Here is a more complicated example using rewrite rules and explicit `Directory` directives. A description follows the example.
Line 69: Line 662:
  ServerName hg.serpentine.com

  ServerAdmin webmaster@serpentine.com
  CustomLog logs/access_log.serpentine combined
  ErrorLog logs/error_log.serpentine
  ServerName hg.example.com

  ServerAdmin webmaster@example.com
  CustomLog logs/access_log.example combined
  ErrorLog logs/error_log.example
Line 76: Line 669:
  RewriteRule (.*) /home/bos/hg/share/hgwebdir.cgi$1

  <Directory "/home/bos/hg/share/">
  RewriteRule (.*) /home/user/webdir/hgweb.cgi/$1

  # Or we can use mod_alias for starting CGI script and making URLs "nice":
  # ScriptAliasMatch ^(.*) /home/user/webdir/hgweb.cgi/$1

  <Directory "/home/user/webdir/">
Line 87: Line 683:

The {{{ServerName}}} directive matches the hostname I configured earlier.

The next section is just administrative cruft.

The rewrite-related directives tell Apache to turn URIs like {{{/mercurial/hg}}} into {{{/home/bos/hg/share/hgwebdir.cgi/mercurial/hg}}}. This causes Apache to fire up the CGI script, giving it the remainder of the URI as an argument.

Finally, the {{{Directory}}} section lets Apache know that we have a CGI script to look at.

=== Using .htaccess file ===

If you may not configure apache, you can use .htaccess file to make urls nicer, like in previous section. Here is an .htaccess file which sits in hg/ directory on webserver and redirects `http://server/hg/*` urls to hg.cgi script inside of that folder, so it is not necessary to use cgi script name in urls, i.e. one can use simple `http://server/hg/repo` instead of `http://server/hg/hg.cgi/repo`.

{{{
# Taken from http://www.pmwiki.org/wiki/Cookbook/CleanUrls#samedir
# Used at http://ggap.sf.net/hg/
Options +ExecCGI
RewriteEngine On
#write base depending on where the base url lives
RewriteBase /hg
RewriteRule ^$ hgwebdir.cgi [L]
# Send requests for files that exist to those files.
RewriteCond %{REQUEST_FILENAME} !-f
# Send requests for directories that exist to those directories.
RewriteCond %{REQUEST_FILENAME} !-d
# Send requests to hgwebdir.cgi, appending the rest of url.
RewriteRule (.*) hgwebdir.cgi/$1 [QSA,L]
}}}
The directives in the above have the following purposes:

 * The `ServerName` directive matches the hostname configured for the domain.

 * The next section (`ServerAdmin` and so on) is just administrative cruft.

 * The rewrite-related directives (`RewriteEngine` and `RewriteRule`) tell Apache to turn URIs ending in `/myproject` into `/home/user/webdir/hgweb.cgi/myproject`. This causes Apache to fire up the CGI script, giving it the remainder of the URI as an argument.

 * Finally, the `Directory` section lets Apache know that we have a CGI script to look at.

{i} See the [[http://httpd.apache.org/docs/2.2/vhosts/|Apache virtual hosts documentation]] for more information.

<<Anchor(push)>>

=== Allowing push ===
Make sure that your repository is writeable by the user running the Apache server (such as `www-data`), and that the repository's `.hg/hgrc` file (or your Web server user's `.hgrc` file, such as `/home/www-data/.hgrc`, or a system-wide `hgrc` file like `/etc/mercurial/hgrc`) contains the allowed users:

{{{
[web]
allow_push = frodo, sam
}}}
This would allow pushing for `frodo` and `sam`. You can allow pushing for everyone with the following:

{{{
[web]
allow_push = *
}}}
By default, pushing is only allowed via HTTPS. To permit HTTP pushing you have to add this to your repository's `.hg/hgrc` file (or your Web server user's `.hgrc` file, such as `/home/www-data/.hgrc`, or a system-wide `hgrc` file like `/etc/mercurial/hgrc`):

{{{
[web]
push_ssl = false
}}}
Now consult the instructions on configuring Apache to [[#pushing|restrict pushing]] in order to set up the authentication/authorisation infrastructure.

==== Defining user credentials ====
To define credentials for the allowed users, use the `htpasswd` tool. For example:

{{{
htpasswd -c /home/user/hg/hgusers frodo
}}}
You will need to enter the desired password for the username `frodo`. Later, you can add more usernames without the `-c` option:

{{{
htpasswd /home/user/hg/hgusers sam
}}}
{i} See the relevant [[http://httpd.apache.org/docs/2.2/programs/htpasswd.html|Apache documentation]] for `htpasswd`.

==== Write permissions on repositories ====
Repositories can only successfully receive pushed changesets if the Web server user has write access to each repository's `.hg` directory and its contents. See the permissions troubleshooting section below for details of errors and remedies related to permissions.

=== Troubleshooting ===
Mercurial is executed on the server by Apache and therefore runs as the Apache user and group. If experiencing flaky behavior, it may be because the CGI script is failing because it does not have enough rights. In that case, you should check the log files, but you can also make some common-sense permissions checks.

==== Problems with trust settings ====
[[Trust|Trust-related messages]] of the form `Not trusting file...` may [[Trust#WebServerLogMessages|appear in the Web server logs]]. Although it is unlikely that such messages would cause a 500 (Internal Server Error) status code, it can be useful to eliminate them in order to troubleshoot other problems.

==== Permissions ====
There are two ways that permissions problems primarily manifest themselves on the server: either you won't see any repositories at all (indicating missing read or execute permissions) or you won't be able to push to the server (indicating missing write permissions), which gives you the error message:

{{{
abort: ‘http://foo/bar’ does not appear to be an hg repository!
}}}
Another common error often related to permissions:

{{{
abort: HTTP Error 500: Internal Server Error
}}}
The best way to solve permissions problems is to grant the required permissions to the Apache group (the `www-data` group on Debian). You should have some familiarity with assigning permissions under Linux/Unix before attempting the following.

Suppose your main user is `john`, your Web server runs as `www-data` and your repositories are in `/home/john/repositories`. Then, execute the following commands to change the group for all files in your repositories on the server and make the files writable to the server process as well as make the home directory readable.

{{{
chown -R john:www-data /home/john/repositories
chmod -R g+rw /home/john/repositories
chmod g+x /home/john/repositories
}}}
For each repository, you will have to make both the repository folder and the `.hg` folder executable as well:

{{{
chmod g+x /home/john/repositories/rep1
chmod g+x /home/john/repositories/rep1/.hg
}}}
If each of your repositories are subdirectories from some main folder which only contains repositories (such as `/var/www/html/hg/repos`, with underlying repositories `/var/www/html/hg/repos/repo1`, `/var/www/html/hg/repos/repo2`, and so on), you may find it easier to remember to script the setting of these permissions. Write the following at the prompt to create a new executable shell script:

{{{
cat <<EOM >permission.sh
chown -R john:www-data repos
chmod -R g+rw repos
chmod g+x repos
chmod g+x repos/*
chmod g+x repos/*/.hg
EOM
sudo chown root:root permission.sh
sudo chmod u+x permission.sh
}}}
These assume your username is `john`, the Apache server's user's group is `www-data`, and the folder containing your repositories is called `repos`. Now you can update permissions for your entire repository by navigating to this containing directory and issuing a single command:

{{{
sudo ./permission.sh
}}}
Before you start crawling through logs to find out why your Mercurial server isn't letting you pull, push, or authenticate, run this command and see if it solves your issue.

It is important to note that the entire repository tree must be accessible by the Web server user (`www-data` in the above examples). For example, the tree `/home/john/source/repos/hg/repo1` requires `john`, `source`, `repos`, and `hg` to be executable by the Web server user.

==== HTTP Error 400: Bad Request ====
A similar problem with pulling through http proxies is discussed [[https://www.mercurial-scm.org/pipermail/mercurial/2010-May/032365.html|here]].

This error may occur when you try to push/pull changes to/from the web server. Mercurial will send out a long (~7k bytes) request line that the server refuses to process.

In Apache 2.2, the [[http://httpd.apache.org/docs/current/mod/core.html#limitrequestline|LimitRequestLine]] defaults to 8190 (bytes). To circumvent the problem, try increasing the request line limit e.g to 16380.

==== Mercurial in verbose mode ====
{{{#!wiki note
This problem (reported as a [[Issue:issue1250|bug]] against Mercurial) might potentially be solved in future Mercurial versions.
}}}
On certain occasions, observed when attempting to clone a repository via `hgweb.cgi`, the Web server will produce a 500 (Internal Server Error) status code, aborting the operation. This is due to extra output being sent by Mercurial to the Web server as part of an HTTP response.

If your repository's `.hg/hgrc` file (or your Web server user's `.hgrc` file, such as `/home/www-data/.hgrc`, or a system-wide `hgrc` file like `/etc/mercurial/hgrc`) includes the following setting, you should consider removing or disabling it (or moving it to your normal user's `.hgrc` file, if appropriate):

{{{
verbose = true
}}}
==== Using an unsupported version of Python ====
When the Web server produces a 500 (Internal Server Error) status code, the error log may contain messages resembling the following:

{{{
/var/lib/python-support/python2.6/mercurial/hgweb/common.py:24: DeprecationWarning: BaseException.message has been deprecated as of Python 2.6
}}}
Such messages are likely to upset the Web server if issued by CGI scripts. The solution is either to use an appropriate version of Python for the version of Mercurial in use or to [[http://docs.python.org/library/warnings.html|suppress deprecation warnings]].

In the above example, Python 2.6 is being used to run code which uses deprecated features and has not been reviewed for use with that version of Python. If an earlier version of Python is available, such as Python 2.5, and if Mercurial has been set up for use by that Python version, you can change the first line of `hgweb.cgi` as follows (assuming a system-wide installation of Python 2.5):

{{{#!python numbers=disable
#!/usr/bin/python2.5
}}}
To suppress warnings, it may be sufficient to modify `hgweb.cgi`, adding the following code immediately after any `sys.path` adjustments:

{{{#!python numbers=disable
import warnings
warnings.simplefilter("ignore", DeprecationWarning)
}}}
Note that this latter solution is not really recommended as it can hide issues with the code that should ultimately be addressed.
Line 117: Line 828:
Line 126: Line 836:
=== Allowing archive downloads ===
Make sure that your repository's `.hg/hgrc` file (or your Web server user's `.hgrc` file, such as `/home/www-data/.hgrc`, or a system-wide `hgrc` file like `/etc/mercurial/hgrc`) contains the `allow_archive` setting:

{{{
[web]
allow_archive = gz, zip, bz2
}}}
This example illustrates how gzip, zip and bzip2 archive formats can be supported. As a result, links should appear in the Web interface corresponding to these archive types.

=== Indicating the encoding of served content ===
/!\ The encoding configuration should not generally be changed unless served content appears incorrectly.

When hgweb serves content, the locale under which hgweb is operating will dictate which encoding shall be specified in (and used by) the generated Web pages. However, it may be the case that repository content - that is, files managed by a repository - and some metadata are encoded differently from this particular locale. For example, a remote system used to serve repositories using hgweb may use a particular locale with a particular encoding (ISO-8859-1, for example), yet the repositories being served may employ a different encoding (UTF-8, for example).

The encoding of served content can be changed in the configuraiton, for example:

{{{
[web]
encoding = UTF-8
}}}
You can also either change the locale under which hgweb operates, or you can add the following to the `hgweb.cgi` script ''before'' lines which start with `from mercurial import`. For example:

{{{#!python numbers=disable
import os
os.environ["HGENCODING"] = "UTF-8"
}}}
The above example might be appropriate on systems running hgweb under a non-UTF-8 locale where users working with repositories have used UTF-8 as their character encoding.
Line 128: Line 865:

If you are trying to publish multiple repositories, and you haven't configured Apache to force all accesses to go through the `hgwebdir.cgi` script, you will not be able to access any of the repositories you have published unless you set up a `hgweb.cgi` script in each published repository. Clearly, this defeats the whole point of using `hgwebdir.cgi` in the first place, as you're not saving any effort.

Whatever mechanism you are trying to use, the important thing is to ensure that all accesses go through `hgwebdir.cgi`, so that Apache can pass the rest of the path to it using the `REQUEST_INFO` environment variable.
If the version of `hgweb.cgi` or `hgweb.wsgi` is newer than the version of Mercurial you have installed, you may experience strange results. This could happen if you use a binary installer for Mercurial, and manually fetch `hgweb.cgi` or `hgweb.wsgi` from a source repository. Newer versions of Mercurial support older versions of the scripts, so you usually do not have to upgrade all your CGI or WSGI deployments, though it might be useful.

If you are trying to publish repositories, and you haven't configured Apache to force all accesses to go through the `hgweb.cgi` or `hgweb.wsgi` script, you will not be able to access any of the repositories you have published. You may then be tempted to copy repositories into a directory published by your Web server, perhaps setting up a `hgweb.cgi` or `hgweb.wsgi` script in each published repository. '''Do not do this!''' Only the ''script'' is meant to be published; when correctly functioning, the script will itself serve up the repository content, not the Web server.

Whatever mechanism you are trying to use, the important thing is to ensure that all accesses go through `hgweb.cgi` or `hgweb.wsgi`, so that Apache can pass the rest of the path to it using the `PATH_INFO` environment variable.
Line 134: Line 872:

The hgweb interface is completely themable. See the ["Theming"] page for additional instructions on customizing the look of your site.
The hgweb interface is completely themable. See the [[Theming]] page for additional instructions on customizing the look of your site.

<<Anchor(SeeAlso)>>

== See also ==
 * HgWebDirStepByStep for more details on publishing multiple Mercurial repositories through CGI

 * HgWebInIisOnWindows for instructions on configuring HgWeb to run under IIS on Windows

 * [[http://hglabhq.com|HgLab]], source control management system and Mercurial Server for Windows with push, pull and streaming capabilities, repository browser and Active Directory integration

 * [[modwsgi]] to do the same using WSGI and Apache

 * [[http://www.aventinesolutions.nl/mediawiki/index.php/Quick_Tip:_Getting_Started_with_Mercurial|Quick Tip: Getting Started with Mercurial]] describes Mercurial installation and repository serving using mod_python

 * [[http://www.jeremyskinner.co.uk/mercurial-on-iis7/|Setting up a Mercurial server under IIS7 on Windows Server 2008 R2]] covers IIS and includes pictures to illustrate the process

 * [[http://www.endswithsaurus.com/2010/05/setting-up-and-configuring-mercurial-in.html|Setting up and configuring Mercurial in a Windows/IIS/Active Directory environment]] is a series of 4 blog posts describing how to set up Mercurial publishing over IIS and Windows

 * [[https://bitbucket.org/joshjcarrier/phphgadmin/wiki/Home|phpHgAdmin]] - a web management tool (formerly named "hg-php") to administer Mercurial repositories, can create/delete repositories and configure hgrc files.

 * [[http://earwicker.com/seismic|SEISMIC]] - really simple shell script that automates setup of shared repositories under Apache, starting from a clean minimal install of Ubuntu server

 * PublishRepositoriesOnNginx for nginx web server specific configuration and examples.

----
CategoryWeb CategoryHowTo CategoryTipsAndTricks

Publishing Mercurial Repositories

This document focuses on public publication of repositories over the Internet, although private/internal sharing of repositories is mentioned below.

1. Quick recommendations

The easiest way to share changes with other people using Mercurial is to publish them on the Web. The recommended method for self-publishing repositories over HTTP is to use the hgweb scripts with a dedicated Web server such as Apache or IIS.

Less desirable are the following:

  • Use the hg serve command. This is hgweb, but running within Mercurial's built-in Web server. It is not really recommended except for temporary situations where you need to publish a repository for a few minutes, for example to pull changes from a laptop.

  • Make the plain repository available. This uses a much slower 'serverless' protocol called static-http. We won't cover it here, see StaticHTTP instead.

The table in the next section gives a comprehensive overview of the different repository publishing options.

2. Choosing a publishing method

There are a variety of different ways to publish your Mercurial repositories. Some are more powerful than others but may require more effort to set up and administer.

For private or restricted-access repositories, aside from the solutions explicitly marked as "private/internal" in the table below, authentication measures (certificates, logins) can be applied to many of the "public" solutions in order to restrict access. See also AuthorizingUsers.

{i} Note that starting with version 1.6 of Mercurial, the hgwebdir.cgi script no longer exists, and its functionality has been merged into the hgweb.cgi script which in most cases can be used with the same configuration.

{i} Python has an issue with hash collisions that potentially can allow denial of service when exposed to untrusted input. It is thus recommended to use Python 2.7.3 or higher (or 2.6.x, x>=8) and set the environment variable PYTHONHASHSEED=random when hgweb or other applications are exposed to the internet.

Solution

Mechanism

Push?

Browsable

Advantages

Disadvantages

Web-based

third-party hosting

HTTP/HTTPS

yes

yes

minimal setup

not locally administered, may have fees

hgweb

off by default

yes

can use existing web server (CGI, WSGI, mod_python, IIS), including authentication

web server config can be hard to debug

hg serve

off by default

yes

simple and built-in

push has no authentication, so can only be used on trusted internal networks

hg serve behind a proxy (Nginx) (Windows setup)

yes

yes

multiple repos, permits authentication, no CGI

requires proxy (Nginx, HAProxy)

Deveo

yes

yes

projects that can contain mercurial, git or svn repos, permits authentication, permissions system, code-review and commenting

not open source

Kallithea

yes

yes

supports both Mercurial and Git, permissions system, code-review, add/edit files from web interface, full text search, code statistics, users actions journal, easy templating, server-side forking and repository creation, API, open source

requires more resources, longer setup than hg-web

RhodeCode

yes

yes

supports Mercurial, GIT and SVN, easy to use installer, advanced permissions system, code-review (chat & comments), pull-requests, add/edit/delete files from web interface, advanced full text search, auditing journal, unlimited nested groups, API, open-source community edition

requires more resources, longer setup than hg-web

Phabricator

yes

yes

many features

...

Kiln for Your Server

yes

yes

easy setup, integrated code review support, commercial support, permissions system, full text search, server-side forking and repository creation

server is Windows-only, not open source

SCM-Manager

yes

yes

permissions system, server side repository creation, zero-configuration startup, open source

depends on Java

HgLab

yes

yes

easy setup, multiple repositories support, authentication and authorization, Active Directory integration

server is Windows-only, not open source

hgadmin

yes

yes

ssh access included

requires hgweb and ssh server

static HTTP

no

no

does not require hg or CGI support on the server

very slow

Private/internal

ssh

SSH

yes

no

no additional setup

requires Unix server, per-user accounts and repositories

shared SSH

SSH (but with shared accounts)

yes

no

easy key management, fine-grained permissions

requires Unix server, not built in

shared disk

NFS/Samba etc.

yes

no

can use existing setup

generally restricted to intranets, not generally recommended due to general issues with network filesystem reliability

virtual

dvcsauth

HTTPS/SSH

yes

yes

virtual users (database), public and restricted access, also provides git access and access to webspace

requires Unix server, python and twisted, requires apache for https, requires own port for ssh access (can be 22)

(!) See also various other guides about configuring Mercurial's Web interface using various technologies.

3. hgweb

3.1. hgweb - introduction and prerequisites

In this document we assume that repositories reside in the /home/user/hg directory. For example, a repository called myproject would reside in /home/user/hg/myproject. This is merely a convention used to give the reader an additional way of understanding the examples.

3.1.1. Python and Mercurial

First of all, you need to have a Python installation that can access the mercurial package. Verify this by running python and typing the following:

import mercurial

If an ImportError appears, you will need to install the Mercurial libraries for Python on your platform. This problem mostly affects Windows where tools like TortoiseHg provide Mercurial (and have their own Python installation), but where a standard Python installation does not have access to these already-installed libraries. See the downloads page for installers and archives providing Mercurial libraries for existing Python installations.

3.1.2. Web servers and domains

To implement the mechanisms described in this document, you will need the following:

  • Some control over the behaviour of the Web server you use.
  • (Optional) control over the DNS domain you use.

With control over DNS, such as that provided with various Web hosting service control panels, you should be able to set up a subdomain; this makes the URL of your repositories a little tidier, so that http://hg.example.com/myproject can be used instead of http://www.example.com/hgweb.cgi/myproject, for example.

Such an approach, known as virtual hosting, is entirely optional. To implement it for the fictional example.com, a CNAME record for hg.example.com would be defined for the same address as that already used by the Web server.

To setup hgweb to publish a single repository or multiple repositories, perform the following steps:

  1. Find the necessary script in the root of your Mercurial source tree.
  2. Copy it to a directory where your Web server can access it. This will be illustrated below using /home/user/webdir as this directory.

  3. Edit its contents. In particular, you will need to edit it so that it is reading the correct config file.
  4. Make sure the Web server (such as Apache) is configured and can execute the script.

These steps are now described in more detail.

3.2. Getting the hgweb script

The hgweb script is provided in more than one form:

  • hgweb.cgi is a script for deployment using CGI and is provided in the top-level directory of the source distribution of Mercurial.

  • hgweb.wsgi is a script for deployment using WSGI and is provided in the contrib directory in the distribution.

(!) Much better performance can be achieved by using WSGI instead of CGI.

If you should find yourself without such a script, perhaps because you are using a binary installation of Mercurial, you can do one of the following:

  • Download a source package corresponding to the version of Mercurial you are using, unpack it, and extract the script of your choice. This can be useful if you have other reasons for looking at the source or the templates.

  • Browse or clone a repository containing the Mercurial sources (see the developer information for details), and download or extract the appropriate version of the script directly from that repository.

  • If you're using a recent Mercurial release, just download the latest version of hgweb.cgi or hgweb.wsgi from the official repository.

{i} If your Mercurial installation is provided by a package which does not include the hgweb.cgi or hgweb.wsgi files, please consider filing a bug report or feature request with the package maintainer.

3.3. Customizing the hgweb script

The most basic configuration is done by editing hgweb.cgi or hgweb.wsgi. Whichever file is chosen must be edited before it can be used, especially to define which configuration file is to be used to find the repositories, or to indicate which single repository is to be served.

3.3.1. Mercurial location

If Mercurial is not installed system-wide, uncomment and edit the Python path in hgweb.cgi or hgweb.wsgi as indicated:

# Uncomment and adjust if Mercurial is not installed system-wide:
import sys; sys.path.insert(0, "/home/user/mercurial")

The above example assumes that Mercurial has been installed locally in the /home/user/mercurial directory.

{i} It is recommended to use the hgweb.cgi or hgweb.wsgi script originating from the version of Mercurial that is installed on your system. If you are using Debian and installed the Mercurial package, you can find the hgweb.cgi script in /usr/share/doc/mercurial-common/examples/ or /usr/share/doc/mercurial/examples/ (depending on your version).

/!\ If you choose to create a symbolic link to the hgweb.cgi script in your Mercurial source tree instead of copying it, you might run into Python library problems as it might try to use the libraries from the source tree instead of the ones already installed on your system.

3.3.2. Configuration file location

hgweb reads global and repository-specific configuration files like Mercurial does - see hg help config. Note that it will read the .hgrc of the user the web server runs as.

It is also possible to specify a configuration file that is specific to hgweb. It is referred to as hgweb.config in this document (although another name can be chosen), and it needs to be created and referenced in the hgweb.cgi or hgweb.wsgi script. This can be done by changing the script as follows:

# Path to repo or hgweb config to serve (see 'hg help hgweb')
config = "hgweb.config"

Here, a file called hgweb.config will be read from the same directory as the script. You may instead choose to place the file in another directory, and to avoid confusion an absolute path is recommended. For example:

config = "/home/user/hgweb.config"

Even if you only want to publish a single repository, but expect the repository name to appear as part of the URL (perhaps because you intend to publish more repositories later and will need to distinguish between them), specifying a configuration file in the script is the most appropriate solution. You may then specify the details of the single repository in the configuration file as described below.

3.4. Configuration of hgweb

3.4.1. [paths]

The repositories and trees of repositories that are served by hgweb can be configured in the [paths] section in the configuration file. (See also hg help hgweb.)

For example, create /home/user/webdir/hgweb.config like this:

[paths]
myproject = /home/user/hg/myproject
otherproject = /home/user/hg/otherproject

The paths setting in this file tells the CGI script which repositories it is allowed to publish and how their published locations map to their actual locations in the filesystem.

  • The keys (on the left) are URL paths which can incorporate / characters - these paths appear as part of the URL used to access a repository

  • The values (on the right) are filesystem paths which can be relative to the CGI directory - note that it is typically preferable to keep the repositories outside the CGI directory

The paths setting can also contain wildcards. If all your repos are in the /home/user/hg directory, use the following to expose repositories within this directory:

[paths]
/ = /home/user/hg/*

The ** wildcard exposes subrepositories (repositories within repositories) whereas * merely finds repositories within a directory. However, this behaviour is modified by the descend setting as described below.

3.4.1.1. The descend setting

The descend setting resides in the [web] section of the configuration:

[web]
descend = True

When set to True, the repositories exposed may change in the Web interface as hgweb will now descend into the directory hierarchy described by each of the path settings. Where a wildcard of * has been used, directories which are not themselves repositories will be navigated, with repositories added to the display as they are found. Where ** has been used, repositories will also be inspected for subrepositories.

The principal difference between the default behaviour and the "descend" behaviour is that, with descend enabled, hgweb will look beyond a single directory level to find repositories. It will then present all these repositories in a single list, showing the path to each of them in the directory hierarchy. For example, consider the following directory layout:

/home/user/hg/active/
  activeproject
    subrepo
  LATEST/
    verynewproject
/home/user/hg/abandoned/
  abandonedproject
  OLD/
    veryoldproject
      subproject

And consider the following path settings:

[paths]
/active = /home/user/hg/active/*
/abandoned = /home/user/hg/abandoned/*
/all_active = /home/user/hg/active/**
/all_abandoned = /home/user/hg/abandoned/**

With descend mode not activated, visiting the given URL paths (making full URLs such as http://example.com/active) should display the following repositories:

URL path

Repositories

Wildcard used

/active

activeproject

*

/abandoned

abandonedproject

*

/all_active

activeproject, activeproject/subrepo

**

/all_abandoned

abandonedproject

**

Here, the subrepository is emphasised.

With descend mode activated, visiting the same paths should display the following repositories:

URL path

Repositories

Wildcard used

/active

activeproject, LATEST/verynewproject

*

/abandoned

abandonedproject, OLD/veryoldproject

*

/all_active

activeproject, activeproject/subrepo, LATEST/verynewproject

**

/all_abandoned

abandonedproject, OLD/veryoldproject, OLD/veryoldproject/subproject

**

Here, the newly exposed repositories and subrepositories are emphasised.

3.4.1.2. The collapse setting

With descend mode activated, the collapse setting gathers together repositories inside their common locations, giving a directory navigation kind of interface.

[web]
descend = True
collapse = True

The above example directory layout should look like the following with both descend and collapse enabled:

URL path

Repositories

/active

activeproject, LATEST

/abandoned

abandonedproject, OLD

/all_active

activeproject, activeproject/subrepo, LATEST

/all_abandoned

abandonedproject, OLD

Here, the directory names have been emphasised. These can be navigated in the interface to reach the following URL paths, showing the expected listings of repositories:

URL path

Repositories

/active/LATEST

verynewproject

/abandoned/OLD

veryoldproject

/all_active/LATEST

verynewproject

/all_abandoned/OLD

veryoldproject, veryoldproject/subproject

In short, the collapse setting collapses collections of repositories found in a directory structure into a single entry bearing the name of the common directory leading to them all. If you want a multi-level navigable directory hierarchy showing only the repositories in each directory, this setting should be enabled together with descend mode.

3.4.2. [collections]

{i} There is no longer any reason to use collections - just use paths instead.

The above hgweb.config file could be rewritten with collections as follows:

[collections]
/home/user/hg = /home/user/hg

The collections setting in this file tells the CGI script where to look for repositories.

  • The keys (on the left) and the values (on the right) are both filesystem paths

  • The keys should be prefixes of the values and are "subtracted" from the values in order to generate the URL paths to each repository

Consider two repository collections given in the hgweb.config file:

[collections]
/home/user/private = /home/user/private
/home/user/official = /home/user/official

Where both /home/user/private and /home/user/official contain repositories using the same names (myproject and otherproject), a combined list will then be shown by the Web interface containing two entries for each of someproject and otherproject: one from the private collection and one from the official collection. This may be confusing to the end-user, so we may modify the configuration file as follows:

[collections]
/home/user = /home/user

This will now produce entries for private/someproject, private/otherproject, official/someproject and official/otherproject. Unfortunately, it will also find other repositories outside the private and official directories. It is therefore recommended that repositories are located in suitably organised directory hierarchies if exported in this way.

3.4.3. Publishing a single repository

It is possible to configure hgweb to publish a single repostiory - like hg serve does by default. This emulates the behaviour of the old hgweb.cgi found in older versions of Mercurial.

Edit the call to hgweb() in hgweb.cgi or hgweb.wsgi to specify the path to the repository instead of a configuration file. You can also specify a descriptive name for the repository. For example:

application = hgweb("/home/user/hg/myproject", "My Project")

3.4.4. Public and Private Repositories

If you want to serve both public and private repositories, you'll need to put them under different web URIs, like http://hg.example.com/hg-public and http://hg.example.com/hg-private. You will also need two different configuration files for hgweb.cgi or hgweb.wsgi, which in turn means two different copies of the script itself.

The actual public/private distinction will mostly be enforced by your web server configuration. Since the two repositories (or collections of repositories) have different paths, you can require different levels of authentication for each path.

3.5. Configuring Lighttpd

3.5.1. Configuring CGI Lighttpd

Put hgweb.cgi and hgweb.config to root of repositories dir (/srv/hg in example). With URL rewriting hgweb.config look like:

[paths]
/ = /srv/hg/*

[web]
style = gitweb
encoding = "UTF-8"

baseurl = /hg

deny_push = *
allow_archive = bz2, gz, zip

/etc/lighttpd/conf-available/92-mercurial.conf (note that url.rewrite work inside $HTTP["url"] with Lighttpd >= 1.4.34):

$HTTP["url"] =~ "^/hg(/|$)" {
  alias.url = ( "/hg/" => "/srv/hg/" )
  cgi.assign = ( "/hgweb.cgi" => "" )
  url.rewrite-once = ("^/hg/?(.*)$" => "/hg/hgweb.cgi/$1" )
}

Under Debian enable config:

sudo lighttpd-enable-mod mercurial

and restart server:

sudo service lighttpd restart

and visit http://localhost/hg/!

3.5.2. Configuring FastCGI Lighttpd

Install packages:

sudo apt-get install lighttpd spawn-fcgi python-flup mercurial

Fill Lighttpd config /srv/hg/lighttpd.conf:

  server.pid-file = "/srv/hg/lighttpd.pid"
  server.document-root = "/srv/hg/"
  server.port = 8888
  server.username = "www"

  server.modules += ( "mod_rewrite" )
  url.rewrite-once = (
    "^/?$" => "/hgweb.fcgi",
  )

  server.modules += ( "mod_fastcgi" )
  fastcgi.server += (
    "hgweb.fcgi" => ( (
       "bin-path"      => "/srv/hg/hgweb.fcgi",
       "socket"        => "/srv/hg/hgweb.fcgi.sock",
       "min-procs"     => 1,
       "max-procs"     => 2
    ) )
  )

Put to /srv/hg/ hgweb.fcgi script. Fix path to hgweb.config:

  config = "/srv/hg/hgweb.config"

  from mercurial import demandimport; demandimport.enable()
  from mercurial.hgweb import hgweb
  from flup.server.fcgi import WSGIServer
  application = hgweb(config)
  WSGIServer(application).run()

Fill hgweb.config:

  [collections]
  /srv/hg/ = /srv/hg/

  [web]
  encoding = "UTF-8"
  style = gitweb

  allow_push = *
  push_ssl = False

Put repositories to /srv/hg/*:

  $ hg clone -U ~/devel/proj1 /srv/hg/proj1
  $ hg clone -U ~/devel/proj2 /srv/hg/proj2

Start Lighttpd:

lighttpd -d -f /srv/hg/lighttpd.conf

Clone repository:

  $ hg clone http://$USER:$PASS@$HOST:$PORT/hg/hgweb.fcgi/proj1

3.5.3. Configuring LDAP auth with Lighttpd

Add to your Lighttpd config:

  server.modules += ( "mod_auth" )
  auth.backend = "ldap"
  auth.backend.ldap.hostname = "ldap.evil.com"
  auth.backend.ldap.base-dn = "ou=XXX,o=YYY"
  auth.backend.ldap.filter = "(uid=$)"
  auth.require = (
      "" => (
          "method"  => "basic",
          "realm"   => "Enter your LDAP auth",
          "require" => "valid-user",
      ),
  )

Check for user name that allowed to push by /srv/hg/proj/.hg/access.bash:

#!/bin/bash
users='LDAP1 LDAP2 LDAP3'

# Allow non-http connections (ssh).
[[ -z "$HTTP_AUTHORIZATION" ]] && exit 0

for user in $users; do
  [[ $user = $REMOTE_USER ]] && exit 0
done

echo "Your name is '$REMOTE_USER'"
echo "You are not in a list of allowed users:"
echo $users | fmt -w 60 | sed 's=^=  ='
exit 1

Register check script at /srv/hg/proj/.hg/hgrc:

  [hooks]
  prechangegroup.access = /srv/hg/proj/.hg/access.bash

3.6. Configuring Apache

There are many ways of configuring Apache to run scripts, and a few of the possibilities are provided below. Where the main configuration files are mentioned, you should use the appropriate conventions for your system in defining such files in the conf.d and/or sites-available directories.

{i} To ensure that a script is executable by the Web server, the following command is typically used:

chmod u+x hgweb.cgi

{i} The preferred mechanism for persuading Apache to use updated configuration information can vary from platform to platform and from distribution to distribution. Please consult your distribution's documentation, if appropriate, or the more general Apache documentation (for example, the apachectl documentation) for details.

Note that only the hgweb.cgi or hgweb.wsgi script should be "published" by the Web server.

This script is perfectly capable of serving repositories once it knows where these repositories are. You do not need (or even want) the actual repositories to be published by the Web server itself: the CGI script will, when run, read from the repositories and output the necessary content itself.

In short, do not put the actual repositories under some kind of "document root" or "public HTML" directory - this is the static HTTP approach and is completely different from what is being documented here. Here, we are using a script to serve up repositories, not the Web server itself.

3.6.1. Using httpd.conf

This example requires access to the main configuration files.

3.6.1.1. CGI

The easiest way to serve the hgweb.cgi script is to use a ScriptAlias directive:

ScriptAlias /hg "/home/user/webdir/hgweb.cgi"

This actually exports the repository browser at the URL path /hg (for example, http://www.example.com/hg) and doesn't expose the name of the script at all.

{i} See the Apache httpd documentation for ScriptAlias.

3.6.1.2. WSGI

The equivalent way to serve the hgweb.wsgi script is the WSGIScriptAlias directive:

WSGIScriptAlias /hg "/home/user/webdir/hgweb.wsgi"

Again, this actually exports the repository browser at the URL path /hg (for example, http://www.example.com/hg) and doesn't expose the name of the script at all.

{i} See the Quick Configuration Guide for mod_wsgi for more information.

3.6.2. Using an .htaccess file

This example can be used with pre-configured CGI directories.

If you may not change the main Apache configuration files, you may still be able to use .htaccess file to make URLs nicer, as suggested in the previous section. Here is an .htaccess file which sits in the published webdir directory on the Web server and redirects http://www.example.com/hg/* URLs to the hgweb.cgi script inside that folder. As a result it would no longer be not necessary to mention the CGI script name in URLs: one could use http://www.example.com/hg/myproject instead of http://www.example.com/hg/hgweb.cgi/myproject.

# Taken from http://www.pmwiki.org/wiki/Cookbook/CleanUrls#samedir
# Used at http://ggap.sf.net/hg/
Options +ExecCGI
RewriteEngine On
#write base depending on where the base url lives
RewriteBase /hg
RewriteRule ^$ hgweb.cgi  [L]
# Send requests for files that exist to those files.
RewriteCond %{REQUEST_FILENAME} !-f
# Send requests for directories that exist to those directories.
RewriteCond %{REQUEST_FILENAME} !-d
# Send requests to hgweb.cgi, appending the rest of url.
RewriteRule (.*) hgweb.cgi/$1  [QSA,L]

A corresponding change in hgweb.config can be made to make sure that the nicer urls are used in the HTML produced by the CGI and WSGI scripts:

[web]
baseurl = /hg

Where the scripts are made to appear at the server root (for example, http://hg.example.com/), leave the baseurl setting blank:

[web]
baseurl =

Generally, the value specified should not end with a / character.

3.6.3. Adding authentication

The following configurations requires access to the main configuration files. They can be combined with the script or directory declarations to impose authentication and access restrictions on repositories.

To use these configurations with the pre-configured CGI directories, the Location directive start and end tags can be omitted, leaving the bare authentication-related directives.

3.6.3.1. Restrict to known users

This configuration restricts access to a known set of users as defined in the /home/user/hg/hgusers password file:

<Location /hg>
    AuthType Basic
    AuthName "Mercurial repositories"
    AuthUserFile /home/user/hg/hgusers
    Require valid-user
</Location>

<!> Since the AuthType directive is set to Basic, passwords are communicated as plain text, and it is therefore recommended that this only be used with a server configured for HTTPS. See the Apache SSL documentation for more information.

{i} To set up the password file, use the htpasswd tool as described in the relevant Apache documentation.

This alternative configuration employs digest authentication and thus offers an alternative to basic authentication and HTTPS:

<Location /hg>
    AuthType Digest
    AuthName "Mercurial repositories"
    AuthDigestProvider file
    AuthUserFile /home/user/hg/hgusers
    Require valid-user
</Location>

{i} To set up the password file, use the htdigest tool as described in the relevant Apache documentation.

{i} See the Apache mod_auth_digest documentation for more information on digest authentication and its limitations.

3.6.3.2. Restrict pushing to known users

To exercise finer control and to provide global read-only access to the repositories, but require authentication for pushing, a LimitExcept directive can be added. Here are the previous examples with such a directive in use. First with basic authentication:

<Location /hg>
    AuthType Basic
    AuthName "Mercurial repositories"
    AuthUserFile /home/user/hg/hgusers
    <LimitExcept GET>
        Require valid-user
    </LimitExcept>
</Location>

And with digest authentication:

<Location /hg>
    AuthType Digest
    AuthName "Mercurial repositories"
    AuthDigestProvider file
    AuthUserFile /home/user/hg/hgusers
    <LimitExcept GET>
        Require valid-user
    </LimitExcept>
</Location>

{i} See the Apache documentation for LimitExcept for more information.

Now consult the instructions on allowing the push operation in Mercurial to complete this configuration task.

3.6.3.3. Using groups

Apache also provides support for user groups through the AuthGroupFile directive. Here it is in context:

    AuthUserFile /home/user/hg/hgusers
    AuthGroupFile /home/user/hg/hggroups

Instead of a Require directive involving users, the following directive can be used in its place. Here it is in context:

    <LimitExcept GET>
        Require group hobbits
    </LimitExcept>

Here, the hobbits group is defined in the nominated file as described in the relevant Apache documentation for AuthGroupFile, connecting users who will authenticate themselves with groups such as hobbits.

3.6.3.4. Public and Private Repositories

As was mentioned earlier, public versus private is mostly enforced by the web server configuration. In this case, we will assume that we have made two copies of the hgweb.cgi script under /home/user/webdir. One will be named hgweb-public.cgi and the other hgweb-private.cgi. These scripts will in turn each load a different configuration file. The public configuration will serve our public repositories, and the private configuration will serve our private repositories.

ScriptAlias /hg-public /home/user/webdir/hgweb-public.cgi

<Location /hg-public>
    AuthType Basic
    AuthName "Mercurial repositories"
    AuthUserFile /home/user/hg/hgusers

    <LimitExcept GET>
        Require user valid-user
    </LimitExcept>
</Location>

ScriptAlias /hg-private /home/user/webdir/hgweb-private.cgi

<Location /hg-private>
    AuthType Basic
    AuthName "Mercurial repositories"
    AuthUserFile /home/user/hg/hgusers
    Require valid-user
</Location>

With this configuration, the public repositories are read-only without authentication.

{i} Note that the above configuration is built from details given in previous sections, combining the different activities of publishing, authentication and access control.

3.6.4. Using virtual hosts

This example requires access to the main configuration files.

Here is an example Apache configuration for publishing repositories at http://hg.example.com/:

<VirtualHost *>
  ServerName hg.example.com

  ServerAdmin webmaster@example.com
  CustomLog logs/access_log.example combined
  ErrorLog logs/error_log.example

  ScriptAlias / "/home/user/webdir/hgweb.cgi"
</VirtualHost>

The ScriptAlias directive is taken from the script example; all other directives support the virtual host hg.example.com.

{i} Note that the CustomLog and ErrorLog directives may need to be changed to refer to files in standard locations such as /var/log/apache2 or /var/log/httpd, depending on how Apache is configured.

Here is a more complicated example using rewrite rules and explicit Directory directives. A description follows the example.

<VirtualHost *:80>
  ServerName hg.example.com

  ServerAdmin webmaster@example.com
  CustomLog logs/access_log.example combined
  ErrorLog logs/error_log.example

  RewriteEngine on
  RewriteRule (.*) /home/user/webdir/hgweb.cgi/$1

  # Or we can use mod_alias for starting CGI script and making URLs "nice":
  # ScriptAliasMatch ^(.*) /home/user/webdir/hgweb.cgi/$1

  <Directory "/home/user/webdir/">
    Order allow,deny
    Allow from all
    AllowOverride All
    Options ExecCGI
    AddHandler cgi-script .cgi
  </Directory>
</VirtualHost>

The directives in the above have the following purposes:

  • The ServerName directive matches the hostname configured for the domain.

  • The next section (ServerAdmin and so on) is just administrative cruft.

  • The rewrite-related directives (RewriteEngine and RewriteRule) tell Apache to turn URIs ending in /myproject into /home/user/webdir/hgweb.cgi/myproject. This causes Apache to fire up the CGI script, giving it the remainder of the URI as an argument.

  • Finally, the Directory section lets Apache know that we have a CGI script to look at.

{i} See the Apache virtual hosts documentation for more information.

3.7. Allowing push

Make sure that your repository is writeable by the user running the Apache server (such as www-data), and that the repository's .hg/hgrc file (or your Web server user's .hgrc file, such as /home/www-data/.hgrc, or a system-wide hgrc file like /etc/mercurial/hgrc) contains the allowed users:

[web]
allow_push = frodo, sam

This would allow pushing for frodo and sam. You can allow pushing for everyone with the following:

[web]
allow_push = *

By default, pushing is only allowed via HTTPS. To permit HTTP pushing you have to add this to your repository's .hg/hgrc file (or your Web server user's .hgrc file, such as /home/www-data/.hgrc, or a system-wide hgrc file like /etc/mercurial/hgrc):

[web]
push_ssl = false

Now consult the instructions on configuring Apache to restrict pushing in order to set up the authentication/authorisation infrastructure.

3.7.1. Defining user credentials

To define credentials for the allowed users, use the htpasswd tool. For example:

htpasswd -c /home/user/hg/hgusers frodo

You will need to enter the desired password for the username frodo. Later, you can add more usernames without the -c option:

htpasswd /home/user/hg/hgusers sam

{i} See the relevant Apache documentation for htpasswd.

3.7.2. Write permissions on repositories

Repositories can only successfully receive pushed changesets if the Web server user has write access to each repository's .hg directory and its contents. See the permissions troubleshooting section below for details of errors and remedies related to permissions.

3.8. Troubleshooting

Mercurial is executed on the server by Apache and therefore runs as the Apache user and group. If experiencing flaky behavior, it may be because the CGI script is failing because it does not have enough rights. In that case, you should check the log files, but you can also make some common-sense permissions checks.

3.8.1. Problems with trust settings

Trust-related messages of the form Not trusting file... may appear in the Web server logs. Although it is unlikely that such messages would cause a 500 (Internal Server Error) status code, it can be useful to eliminate them in order to troubleshoot other problems.

3.8.2. Permissions

There are two ways that permissions problems primarily manifest themselves on the server: either you won't see any repositories at all (indicating missing read or execute permissions) or you won't be able to push to the server (indicating missing write permissions), which gives you the error message:

abort: ‘http://foo/bar’ does not appear to be an hg repository!

Another common error often related to permissions:

abort: HTTP Error 500: Internal Server Error

The best way to solve permissions problems is to grant the required permissions to the Apache group (the www-data group on Debian). You should have some familiarity with assigning permissions under Linux/Unix before attempting the following.

Suppose your main user is john, your Web server runs as www-data and your repositories are in /home/john/repositories. Then, execute the following commands to change the group for all files in your repositories on the server and make the files writable to the server process as well as make the home directory readable.

chown -R john:www-data /home/john/repositories
chmod -R g+rw /home/john/repositories
chmod g+x /home/john/repositories

For each repository, you will have to make both the repository folder and the .hg folder executable as well:

chmod g+x /home/john/repositories/rep1
chmod g+x /home/john/repositories/rep1/.hg

If each of your repositories are subdirectories from some main folder which only contains repositories (such as /var/www/html/hg/repos, with underlying repositories /var/www/html/hg/repos/repo1, /var/www/html/hg/repos/repo2, and so on), you may find it easier to remember to script the setting of these permissions. Write the following at the prompt to create a new executable shell script:

cat <<EOM >permission.sh
chown -R john:www-data repos
chmod -R g+rw repos
chmod g+x repos
chmod g+x repos/*
chmod g+x repos/*/.hg
EOM
sudo chown root:root permission.sh
sudo chmod u+x permission.sh

These assume your username is john, the Apache server's user's group is www-data, and the folder containing your repositories is called repos. Now you can update permissions for your entire repository by navigating to this containing directory and issuing a single command:

sudo ./permission.sh

Before you start crawling through logs to find out why your Mercurial server isn't letting you pull, push, or authenticate, run this command and see if it solves your issue.

It is important to note that the entire repository tree must be accessible by the Web server user (www-data in the above examples). For example, the tree /home/john/source/repos/hg/repo1 requires john, source, repos, and hg to be executable by the Web server user.

3.8.3. HTTP Error 400: Bad Request

A similar problem with pulling through http proxies is discussed here.

This error may occur when you try to push/pull changes to/from the web server. Mercurial will send out a long (~7k bytes) request line that the server refuses to process.

In Apache 2.2, the LimitRequestLine defaults to 8190 (bytes). To circumvent the problem, try increasing the request line limit e.g to 16380.

3.8.4. Mercurial in verbose mode

This problem (reported as a bug against Mercurial) might potentially be solved in future Mercurial versions.

On certain occasions, observed when attempting to clone a repository via hgweb.cgi, the Web server will produce a 500 (Internal Server Error) status code, aborting the operation. This is due to extra output being sent by Mercurial to the Web server as part of an HTTP response.

If your repository's .hg/hgrc file (or your Web server user's .hgrc file, such as /home/www-data/.hgrc, or a system-wide hgrc file like /etc/mercurial/hgrc) includes the following setting, you should consider removing or disabling it (or moving it to your normal user's .hgrc file, if appropriate):

verbose = true

3.8.5. Using an unsupported version of Python

When the Web server produces a 500 (Internal Server Error) status code, the error log may contain messages resembling the following:

/var/lib/python-support/python2.6/mercurial/hgweb/common.py:24: DeprecationWarning: BaseException.message has been deprecated as of Python 2.6

Such messages are likely to upset the Web server if issued by CGI scripts. The solution is either to use an appropriate version of Python for the version of Mercurial in use or to suppress deprecation warnings.

In the above example, Python 2.6 is being used to run code which uses deprecated features and has not been reviewed for use with that version of Python. If an earlier version of Python is available, such as Python 2.5, and if Mercurial has been set up for use by that Python version, you can change the first line of hgweb.cgi as follows (assuming a system-wide installation of Python 2.5):

#!/usr/bin/python2.5

To suppress warnings, it may be sufficient to modify hgweb.cgi, adding the following code immediately after any sys.path adjustments:

import warnings
warnings.simplefilter("ignore", DeprecationWarning)

Note that this latter solution is not really recommended as it can hide issues with the code that should ultimately be addressed.

3.9. Putting useful information in the index page

If you get everything working properly, pointing a browser at the CGI script directly should give a list of the repositories you've published. This will be a table containing four columns. Let's say you have published a repository named lord/rings. To fill out the first three columns of the index entry for that repository, you will need to edit its .hg/hgrc file, and add a new section:

[web]
contact = Bilbo Baggins
description = My precious!
name = lord/rings

3.10. Allowing archive downloads

Make sure that your repository's .hg/hgrc file (or your Web server user's .hgrc file, such as /home/www-data/.hgrc, or a system-wide hgrc file like /etc/mercurial/hgrc) contains the allow_archive setting:

[web]
allow_archive = gz, zip, bz2

This example illustrates how gzip, zip and bzip2 archive formats can be supported. As a result, links should appear in the Web interface corresponding to these archive types.

3.11. Indicating the encoding of served content

/!\ The encoding configuration should not generally be changed unless served content appears incorrectly.

When hgweb serves content, the locale under which hgweb is operating will dictate which encoding shall be specified in (and used by) the generated Web pages. However, it may be the case that repository content - that is, files managed by a repository - and some metadata are encoded differently from this particular locale. For example, a remote system used to serve repositories using hgweb may use a particular locale with a particular encoding (ISO-8859-1, for example), yet the repositories being served may employ a different encoding (UTF-8, for example).

The encoding of served content can be changed in the configuraiton, for example:

[web]
encoding = UTF-8

You can also either change the locale under which hgweb operates, or you can add the following to the hgweb.cgi script before lines which start with from mercurial import. For example:

import os
os.environ["HGENCODING"] = "UTF-8"

The above example might be appropriate on systems running hgweb under a non-UTF-8 locale where users working with repositories have used UTF-8 as their character encoding.

3.12. What can go wrong?

If the version of hgweb.cgi or hgweb.wsgi is newer than the version of Mercurial you have installed, you may experience strange results. This could happen if you use a binary installer for Mercurial, and manually fetch hgweb.cgi or hgweb.wsgi from a source repository. Newer versions of Mercurial support older versions of the scripts, so you usually do not have to upgrade all your CGI or WSGI deployments, though it might be useful.

If you are trying to publish repositories, and you haven't configured Apache to force all accesses to go through the hgweb.cgi or hgweb.wsgi script, you will not be able to access any of the repositories you have published. You may then be tempted to copy repositories into a directory published by your Web server, perhaps setting up a hgweb.cgi or hgweb.wsgi script in each published repository. Do not do this! Only the script is meant to be published; when correctly functioning, the script will itself serve up the repository content, not the Web server.

Whatever mechanism you are trying to use, the important thing is to ensure that all accesses go through hgweb.cgi or hgweb.wsgi, so that Apache can pass the rest of the path to it using the PATH_INFO environment variable.

3.13. Theming

The hgweb interface is completely themable. See the Theming page for additional instructions on customizing the look of your site.

4. See also


CategoryWeb CategoryHowTo CategoryTipsAndTricks

PublishingRepositories (last edited 2020-12-06 23:19:24 by PaulBoddie)