A Private Mac Mercurial Server with SSH Key Authentication

Now, a private Mac Mercurial server with SSH key authentication was set up.

I already pushed my main project to the server and updated it at the server side, so repository migration has started without a hitch. But I didn't migrate the subprojects of the main project and some lingering/untended/rogue projects to the server, because they have their own choices of VCSs or none at all: I already smells a trouble, a delicious one. I know there are inter-VCS plugins out there for Mecurial, I'm looking forward using them.

So, assuming you have an administrative privilege, here are instructions of how to set up a private SSH Mercurial server.

Equip Yourself Head to Toe

First, install MacPorts at the server side. That will save a lot and lot of time in the future. If you prefer, you can also get a GUI app for MacPorts, such as Porticus or Pallet. But personally, if you decided to put yourself into these sever thingies, you should get accustomed to CLI: these GUI apps do not provide all the info CLI can provide.

After the installation, in Terminal.app at the server side, type:
sudo port selfupdate
sudo port install mercurial +bash_completion
sudo mkdir -p <repo_base_dir>
sudo chown -R <username> <repo_base_dir>
sudo chmod 750 <repo_base_dir>
  1. Updates the MacPorts system.
  2. Install Mercurial with a Bash command completion capability.
  3. Create a base directory <repo_base_dir> to contain Mercurial central repositories (e.g. ~/hg-repos).
  4. Change the ownership of the base directory tree to <username>. Because this is for a private Mercurial server setup, <username> can just be your account's user name at the server side.
  5. Change the permission of <repo_base_dir>. The owner (you) have full permission, group have only read and execute permissions, and the other does not have any permission at all.

You Got My Back, SSH

System Preferences » Sharing

Now, go to System Preferences » Sharing, and turn on "Remote Login." It will make OS maintain a SSH daemon, meaning SSH becomes active. And now, SFTP is also active.

Now, back to the client side. Password authentication is considered highly insecure, so let's use public/private key authentication: it's something like a split tally in a digital and non-human-friendly form.
cp -R ~/.ssh ~/.ssh.bk
cd ~/.ssh
ssh-keygen -t rsa -b 8192
/usr/bin/ssh-add -K <path_to_private_key_file>
  1. Create a backup of SSH resources for precaution. If "~/.ssh" does not exist, create one by mkdir ~/.ssh.
  2. Change the current directory to "~/.ssh" .
  3. Start a ssh-keygen interactive session creating a 8192-bit RSA key pair. Key generation takes some time, so be patient here (it's not alarmingly long though). When you are asked the base filename for private and public key files, you can just use the default, or distinguish it from ones from existing key pairs. And finally, set a passphrase for an additional security.
  4. Register the generated RSA key pair to the SSH authentication agent. You are asked to type the passphrase of the RSA key pair, and hopefully this will be the last time you type it: it's registered to Mac OS X's "Keychain Access.app," saving us from typing it system-wide (Mac OS X 10.5 Leopard or later?).

Now, you should have a public key file (e.g. id_rsa.pub). Execute the following command:
sftp <remote_host_user_name>@<hg_server>
cd ~/.ssh
put <pub_key_file>
  1. Start a SFTP session. <remote_host_user_name> must be the user name you chose at the line 4 of the previous snippet. <hg_server> is the host name or IP address of the Mercurial server.
  2. Change the current directory to "~/.ssh" . If it does not exist, create one by mkdir ~/.ssh.
  3. Upload the public key file <pub_key_file> to the Mercurial server.
  4. Exit the SFTP session.

Final Push

So, the end is nigh.
ssh <remote_host_user_name>@<hg_server>
cp -R ~/.ssh ~/.ssh.bk
cd ~/.ssh
cat <pub_key_file> >> authorized_keys
sudo perl -i.bk -pe "s/^[#\s\t]*(RSAAuthentication|PubkeyAuthentication)[\t\s]+(yes|no)/\1 yes/; s/^[#\s\t]*(AuthorizedKeysFile)[\t\s]+.*/\1 \.ssh\/authorized_keys/" /etc/sshd_config
  1. Start a SSH session just like the last SFTP session.
  2. Again like in the client side, backup "~/.ssh" for precaution.
  3. Change the current directory to "~/.ssh" .
  4. Concatenate the public key file <pub_key_file> to the end of "authorized_keys" .
  5. Edit the configuration file of the SSH daemon using Perl's regex functionality. Authentication using a RSA key is enabled, and the file containing public keys of authorized users is specified. The old configuration file is backed up with name suffix ".bk" .
  6. Exit the SSH session.

Phew, finally!
Now, you can use something like the following:
hg init ssh://<username>@<hg_server>/<base_path>/<new_repo>
hg clone ssh://<username>@<hg_server>/<base_path>/<repo>

A relative or absolute path can be used in <base_path>. For a relative path, the working directory is the home directory of <username>. When you use an absolute path, it will look like ssh://Shig@hg-server.org//Users/Shig/hg-repos/test.hg.

Hmm, I feel something's missing. Oh yeah, a conclusion… Ahem, this is the end of this article.


Popular posts from this blog

Hardcoding Data Like Images and Sounds into HTML or CSS

DDS for GIMP (Mountain Lion, Native, no X11 GUI)

Make It Work: Global .gitattributes