Installing Mercurial on a Shared Web Server without Root Access (HostEurope)

April 12th, 2010 · 20 Comments · Server

SVN did a great job for me for at least four years now. Lately, I stumbled upon Mercurial and decided to have a closer look. It turned out that Mercurial (also called “hg”) comes with some great advantages, namely:

  • Not a “Version Control System” (VCS), but a “Distributed Version Control System” (DVCS) enabling you to check in changes locally (offline, without an internet connection). The advantages of this one are also discussed in detail in PEP 374 (Python Foundation).
  • Available in pure Python, therefore installable on a standard shared web server without root access (not a virtual server, just a “web host”). Thereby cutting my costs of maintaining a root server on my own or being charged by a specialized host for an SVN/VPS plan.

This post is a small guide on how to accomplish the mission of installing Mercurial (the pure Python version) on a shared web host. In this exemplary case a “WebPack Pro” that we rent from our ISP of choice, HostEurope, is going to be used. However, what is described herein should basically work for any web hosting plan that fulfills the following requirements. This article is therefore most interesting for people who already own a shared web hosting plan and wish to use that plan for hg hosting also.

Requirements

  • Source version of Mercurial
  • A shared web server at an arbitrary web host enabling execution of CGI scripts written in Python (HostEurope provides Python 2.4 which appears to be sufficient).
  • mod_python or mod_wsgi (better).
  • SSH access to that host. This is required to setup Mercurial on your shared web server. No need for root privileges.

Installation (Step by Step)

  1. Unpack the Mercurial source tarball on your local system.
  2. Create a temporary directory on your web server and transfer the extracted Mercurial source tree to that directory. You can do so via SSH or FTP.
  3. SSH into the server (if you did not so already) and create a top-level directory named “python”. This is going to hold all the Python modules you would like to use, but which are not currently installed on the server’s root Python distribution.
  4. Change to the Mercurial source directory and build the module in pure Python mode (instructions adopted from Mercurial Wiki) :
    $ python setup.py --pure build_py -c -d . build_ext -i build_mo --force
    
  5. Likewise, install the module. Here, it is essential to enter the correct prefix path, as you want an alternate installation following the prefix scheme, not a standard installation. Please specify the path to your “python” directory, which you created in step 3 (in my case this is “../../python”):
    $ python setup.py --pure install --prefix ../../python --force
    
  6. If everything went well setup.py has installed the Mercurial module files to python/lib/python2.4/site-packages and the hg binary to python/bin.
  7. In order to get the hg binary running via SSH you have to export your custom PYTHONPATH so Python knows where to look for the hg modules. Via SSH go to your home directory on the web host and create a .bash_profile file as follows:
    $ cd ~
    $ touch .bash_profile
    

    Open the file in a text editor and add the following line to it (adjust the path so that it fits your configuration):

    export PYTHONPATH=/is/htdocs/wpXXXXX_XXX/python/lib/python2.4/site-packages
    

    In order to make hg accessible from any directory within the shell, add the following line (adjust path corresponding to your environment again):

    export PATH=/is/htdocs/wpXXXXX_XXX/python/bin:$PATH
    
  8. Logout and login again via SSH. Type hg. If you get the Mercurial Distribution SCM help screen you now have finished installation and are ready to go for setting up Mercurial web access.

Setting up hgwebdir.cgi

  1. First of all, create a directory on your webspace for hg. This directory must be reachable via HTTP. You may also want to set up a subdomain, e.g. hg.yourdomain.com and link that to your hg web directory.
  2. Get hgwebdir.cgi from the root of the Mercurial source tree or download hgwebdir.cgi from the Mercurial website, upload it to your hg directory and rename it to index.cgi.
  3. Make sure your web host is configured appropriately to handle .cgi files and index.cgi files. (You should be able to configure these settings in the scripts settings of your ISP’s administrative UI.)
  4. Open index.cgi using your text editor of choice. It is a good idea to check the script environment statement that is located in the first line of the file. It should look like the following:
    #!/usr/bin/env python
    

    This should work on most servers. However, if your python binary is not linked (or located) in /usr/bin/python you may have to correct for this.

  5. Find the following comment # enable importing on demand to reduce startup time. Beneath the comment line there should be two commented lines. Change these lines to something like this:
    import sys
    sys.path.insert(0, "/is/htdocs/wpXXXXX_XXX/python/lib/python2.4/site-packages")
    

    Replace the absolute path to the site-packages directory with your own one.

  6. If everything works as intended, the script should now be callable via HTTP. Enter the address of your hg web directory into your web browser and check whether the script runs correctly.

