08 Feb 2007

Mac OS 10.4, Apache, Subversion

I recently set up a Subversion server on my Mac OS 10.4 MacBook Pro. It was, amongst other things, a test-run for installing SVN on an XServe. It was somewhat involved, so here’s my reminder on how to do this. Hopefully when 10.5 ships a lot of this will just go away.

The goal is to: install subversion, convert an existing CVS repository to SVN, set up Apache to access the repository, set up some access restrictions, and get it running over HTTPS. The starting point is that 10.4 ships with Apache 1.3, and I’d already installed a SVN client from a .dmg, but you need Apache 2 and to install Subversion from source to get the Apache SVN module compiled up, so that really doesn’t matter (the Mac OS 10.4 server, BTW, ships with an Apache 2.0 instance for “evaluation purposes”, but I’m going to ignore that as we want the latest and greatest Apache really).

My plan: install Apache in to ~/Applications/apache/2.2.4/ and SVN into ~/Applications/svn/1.4.3/ and to convert the CVS repository into a SVN one in ~/Developer/svn/BIG_PROJECT (obviously, adjust to your own tastes).

Here we go…

Step 0: You need the Apple Developer tools installed.

The next five steps are all concerned with cvs2svn.

Step 1: Install DarwinPorts (or is it MacPorts now?). Ports provides a way to download, compile and install open source projects into /opt. The DarwinPorts instructions are pretty clear: grab the Tiger .dmg installer and do the sudo port selfupdate thing. One gotcha here: the installer adds /opt/local/bin to your $PATH by adding a line to .profile. If you’ve got a .bash_profile already, you may find the .profile file being ignored, so adjust however you like so that /opt/local/bin:/opt/local/sbin ends up at the start of your $PATH. An echo $PATH will tell you if you’re good or not after install and starting a new shell.

Step 2: Install Berkeley DB, which you need for cvs2svn later. If you want you can skip this step and discover later if you need it, but I needed it. The command to perform this install is: sudo port install db42. Two confessions at this point. DarwinPorts understands dependencies and will go and get any additional packages required by db42, but I don’t know how many that will be for you because I’d already used Ports to install the latest version of Ruby which downloaded lots of packages. The second confession is that at the time I ran the above command, Ports wasn’t responding to my proxy configurations and it couldn’t download the package from the shell. To get around this I manually downloaded the package (db-4.2.52.tar.gz) in my browser and put it in /opt/local/var/db/dports/distfiles/db4/. If you have problems like this, running the port command with -v can help.

Step 3: Add Berkley DB support to Python, which is something required by cvs2svn as described by plasticfuture. The steps here are to grab the Python Berkeley DB bindings source (bsddb3-4.5.0.tar.gz for me), extract it and run:

$ python setup.py build --berkeley-db-libdir=/opt/local/lib/db42\
 --berkeley-db-incdir=/opt/local/include/db42

$ python setup.py install --berkeley-db-libdir=/opt/local/lib/db42\
 --berkeley-db-incdir=/opt/local/include/db42

Step 4: You’re now set to download and set up cvs2svn. I had a tar.gz of an existing CVS repository, which I unpacked to ~/Developer/oldcvs/BIG_PROJECT. You need to create a cvs2svn.options file to set up the conversion. I was going to create a new SVN repository, and you can download the cvs2svn.options I used (more or less… search for [CHANGE ME] in that file and fix it up for your own usage).

Step 5: Run the conversion with: cvs2svn-1.5.1/cvs2svn --options PATH_TO/cvs2svn.options. If you have a “big project” this may take a while, so while it’s running you might want to type the following to be told when it’s done: say Conversion Complete. I had a handful of errors about files existing in the repository and also in the Attic. I rm-ed the Attic versions of the files and re-ran the command.

Now that we have a converted CVS repository as a SVN repository we can continue and set up the server. Before that, I just did a sanity check with svn co file:///Users/richard/Developer/svn/BIG_PROJECT into /tmp or wherever to ensure there were no problems with the conversion (remember: I already had the SVN client installed, but if you don’t you’ll be able to do a test checkout around step 7, below).

Step 6: Install Apache. There’s a pretty nice Apple Developer article on Subversion and Apache which is worth a read. All I did in the end was to download Apache, unpack it, and run:\

$ ./configure --prefix=/Users/richard/Applications/apache/2.2.4 \
 --enable-mods-shared=most --enable-ssl --with-mpm=worker\
 --without-berkeley-db --enable-proxy\

The --without-berkeley-db is ironic after the BDB hoops we’ve jumped through above. The usual make and sudo make install and you’re done. Start apache with sudo ./apachectrl start from the ~/apache/2.2.4/bin directory and check that http://127.0.0.1/ is running and then stop Apache. (Warning: if you just run apachectrl you’ll pick up the Apple-installed Apache 1.3 instance, so remember to use the ./ or use the full path to the apachectrl for the Apache you’ve installed).

I ran into a few segmentation faults (or bus errors, depending on which user you run as) when starting up Apache. It turns out there are a couple of modules that fail to load or other issues in the configuration file. One useful way to see how far Apache is getting is to validate the configuration with debugging on: sudo bin/httpd -t -e DEBUG.

