Serving svn on Mountain Lion - OS X 10.8

With the move to Mountain Lion, Apple removed apache web hosting from System Preferences. This demotion of apache's httpd daemon on Mac OS X prompted me to start learning how to host svn repositories over alternative protocols such as svn+ssh:// and svn://.

With the move to Mountain Lion, Apple removed apache web hosting from System Preferences. This demotion of apache’s httpd daemon on Mac OS X prompted me to start learning how to host svn repositories over alternative protocols such as svn+ssh:// and svn://.

Before OS X 10.8, aka Mountain Lion, I had set up svn repositories running on a Mac being accessed by the http protocol. Users accessed the repositories using commands and URLS that looked like svn co http://mac-pro.local/svn/petproject/trunk. This set up relied on apache httpd and involved adding to the httpd configuration files.

With the introduction of Mountain Lion, Apple signalled the end of a supported standardised web server (httpd) on the standard installation of Mac OS X. The easy single click interface in the System Preference was gone and any customisations of apache httpd configuration files where lost during the upgrade from Mac OS X 10.7 (Lion) to OS X 10.8 (Mountain Lion).

Rather than set about recreating my previous structure, I searched for an alterative method less likely to be affected by future OS X updates.

Version Control with Subversion has a good chapter covering the possibilities.

Subversion Tunnelling Over ssh

I took a fancy to the svn+ssh protocol and felt it would be a good enough fit for my needs. This method avoids opening another socket, avoids needing a dedicated server process, and makes use of the existing ssh infrastructure. As a bonus, Apple is unlikely to reduce OS X’s ssh support any time soon.

With the svn+ssh protocol there is very little to configure. If the svn repository files have the appropriate file permissions, users can switch over to using a modified URL immediately. What was http://mac-pro.local/svn/petproject/trunk would become svn+ssh://mac-pro.local/``/petproject/trunk.

Testing this protocol quickly raised two problems; users are asked for their password too frequently and users can check out projects but not check in changes.

Remote users could immediately check out projects because they had read access to the repositories but they lacked write permissions. Trying to check in changes led to permission errors.

This checking in problem was because of the restrictive file and folder permissions I had on the svn repositories. I was not willing to relax these file restrictions.

The other problem, removing the need for an ssh password, is a well covered topic. This requires setting up a public and private key pair.

I needed a way allow to remote access to the repositories without passwords but without granting full rights to the svn project files. I needed to maintain control who could access and modify what files.

Adding a public and private key pair would solve only half the problem. Thankfully the Subversion book provides a hint at what is possible and James Gardner has shared an excellent walk through on how to set up such an environment for the Debian operating system.

This method looks good but as I worked through the steps I realised I needed a dedicated svn user with a home directory I could save the ssh public keys to. That was not something I had in place. An svn user called _svn exists on OS X 10.8 but it is hidden and has no home folder.

$ finger svn
Login: _svn                     Name: SVN Server
Directory: /var/empty                   Shell: /usr/bin/false
Never logged in.
No Mail.
No Plan.

Subversion as a Service

An alternative approach is to provide a dedicated service to handle incoming svn network requests. On OS X 10.8, such services are handled by launchd. Thankfully once again the Subversion book was an excellent starting point.

I used the following launchd job ticket as a starting point. Note the --root path passed to svnserve. This is an absolute path to a folder of svn projects; it is not a single svn project.

For OS X 10.8, I had to update the user and group name from svn to _svn.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
	"http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
	<dict>
		<key>Label</key>
		<string>org.apache.subversion.svnserve</string>
		<key>ServiceDescription</key>
		<string>Host Subversion repositories using svn:// scheme</string>
		<key>ProgramArguments</key>
		<array>
			<string>/usr/bin/svnserve</string>
			<string>--inetd</string>
			<string>--root=/Volumes/Documents/svn</string>
			<string>--config-file=/Volumes/Documents/svn.conf</string>
		</array>
		<key>UserName</key>
		<string>_svn</string>
		<key>GroupName</key>
		<string>_svn</string>
		<key>inetdCompatibility</key>
		<dict>
			<key>Wait</key>
			<false/>
		</dict>
		<key>Sockets</key>
		<dict>
			<key>Listeners</key>
			<array>
				<dict>
					<key>SockServiceName</key>
					<string>svn</string>
					<key>Bonjour</key>
					<true/>
				</dict>
			</array>
		</dict>
	</dict>
</plist>

Creating a svnserve launchd job ticket

  1. Create a text file containing the property list contents above.

  2. Customise the --root and --config-file paths to point to your svn folder of projects and configuration.

  3. Save the file as org.apache.subversion.svnserve.plist

  4. Copy the file into /Library/LaunchDaemons/.

  5. Change the ownership of the file to root:wheel and the permissions to -rw-r–r–:

    sudo chown root:wheel /Library/LaunchDaemons/org.apache.subversion.svnserve.plist
    sudo chmod 644 /Library/LaunchDaemons/org.apache.subversion.svnserve.plist
    
  6. Load the launchd job ticket:

    sudo launchctl load /Library/LaunchDaemons/org.apache.subversion.svnserve.plist
    

Warning asking to allow svnserver to accept incoming connections

Warning asking to allow svnserver to accept incoming connections

Not Ideal

/usr/bin/svnserve is included and works on OS X 10.8 but is not secure enough for my needs. I want all connections between users and the repositories to be encrypted and passwords to be stored in a hashed form on the server. Neither of these requirements are provided by default.

This will be a topic to revisit. I expect I will be returning to explore svn+ssh further.