Setting Up Your First Repository and Configuring hgweb.config

  1. Via SSH you can setup a first test repository like this:
    $ cd /path/to/www/hg
    $ hg init test
    

    hg will create a directory named test and place a .hg subdirectory in it containing repository-specific configuration and payload data.

  2. hgwebdir.cgi has to know which repositories to serve. You tell this by creating a file named hgweb.config. Simply put the config file into the directory of hgwebdir.cgi.
  3. Open the config file with a text editor and add the following lines:
    [paths]
    test=test
    

    Note: more info on how to configure hgwebdir.cgi can be found on HgWebDirStepByStep (in the Mercurial Wiki).

  4. Finally, the repository itself needs some configuration. In test/.hg create a new file named hgrc and add the following lines to it:
    [ui]
    user = Firstname Lastname 
    
    [web]
    push_ssl = false
    allow_push = *
    

    This will register a first user, allow for HTTP pushing, and allow pushing for everyone (we will take care of security later on).

  5. That’s it. Your first repository is served via Mercurial on your shared web host.

Testing the Whole Thing

You may want to do a simple test to check whether your repository is working and you are able to pull and push changes as intended. You can do so by opening a terminal and type something like the following:

$ hg clone http://hg.yourdomain.com/index.cgi/test
$ cd test
$ touch testfile
$ echo "This is just a test" > testfile
$ hg add testfile
$ hg commit -m 'Testing...' -u username
$ hg push

If everything went right, this should add the file testfile to the repository root and push it to the web server.

For now, you hopefully have a working Mercurial repository directory service up and running on your shared web host. However, there are two major flaws. Firstly, the repository address is not as beautiful as it could be, because of the index.cgi contained in any path. Secondly, the repositories are accessible for everyone. We will fix these issues in what follows.

Beautifying hgwebdir Paths

In order to strip index.cgi from the repository URLs we will have to use mod_rewrite (and your server needs to support that apache module).

Go to your hg webdir root directory and create a file named .htaccess. Open the file in a text editor and add the following lines:

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

Note: this apache script rewrites URLs so that any directory queried in the form hg.yourdomain.com/directory is automatically rewritten to hg.yourdomain.com/index.cgi/directory internally. Consequently, users can omit disturbing repetitive typing of index.cgi in hg repository URLs. Please note that you may have to adapt RewriteBase to your specific server environment. If you do not serve hg repositories via a subdomain you should specify the relative base directory of your hg webdir here instead (this may e.g. be /hg if you serve hg repositories via www.yourdomain.com/hg). The approach is also discussed in PublishingMultipleRepositories on the Mercurial Wiki.

Securing hgwebdir

You can secure your hg web directory in multiple ways. You may want to allow pulling by anyone and pushing only to specific core developers. Detailed information about hg authentication can be found on PublishingMultipleRepositories.

However, my intention is to have private repositories, which I share only with my friends (no public pulling). Me and my friends will use HTTP authentication and I will create a user and password for everyone who is allowed to pull and push. Fortunately, this scenario is relatively simple to configure for everyone who knows about apache authentication configuration using htaccess files.

First of all, use htpasswd to create a password file for hg users. Name the file .hgusers and place it in a location that is not accessible via HTTP. For example, you may want to do it this way:

$ cd /private-path
$ htpasswd -c hgusers username
Enter password twice, etc...

Since we already have a .htaccess file, it is even more simple. Re-open the file using a text editor and add the following lines at the end of the file:

# Authentication
AuthName "Please enter your username and password."
AuthType Basic
Require valid-user
AuthUserFile /is/htdocs/wpXXXXX_XXX/.hgusers

Please change the path to the .hgusers file conforming to your server environment.

Congratulations! You now have a running, secured, beautified, pure-python hg repository server on your cheap web hosting account.

Remarks
Building Mercurial in pure Python may have drawbacks in terms of performance. This has more thoroughly been discussed on the Mercurial mailing list, see mailing list archive on pure python Mercurial.

Tags: ····

