This documentation was written to describe Subversion 1.0. If you are running a newer version of Subversion, we strongly suggest that you visit http://www.svnbook.com/ and consult the version of this book appropriate for your version of Subversion.

svnserve, a custom server

The svnserve program is a lightweight server, capable of speaking to clients over TCP/IP using a custom, stateful protocol. Clients contact an svnserve server by using URLs that begin with the svn:// or svn+ssh:// schema. This section will explain the different ways of running svnserve, how clients authenticate themselves to the server, and how to configure appropriate access control to your repositories.

Invoking the Server

There a few different ways to invoke the svnserve program. If invoked with no options, you'll see nothing but a help message. However, if you're planning to have inetd launch the process, then you can pass the -i (--inetd) option:

$ svnserve -i
( success ( 1 2 ( ANONYMOUS ) ( edit-pipeline ) ) )

When invoked with the --inetd option, svnserve attempts to speak with a Subversion client via stdin and stdout using a custom protocol. This is the standard behavior for a program being run via inetd. The IANA has reserved port 3690 for the Subversion protocol, so on a Unix-like system you can add lines to /etc/services like these (if they don't already exist):

svn           3690/tcp   # Subversion
svn           3690/udp   # Subversion

And if your system is using a classic Unix-like inetd daemon, you can add this line to /etc/inetd.conf:

svn stream tcp nowait svnowner /usr/local/bin/svnserve svnserve -i

Make sure “svnowner” is a user which has appropriate permissions to access your repositories. Now, when a client connection comes into your server on port 3690, inetd will spawn an svnserve process to service it.

A second option is to run svnserve as a standalone “daemon” process. Use the -d option for this:

$ svnserve -d
$               # svnserve is now running, listening on port 3690

When running svnserve in daemon mode, you can use the --listen-port= and --listen-host= options to customize the exact port and hostname to “bind” to.

There's still a third way to invoke svnserve, and that's in “tunnel mode”, with the -t option. This mode assumes that a remote-service program such as RSH or SSH has successfully authenticated a user and is now invoking a private svnserve process as that user. The svnserve program behaves normally (communicating via stdin and stdout), and assumes that the traffic is being automatically redirected over some sort of tunnel back to the client. When svnserve is invoked by a tunnel agent like this, be sure that the authenticated user has full read and write access to the repository database files. (See Servers and Permissions: A Word of Warning.) It's essentially the same as a local user accessing the repository via file:/// URLs.

Once the svnserve program is running, it makes every repository on your system available to the network. A client needs to specify an absolute path in the repository URL. For example, if a repository is located at /usr/local/repositories/project1, then a client would reach it via svn://host.example.com/usr/local/repositories/project1 . To increase security, you can pass the -r option to svnserve, which restricts it to exporting only repositories below that path:

$ svnserve -d -r /usr/local/repositories
…

Using the -r option effectively modifies the location that the program treats as the root of the remote filesystem space. Clients then use URLs that have that path portion removed from them, leaving much shorter (and much less revealing) URLs:

$ svn checkout svn://host.example.com/project1
…

Built-in authentication and authorization

When a client connects to an svnserve process, the following things happen:

  • The client selects a specific repository.

  • The server processes the repository's conf/svnserve.conf file, and begins to enforce any authentication and authorization policies defined therein.

  • Depending on the situation and authorization policies,

    • the client may be allowed to make requests anonymously, without ever receiving an authentication challenge, OR

    • the client may be challenged for authentication at any time, OR

    • if operating in “tunnel mode”, the client will declare itself to be already externally authenticated.

At the time of writing, the server only knows how to send a CRAM-MD5 [21] authentication challenge. In essence, the server sends a bit of data to the client. The client uses the MD5 hash algorithm to create a fingerprint of the data and password combined, then sends the fingerprint as a response. The server performs the same computation with the stored password to verify that the result is identical. At no point does the actual password travel over the network.

It's also possible, of course, for the client to be externally authenticated via a tunnel agent, such as SSH. In that case, the server simply examines the user it's running as, and uses it as the authenticated username.

As you've already guessed, a repository's svnserve.conf file is the central mechanism for controlling authentication and authorization policies. The file has the same format as other configuration files (see the section called “Runtime Configuration Area”): section names are marked by square brackets ([ and ]), comments begin with hashes (#), and each section contains specific variables that can be set (variable = value). Let's walk through this file and learn how to use them.

Create a 'users' file and realm

For now, the [general] section of the svnserve.conf has all the variables you need. Begin by defining a file which contains usernames and passwords, and an authentication realm:

[general]
password-db = userfile
realm = example realm

The realm is a name that you define. It tells clients which sort of “authentication namespace” they're connecting to; the Subversion client displays it in the authentication prompt, and uses it as a key (along with the server's hostname and port) for caching credentials on disk (see the section called “Client Credentials Caching”.) The password-db variable points to a separate file that contains a list of usernames and passwords, using the same familiar format. For example:

[users]
harry = foopassword
sally = barpassword

The value of password-db can be an absolute or relative path to the users file. For many admins, it's easy to keep the file right in the conf/ area of the repository, alongside svnserve.conf. On the other hand, it's possible you may want to have two or more repositories share the same users file; in that case, the file should probably live in a more public place. The repositories sharing the users file should also be configured to have the same realm, since the list of users essentially defines an authentication realm. Wherever the file lives, be sure to set the file's read and write permissions appropriately. If you know which user(s) svnserve will run as, restrict read access to the user file as necessary.

Set access controls

There are two more variables to set in the svnserve.conf file: they determine what unauthenticated (anonymous) and authenticated users are allowed to do. The variables anon-access and auth-access can be set to the values none, read, or write. Setting the value to none restricts all access of any kind; read allows read-only access to the repository, and write allows complete read/write access to the repository. For example:

[general]
password-db = userfile
realm = example realm

# anonymous users can only read the repository
anon-access = read

# authenticated users can both read and write
auth-access = write

The example settings are, in fact, the default values of the variables, should you forget to define them. If you want to be even more conservative, you can block anonymous access completely:

[general]
password-db = userfile
realm = example realm

# anonymous users aren't allowed
anon-access = none

# authenticated users can both read and write
auth-access = write

Notice that svnserve only understands “blanket” access control. A user either has universal read/write access, universal read access, or no access. There is no detailed control over access to specific paths within the repository. For many projects and sites, this level of access control is more than adequate. However, if you need per-directory access control, you'll need to use Apache instead of svnserve as your server process.

SSH authentication and authorization

svnserve's built-in authentication can be very handy, because it avoids the need to create real system accounts. On the other hand, some administrators already have well-established SSH authentication frameworks in place. In these situations, all of the project's users already have system accounts and the ability to “SSH into” the server machine.

It's easy to use SSH in conjunction with svnserve. The client simply uses the svn+ssh:// URL schema to connect:

$ whoami
harry

$ svn list svn+ssh://host.example.com/repos/project
harry@host.example.com's password:  *****

foo
bar
baz
…

What's happening here is that the Subversion client is invoking a local ssh process, connecting to host.example.com, authenticating as the user harry, then spawning a private svnserve process on the remote machine, running as the user harry. The svnserve command is being invoked in tunnel mode (-t) and all network protocol is being “tunneled” over the encrypted connection by ssh, the tunnel-agent. svnserve is aware that it's running as the user harry, and if the client performs a commit, the authenticated username will be attributed as the author of the new revision.

When running over a tunnel, authorization is primarily controlled by operating system permissions to the repository's database files; it's very much the same as if Harry were accessing the repository directly via a file:/// URL. If multiple system users are going to be accessing the repository directly, you may want to place them into a common group, and you'll need to be careful about umasks. (Be sure to read the section called “Supporting Multiple Repository Access Methods”.) But even in the case of tunneling, the svnserve.conf file can still be used to block access, by simply setting auth-access = read or auth-access = none.

You'd think that the story of SSH tunneling would end here, but it doesn't. Subversion allows you to create custom tunnel behaviors in your run-time config file (see the section called “Runtime Configuration Area”.) For example, suppose you want to use RSH instead of SSH. In the [tunnels] section of your config file, simply define it like this:

[tunnels]
rsh = rsh

And now, you can use this new tunnel definition by using a URL schema that matches the name of your new variable: svn+rsh://host/path. When using the new URL schema, the Subversion client will actually be running the command rsh host svnserve -t behind the scenes. If you include a username in the URL (for example, svn+rsh://username@host/path) the client will also include that in its command (rsh username@host svnserve -t.) But you can define new tunneling schemes to be much more clever than that:

[tunnels]
joessh = $JOESSH /opt/alternate/ssh -p 29934

This example demonstrates a couple of things. First, it shows how to make the Subversion client launch a very specific tunneling binary (the one located at /opt/alternate/ssh) with specific options. In this case, accessing a svn+joessh:// URL would invoke the particular SSH binary with -p 29934 as arguments—useful if you want the tunnel program to connect to a non-standard port.

Second, it shows how to define a custom environment variable that can override the name of the tunneling program. Setting the SVN_SSH environment variable is a convenient way to override the default SSH tunnel agent. But if you need to have several different overrides for different servers, each perhaps contacting a different port or passing a different set of options, you can use the mechanism demonstrated in this example. Now if we were to set the JOESSH environment variable, its value would override the entire value of the tunnel variable—$JOESSH would be executed instead of /opt/alternate/ssh -p 29934.

A final note: when using svn+ssh:// URLs to access a repository, remember that it's the ssh program prompting you for authentication, and not the svn program. That means there's no automatic password caching going on (see the section called “Client Credentials Caching”). If you want to prevent ssh from repeatedly asking for your password, you'll need to use a separate memory-caching tool like ssh-agent on a Unix-like system, or pageant on Windows.



[21] See RFC 2195.