Full-service Internet Marketing & Web Development
Recent Posts

Sponsors
![]() |
How to serve Mercurial HG repository over NGinxAdrian Singer, 09-03-2009 |
Mercurial server can be setup in two modes:
* hg serve - a built in lightweight web server that is provided as part of the Mercurial package. hg serve can be used to quickly serve a single repository, but it's not a good choice for production systems.
hg serve doesn't support user authentication, multiple repositories and is limited to handling a single connection at a time.
* hgweb.cgi - a Python script that is faster, supports user authentication, multiple repositories, styles and web console.
As part of this post I'll walk you through setting up hgweb.cgi on an NGinx web server.
Step 1 - Install Python
Step 2 - Install hgweb.cgi
Save this file under your web server main direcory.
hgweb.cgi:
Replace /home/admin/htdocs/ with your web server folder
Step 3 - Configure hgweb
Save this config file under your web server main directory.
hgweb.config:
Replace mydomain with your web server url
Create this global settings file under /etc/mercurial/hgrc:
Step 4 - Install Spawn-fcgi
Before we can tell NGinx to handle the hgweb.cgi Python script, we have to install spawn-fcgi
Follow these steps:
Start spawn-fcgi:
Try running hgweb.cgi by issuing: python hgweb.cgi
If you get a message about missing flup, you'll have to download flup and install it:
--
Now create a new file under /usr/local/etc/rc.d/start-spawnfcgi.sh to start spawn-fcgi automatically after a reboot.
Save the same line above under /usr/local/etc/rc.d/start-spawnfcgi.sh
Step 5 - Configure NGinx
Add this to your nginx.conf, replacing mydomain.com with your web server domain name and 1.2.3.4 with the dedicated ip address:
Note that we are password protecting the repository by using an .htpasswd file. You can generate one using publicly available htpasswd generators like this one.
Tell NGinx to reload its configuration file:
If all goes well, you should be able to point your browser to mydomain.com and see a list of Mercurial repositories.
* hg serve - a built in lightweight web server that is provided as part of the Mercurial package. hg serve can be used to quickly serve a single repository, but it's not a good choice for production systems.
hg serve doesn't support user authentication, multiple repositories and is limited to handling a single connection at a time.
* hgweb.cgi - a Python script that is faster, supports user authentication, multiple repositories, styles and web console.
As part of this post I'll walk you through setting up hgweb.cgi on an NGinx web server.
Step 1 - Install Python
cd /usr/ports/lang/python25
make all install
make all install
Step 2 - Install hgweb.cgi
Save this file under your web server main direcory.
hgweb.cgi:
#!/usr/bin/env python
import cgitb
from mercurial.hgweb.hgwebdir_mod import hgwebdir
from mercurial.hgweb.request import wsgiapplication
from flup.server.fcgi import WSGIServer
cgitb.enable()
def make_web_app():
return hgwebdir("/home/admin/htdocs/hgweb.config")
WSGIServer(wsgiapplication(make_web_app)).run()
import cgitb
from mercurial.hgweb.hgwebdir_mod import hgwebdir
from mercurial.hgweb.request import wsgiapplication
from flup.server.fcgi import WSGIServer
cgitb.enable()
def make_web_app():
return hgwebdir("/home/admin/htdocs/hgweb.config")
WSGIServer(wsgiapplication(make_web_app)).run()
Replace /home/admin/htdocs/ with your web server folder
Step 3 - Configure hgweb
Save this config file under your web server main directory.
hgweb.config:
[ui]
username = root
editor = vim
[hooks]
changegroup = hg update >&2
[web]
baseurl =/.
style= gitweb
push_ssl = false
allow_push = *
[paths]
Clients = /home/
SPI = /home/admin/htdocs/
username = root
editor = vim
[hooks]
changegroup = hg update >&2
[web]
baseurl =/.
style= gitweb
push_ssl = false
allow_push = *
[paths]
Clients = /home/
SPI = /home/admin/htdocs/
Replace mydomain with your web server url
Create this global settings file under /etc/mercurial/hgrc:
[web]
style= gitweb
style= gitweb
Step 4 - Install Spawn-fcgi
Before we can tell NGinx to handle the hgweb.cgi Python script, we have to install spawn-fcgi
Follow these steps:
wget "http://www.lighttpd.net/download/spawn-fcgi-1.6.2.tar.gz"
tar -xvf spawn-fcgi-1.6.2.tar.gz
cd spawn-fcgi-1.6.2
./configure
make all
make install
tar -xvf spawn-fcgi-1.6.2.tar.gz
cd spawn-fcgi-1.6.2
./configure
make all
make install
Start spawn-fcgi:
/usr/local/bin/spawn-fcgi -f /home/code/hgweb.cgi -a 127.0.0.1 -p 8081
Try running hgweb.cgi by issuing: python hgweb.cgi
If you get a message about missing flup, you'll have to download flup and install it:
wget "http://www.saddi.com/software/flup/dist/flup-1.0.1.tar.gz"
tar -xvf flup-1.0.1.tar.gz
cd flup-1.0.1
python setup.py install
tar -xvf flup-1.0.1.tar.gz
cd flup-1.0.1
python setup.py install
--
Now create a new file under /usr/local/etc/rc.d/start-spawnfcgi.sh to start spawn-fcgi automatically after a reboot.
Save the same line above under /usr/local/etc/rc.d/start-spawnfcgi.sh
Step 5 - Configure NGinx
Add this to your nginx.conf, replacing mydomain.com with your web server domain name and 1.2.3.4 with the dedicated ip address:
server {
listen 1.2.3.4:80;
server_name mydomain.com;
server_name_in_redirect off;
auth_basic "Restricted";
auth_basic_user_file /home/hg/.htpasswd;
gzip on;
location / {
root /home/hg/;
index index.php index.html index.htm;
fastcgi_pass 127.0.0.1:8081;
fastcgi_param SCRIPT_FILENAME /home/hg/$fastcgi_script_name;
include /etc/nginx/fastcgi_top.conf;
fastcgi_param DOCUMENT_ROOT /home/hg/;
include /etc/nginx/fastcgi_bottom.conf;
fastcgi_param QUERY_STRING $query_string;
fastcgi_param REQUEST_METHOD $request_method;
fastcgi_param CONTENT_TYPE $content_type;
fastcgi_param CONTENT_LENGTH $content_length;
}
}
listen 1.2.3.4:80;
server_name mydomain.com;
server_name_in_redirect off;
auth_basic "Restricted";
auth_basic_user_file /home/hg/.htpasswd;
gzip on;
location / {
root /home/hg/;
index index.php index.html index.htm;
fastcgi_pass 127.0.0.1:8081;
fastcgi_param SCRIPT_FILENAME /home/hg/$fastcgi_script_name;
include /etc/nginx/fastcgi_top.conf;
fastcgi_param DOCUMENT_ROOT /home/hg/;
include /etc/nginx/fastcgi_bottom.conf;
fastcgi_param QUERY_STRING $query_string;
fastcgi_param REQUEST_METHOD $request_method;
fastcgi_param CONTENT_TYPE $content_type;
fastcgi_param CONTENT_LENGTH $content_length;
}
}
Note that we are password protecting the repository by using an .htpasswd file. You can generate one using publicly available htpasswd generators like this one.
Tell NGinx to reload its configuration file:
kill -HUP `cat /usr/local/nginx/logs/nginx.pid`
If all goes well, you should be able to point your browser to mydomain.com and see a list of Mercurial repositories.
![]() |
Mike Peters, 10-29-2009 |
While you can force your developers to always go through Mercurial when uploading changes, from time to time, engineers may connect to the server directly via FTP/SSH and update files.
If the server is a client website, chances are the client's engineers and graphic designers will upload changes directly to the server via FTP.
When this happens, we'd like to ensure the new files are stored in Mercurial, just as if someone uploaded a new revision. This way, nothing gets overwritten and you always have a history of all changes.
The way to do this automatically, is to install a cronjob that wakes up every 30 minutes and commits any new changes automatically.
Add this line to your cronjob:
Contents of hg-update.sh:
Update with your folder names and you'd be all set. Now even when files are updated outside of Mercurial, they will be picked up and stored so that nothing ever gets lost.
If the server is a client website, chances are the client's engineers and graphic designers will upload changes directly to the server via FTP.
When this happens, we'd like to ensure the new files are stored in Mercurial, just as if someone uploaded a new revision. This way, nothing gets overwritten and you always have a history of all changes.
The way to do this automatically, is to install a cronjob that wakes up every 30 minutes and commits any new changes automatically.
Add this line to your cronjob:
# Commit local file changes, every 30 minutes
*/30 * * * * /home/hg-update.sh
*/30 * * * * /home/hg-update.sh
Contents of hg-update.sh:
cd /home/myfolder/
/usr/local/bin/hg add
/usr/local/bin/hg commit -u "root" -m "Local File Changes"
/usr/local/bin/hg add
/usr/local/bin/hg commit -u "root" -m "Local File Changes"
Update with your folder names and you'd be all set. Now even when files are updated outside of Mercurial, they will be picked up and stored so that nothing ever gets lost.
![]() |
Dawn Rossi, 10-29-2009 |
The script below will install Mercurial HG, hgweb.cgi, Python flup and hg config files. Just enter your repository name and full path under repName,repFolder and run this script.
### Update this section with the folder and name of your repository
repName = "My Stuff"
repFolder = "/home/mystuff"
###
# Install Mercurial
cd /usr/ports/devel/mercurial
make all
make install
# Install spawn-fgi
cd /usr/home
mkdir temp
cd temp
wget "http://www.lighttpd.net/download/spawn-fcgi-1.6.2.tar.gz"
tar -xvf spawn-fcgi-1.6.2.tar.gz
cd spawn-fcgi-1.6.2
./configure
make all
make install
# Install Python Flup
cd /usr/home/temp
wget "http://www.saddi.com/software/flup/dist/flup-1.0.1.tar.gz"
tar -xvf flup-1.0.1.tar.gz
cd flup-1.0.1
python setup.py install
# Install hgweb.cgi
mkdir /home/hg
cd /home/hg
echo "#\!/usr/bin/env python" >> hgweb.cgi
echo "" >> hgweb.cgi
echo "import cgitb" >> hgweb.cgi
echo "from mercurial.hgweb.hgwebdir_mod import hgwebdir" >> hgweb.cgi
echo "from mercurial.hgweb.request import wsgiapplication" >> hgweb.cgi
echo "from flup.server.fcgi import WSGIServer" >> hgweb.cgi
echo "" >> hgweb.cgi
echo "cgitb.enable()" >> hgweb.cgi
echo "" >> hgweb.cgi
echo "def make_web_app():" >> hgweb.cgi
echo " return hgwebdir('/home/hg/hgweb.config')" >> hgweb.cgi
echo "" >> hgweb.cgi
echo "WSGIServer(wsgiapplication(make_web_app)).run()" >> hgweb.cgi
chmod a+x hgweb.cgi
echo "[ui]" >> hgweb.config
echo "username = root" >> hgweb.config
echo "editor = vim" >> hgweb.config
echo "" >> hgweb.config
echo "[hooks]" >> hgweb.config
echo "changegroup = hg update >&2" >> hgweb.config
echo "" >> hgweb.config
echo "[web]" >> hgweb.config
echo "baseurl =/." >> hgweb.config
echo "style= gitweb" >> hgweb.config
echo "push_ssl = false" >> hgweb.config
echo "allow_push = *" >> hgweb.config
echo "" >> hgweb.config
echo "[paths]" >> hgweb.config
echo "$repName = $repFolder" >> hgweb.config
mkdir /etc/mercurial
echo "[web]" >> /etc/mercurial/hgrc
echo "style= gitweb" >> /etc/mercurial/hgrc
# Start spawn-fcgi
/usr/local/bin/spawn-fcgi -f /home/hg/hgweb.cgi -a 127.0.0.1 -p 8081
echo "/usr/local/bin/spawn-fcgi -f /home/hg/hgweb.cgi -a 127.0.0.1 -p 8081" >> /usr/local/etc/rc.d/start-spawnfcgi.sh
# Install cronjob
echo "# Commit local file changes, every 30 minutes" >> /var/cron/tabs/root
echo "*/30 * * * * /home/hg/hg-update.sh" >> /var/cron/tabs/root
# Install update file and run it
echo "cd '$repFolder'" >> /home/hg/hg-update.sh
echo "/usr/local/bin/hg add" >> /home/hg/hg-update.sh
echo "/usr/local/bin/hg commit -u 'root' -m 'Local file changes'" >> /home/hg/hg-update.sh
chmod a+x hg-update.sh
./hg-update.sh
repName = "My Stuff"
repFolder = "/home/mystuff"
###
# Install Mercurial
cd /usr/ports/devel/mercurial
make all
make install
# Install spawn-fgi
cd /usr/home
mkdir temp
cd temp
wget "http://www.lighttpd.net/download/spawn-fcgi-1.6.2.tar.gz"
tar -xvf spawn-fcgi-1.6.2.tar.gz
cd spawn-fcgi-1.6.2
./configure
make all
make install
# Install Python Flup
cd /usr/home/temp
wget "http://www.saddi.com/software/flup/dist/flup-1.0.1.tar.gz"
tar -xvf flup-1.0.1.tar.gz
cd flup-1.0.1
python setup.py install
# Install hgweb.cgi
mkdir /home/hg
cd /home/hg
echo "#\!/usr/bin/env python" >> hgweb.cgi
echo "" >> hgweb.cgi
echo "import cgitb" >> hgweb.cgi
echo "from mercurial.hgweb.hgwebdir_mod import hgwebdir" >> hgweb.cgi
echo "from mercurial.hgweb.request import wsgiapplication" >> hgweb.cgi
echo "from flup.server.fcgi import WSGIServer" >> hgweb.cgi
echo "" >> hgweb.cgi
echo "cgitb.enable()" >> hgweb.cgi
echo "" >> hgweb.cgi
echo "def make_web_app():" >> hgweb.cgi
echo " return hgwebdir('/home/hg/hgweb.config')" >> hgweb.cgi
echo "" >> hgweb.cgi
echo "WSGIServer(wsgiapplication(make_web_app)).run()" >> hgweb.cgi
chmod a+x hgweb.cgi
echo "[ui]" >> hgweb.config
echo "username = root" >> hgweb.config
echo "editor = vim" >> hgweb.config
echo "" >> hgweb.config
echo "[hooks]" >> hgweb.config
echo "changegroup = hg update >&2" >> hgweb.config
echo "" >> hgweb.config
echo "[web]" >> hgweb.config
echo "baseurl =/." >> hgweb.config
echo "style= gitweb" >> hgweb.config
echo "push_ssl = false" >> hgweb.config
echo "allow_push = *" >> hgweb.config
echo "" >> hgweb.config
echo "[paths]" >> hgweb.config
echo "$repName = $repFolder" >> hgweb.config
mkdir /etc/mercurial
echo "[web]" >> /etc/mercurial/hgrc
echo "style= gitweb" >> /etc/mercurial/hgrc
# Start spawn-fcgi
/usr/local/bin/spawn-fcgi -f /home/hg/hgweb.cgi -a 127.0.0.1 -p 8081
echo "/usr/local/bin/spawn-fcgi -f /home/hg/hgweb.cgi -a 127.0.0.1 -p 8081" >> /usr/local/etc/rc.d/start-spawnfcgi.sh
# Install cronjob
echo "# Commit local file changes, every 30 minutes" >> /var/cron/tabs/root
echo "*/30 * * * * /home/hg/hg-update.sh" >> /var/cron/tabs/root
# Install update file and run it
echo "cd '$repFolder'" >> /home/hg/hg-update.sh
echo "/usr/local/bin/hg add" >> /home/hg/hg-update.sh
echo "/usr/local/bin/hg commit -u 'root' -m 'Local file changes'" >> /home/hg/hg-update.sh
chmod a+x hg-update.sh
./hg-update.sh
![]() |
Mike Peters, 12-05-2009 |
Update:
Make sure you install the Forbid_2head hook on your live repository, or you'll have major issues merging changes locally.
Make sure you install the Forbid_2head hook on your live repository, or you'll have major issues merging changes locally.
|
|
Subscribe Now to receive new posts via Email as soon as they come out.
Comments
Post your comments