20 responses so far ↓

  • 1 Installing Mercurial on a Shared Web Server without Root Access … | SSH Hosting  Apr 12, 2010 at 4:48 pm

    […] more here: Installing Mercurial on a Shared Web Server without Root Access … Posted in Create, Custom, Uncategorized, for, home, host, in, or, ssh, web, your | Tags: […]

  • 2 Keith  May 5, 2010 at 5:28 pm

    fantastic walkthrough I spend a bunch of time following other people’s instructions.

    this worked perfectly on hostgator. thanks for the write-up.

  • 3 basketball jerseys  May 24, 2010 at 3:13 am

    I hope you will keep updating your content constantly as you have one dedicated reader here.

  • 4 Martin Geisler  Jun 7, 2010 at 10:26 am

    Nice guide. Let me just note that if the webhost has the standard set of development tools installed (GCC, make, Python header files, etc), then a simple

    make local

    will give you a completely self-contained installation right where you’ve unpacked Mercurial.

    If you cannot compile Mercurial, then

    make local PURE=–pure

    will prepare a pure-Python version of Mercurial. The preparation is really just a matter of moving the files from mercurial/pure/ up to mercurial/ — that will make Mercurial find them.

    In both cases, you should put the top-level hg script into your patch via a symlink. It is important that you use a symlink instead of copying the file, since otherwise the hg script wont be able to find all the other Python files.

  • 5 Sam  Sep 18, 2010 at 3:27 pm

    Thanks Tobias, that guide helped me a lot!

  • 6 pioj  Nov 28, 2010 at 11:22 pm

    Help! I can’t get the online repository at Hostgator to pull from the local clone.

    Keith, can I contact you?

  • 7 Haqqi  Dec 6, 2010 at 4:57 pm

    I cannot do htpasswd command in hostgator for creating authentication. Any other way?

  • 8 Du  Dec 16, 2010 at 11:58 pm

    Hello, thanks for the nice tutorial but i dont have ssh access to my host, at least at the current one, so can i perform part of the ssh steps through ftp (file related) and through cron jobs ?

    Thanks in advance!

  • 9 admin  Dec 28, 2010 at 5:21 pm

    Hello Du, I think this could be kind of fiddling without SSH access… Of course everything file related can be done via FTP, but once you have done that probability is high you will run into privilege problems using cron. I am very sorry, but I suggest you spend a few dollars for a host with SSH access…

    Tobias

  • 10 hg-gateway: Supporting multiple Mercurial users on a Shared SSH account | Untyped  Feb 21, 2011 at 12:20 am

    […] of being in this situation, download and compile hg as non-root user (without access to gcc) as detailed here. That works with GoDaddy’s […]

  • 11 Roshan  Mar 1, 2011 at 9:28 am

    Shameless Plug: If you care, there is also hg-gateway for scenarios where you don’t have root access on the machine, such as the case with shared hosting accounts.

    http://parametricity.net/b/2011/02/20/hg-gateway-supporting-multiple-mercurial-users-on-a-shared-ssh-account/

  • 12 sk  Aug 28, 2011 at 6:49 pm

    Hey, thanks for the writeup.

    I’m just using the first part of this walkthrough so that I can version control my site, and push/update it from my local terminal. However, I cannot push to the server, because hg push ssh://admin@example.com/path/to/project returns “hg: command not found”. I know hg is working because I’ve scp’d a repo up there, and its able to check the status etc… I know its a different scenario, but do you have any hints? It seems that .bash_profile isn’t run? at least, the hg binary isn’t found.

    Many thanks

  • 13 Geier  Sep 25, 2011 at 7:12 am

    Installing mercurial on a shared webhost without SSH access is also possible: All the SSH-commands posted by you can also be executed using php’s shell_exec() function!

  • 14 danne34  Feb 4, 2012 at 10:42 am

    Give it a chance, I realy like your way to post

  • 15 Marvin  Mar 16, 2012 at 10:01 pm

    Thank you for this tutorial!

    Mercurial has changed things slightly, which has confused me. There is no longer a hgwebdir.cgi file. It has been incorporated into the hgweb.cgi file.

    Also, I am stuck at “Setting up hgwebdir.cgi”. I don’t know where to create the hg directory. In my /home/user/ or at /home/user/domain/ ?

  • 16 Install mercurial hg on remote server without root access | Programming Notes  Apr 23, 2012 at 10:33 am

    […] source: http://blog.tlensing.org/2010/04/12/installing-mercurial-on-a-shared-web-server-without-root-access-… […]

  • 17 eziscript.com  Apr 23, 2012 at 3:21 pm

    Cheers $author! Superb weblog! It’s almost like a game for me. It’s therefore valuable also usefull, appreciation many! If you submit more of this excellent clone php script, I’ll look around your site again.

  • 18 Installing Mercurial on your shared hosting account » Splatter  Jun 17, 2012 at 2:06 pm

    […] I had personally used this link but had found many instructions outdated, so updated them. http://blog.tlensing.org/2010/04/12/installing-mercurial-on-a-shared-web-server-without-root-access-…  Posted by admin at 5:36 […]

  • 19 Ethan Mallove  Nov 23, 2012 at 3:54 am

    Great non-root Mercurial installation HOWTO – thanks!

  • 20 Venkata Krishna Kotra  Mar 9, 2014 at 3:30 pm

    Sweet. Works well on hostgator

Leave a Comment

Before you comment: please be kind and save me some time by NOT posting inappropriate content. Example: if you're religious that's fine. But it doesn't belong here! Comments should generally be related to the topic of the article. Thanks!

© 2013 Tobis Lensing. All rights reserved. Powered by Wordpress — based upon Cutline by Chris Pearson. This page reflects the personal opinion of the author and is in no way linked to institutions the author is working or has worked for. For more information, see the disclaimer.