We’ll configure Apache later, but first…

Step 7: Install subversion. Again, the Apple Developer document above is helpful here. I downloaded the subversion source from subversion.tigris.org and ran…\

$ ./configure --prefix=/Users/richard/Applications/svn/1.4.3 --with-ssl
 --with-apxs=/Users/richard/Applications/apache/2.2.4/bin/apxs \
 --with-zlib --enable-swig-bindings=no --without-berkeley-db \
 --with-apr=/Users/richard/Applications/apache/2.2.4/ \
 --with-apr-util=/Users/richard/Applications/apache/2.2.4/\

…followed by make and sudo make install. If you don’t already have a Subversion client on your $PATH, you can add ~/Appliations/1.4.3/bin now.

If you’re going to go on to install Continuum or anything else that might require http or https support from the Subversion client, you’ll want to also download the Neon library as documented by The Punk Engineer and indeed also by the Subverison INSTALL text file.

Step 8: Configure Apache. Now comes the Apache voodoo to turn on SVN access. Edit ~/Applications/apache/2.2.4/conf/httpd.conf. (BTW, TextMate is quite nice for all of this, partly because it recognizes and colours Apache configuration, but also because from the shell you can run mate . to open all files in a nice folder view.) At the bottom of the Apache config add the following:

<IfModule dav\_svn\_module>
<Location /repos>
DAV svn
SVNPath /Users/richard/Developer/svn/BIG_PROJECT
</Location>
</IfModule>

Start Apache and in your browser you can hit http://127.0.0.1/repos to browse the source.

Step 10: Add authentication. Go back to httpd.conf and add in some form of authentication and access control. Here’s what I did…

<IfModule dav_svn_module>
<Location /repos>
DAV svn
SVNPath /Users/richard/Developer/svn/BIG_PROJECT
AuthzSVNAccessFile conf/svn-access.conf

Require valid-user
AuthType Basic
AuthName "Subversion Access"
AuthUserFile /Users/richard/Developer/svn/svn-pwd-file
</Location>
</IfModule>

There are two changes here. The first is a svn-access.conf file that controls what users or groups can do to parts of the repository. This file looks like this:

[groups]
dev = paul, gareth, richard, andrew, jono

[/]
@dev = rw

It’s saying there’s a group of users call “dev” to have read+write access to the “/” path in the repository (i.e., the lot). I wasn’t able to find a great deal of documentation on this, but thank you to Richard Tesh for spotting the archlinux.org guide.

The second part of the Apache configuration is the basic authentication part, which is straight-forward non-weird Apache stuff. The command you need is htpasswd: run it with -c the first time only to create the svn-pwd-file. Use this to create a username and password for each of your “dev” users.

Quit your browser, restart Apache, and try to hit the repository again: This time you’ll be prompted to login.

Step 11: Set up permissions on SVN repository. A gotcha here is that the Apache user (daemon, group daemon) needs write access to the repository, so you need to decide what you’re going to do there. One option is to chmod the repository, which is what I did.

Step 12: Finally you’ll want all of this to run over HTTPS, and so you’ll need to set up a certificate for Apache. I’m using a self-signed certificate. There’s some great documentation for this, including the ever-useful macosxhints.com. I created a folder in my home directory called keys, and from there I ran the following:

$ /System/Library/OpenSSL/misc/CA.pl -newca
$ openssl genrsa -des3 -out webserver.key 1024
$ openssl rsa -in webserver.key -out webserver.nopass.key
$ openssl req -config /System/Library/OpenSSL/openssl.cnf -new \
   -key webserver.key -out newreq.pem -days 3650
$ /System/Library/OpenSSL/misc/CA.pl -signreq

You’ll get prompted to enter a bunch of information. Use your hostname as the common name.

When those commands are done, you’ll have a set of files and a subdirectory in ~/keys. Now to configure Apache, by adding the following the httpd.conf:

<IfModule mod_ssl.c>
Listen 80
Listen 443

<VirtualHost _default:443>
SSLEngine on
ServerName 127.0.0.1
SSLRequireSSL

SSLCipherSuite ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM: \
 +LOW:+SSLv2:+EXP:+eNULL
SSLCertificateFile /Users/richard/keys/newcert.pem
SSLCertificateKeyFile /Users/richard/keys/webserver.nopass.key
SSLCACertificateFile /Users/richard/keys/demoCA/cacert.pem
SSLCARevocationPath /Users/richard/keys/demoCA/crl
</VirtualHost>

</IfModule>

Restart Apache and you can now hit https://127.0.0.1/repos/BIG_PROJECT or enter that into whatever tool you use to access subversion, such as an Eclipse plugin. You’ll be told the certificate isn’t recognized, but just “continue” or “OK” or “accept” your way past that. BTW, if you try to hit the non-HTTPS URL, you’ll be forbidden.

Aaaaaaaaand we’re done. Apart from backups, more sensible security, better file naming, multiple repositories, automated builds….

Thank you: Paul, Pragmatic Version Control Using Subversion and all the HOW TOs I’ve not mentioned.