Setting up a Secure Subversion Serverby Dru Lavigne, author of BSD Hacks
Recently a client hired a team of web developers to assist his overworked web administrator. They asked me to set up a revision-control system to ensure that no one on the team inadvertently overwrote another member's work and to give the administrator the flexibility of rolling back to any version of a file.
My first thought was Subversion, as it is the revisioning system I used with my editor when writing BSD Hacks A search for subversion in the Ports Collection indicated that there are also several related ports. For example, esvn looked like an excellent match for the client, as this GUI front end works from Unix, Mac OS X, and Windows. That's perfect for a web development team short on Unix skills who would be accessing data stored on a FreeBSD server from non-FreeBSD operating systems.
This week's article demonstrates how to create a secure repository using Subversion. The next installment will show how to train your users to access the repository using a GUI client.
Preparing the System
In my scenario, it was important that only the members of the development team have access to the repository. We also chose to have the repository on a system separate from the actual web server and left it up to the web administrator to copy over files from the repository to the web server as he saw fit.
To accomplish this, start by creating a backup of the existing directory
structure you wish to put under revision control, and send it securely to the
repository server. In my case, I backed up the
www data on the web server to an
internal server at 192.168.2.2.
# tar czvf - /usr/local/etc/www/data | ssh email@example.com "cat > www.tar.gz"
Next, on the repository system, create a new group called
and add to it any existing user accounts that need access to the repository.
For example, I added my existing web administrator as I created the group by
adding this line to /etc/group:
# vi /etc/group svn:*:3690:webadmin
Then, create a new user called
svn and, if necessary, any
missing user accounts that need access to the repository. Make sure each
account is a member of the
svn group and has a password and a
valid shell. I used
sysinstall to create user accounts for the new
web developers. When I finished, I double-checked the membership of the
svn group. It looked something like this:
# grep svn /etc/group svn:*:3690:webadmin,devel1,devel2
Before installing Subversion, take a close look at the existing
umask for the
svn user. On my FreeBSD system it was:
# su -l svn % umask 022
In Unix, the
umask value determines the default permissions of
a newly created directory or file. It does this by defining which permissions
to disable. If you remember:
r = 4 w = 2 x = 1
you'll see that this
umask doesn't turn off any (0) permissions
for the user (
svn); it turns off write (2) for the group
svn); and it turns off write (2) for world.
Because the members of the
svn group should be able to write to
the repository, change that group
2 to a
0. If you don't want nongroup members
even to be aware of the existence of the repository, also change the world
The easy part is changing the
umask for the
user's shell. If it uses
% vi ~svn/.cshrc
then find the existing
umask line and change it to either
svn user has a shell other than
your edit in your chosen shell's configuration file.
Once you've saved your changes to ~svn/.cshrc (or wherever), don't forget to tell the shell:
% source ~svn/.cshrc
umask command to verify that your changes have taken
Installing Subversion with the correct
If you chose a
002, you can compile a wrapper into
Subversion when you build it from the ports collection. If you chose a
007 or prefer to install the precompiled version of
Subversion, create a wrapper script to ensure that the Subversion binaries use
To compile in a wrapper that sets a
# cd /usr/ports/devel/subversion # make -DWITH_SVNSERVE_WRAPPER install clean
Alternatively, to install the precompiled binary:
# pkg_add -r subversion
Note: before installing by either method, finish reading the article. You may find some additional compile options that interest you.
If you didn't compile in your wrapper, move your existing binary and create your own wrapper script:
# mv /usr/local/bin/svn /usr/local/bin/svn.orig
# vi /usr/local/bin/svn #!/bin/sh #wrapper script to set umask to 007 on subversion binaries umask 007 /usr/local/bin/svn.orig "$@"
umask to either
007 so that it is the same as
umask for your
Don't forget to make your wrapper script executable:
# chmod +x /usr/local/bin/svn
Creating the Repository
Now that your environment is set up properly, you're ready to create the
repository itself. Log in as the user
svn to ensure that both the
svn user and the
svn group own the files you create
in the repository. From /usr/home/svn/, type:
% svnadmin create repository
In this example, I've called my repository
repository. You can
choose any name that is useful to you.
svnadmin create simply creates the directory infrastructure
required by the Subversion tools:
% ls -F repository README.txt dav/ format locks/ conf/ db/ hooks/
db directory? By default, Subversion uses
databases to track changes to the files that you place under revision control.
This means that you must import your data into those databases.
At that point, I untarred my backup so that I had some data to import. If you do this, don't restore directly into the ~svn/repository directory. (It's a database, remember?) Instead, I first made a new directory structure:
% pwd /usr/home/svn % mkdir www && cd www % mkdir branches tags trunk % cd trunk % tar xzvf /full/path/to/www.tar.gz . % cd
That made the
svn user's home directory look like:
% ls -F ~svn repository/ www/
Importing the Data
Next, it's time to import the information from
the Subversion databases. To do so, use the
svn import command:
% svn import www file:///usr/home/svn/repository/www -m "initial import"
svn import is one of many
svn commands available
to users. Type
svn help to see the names of all the available
commands. If you insert one of those commands between
help, as in
svn import help, you'll receive help on
the syntax for that specified command.
svn import, specify the name of the directory containing
the data to import (
www). Your data doesn't have to be in the same
directory; simply specify the full path to the data, but ensure that your
svn user has permission to access the data you wish to import.
Note: once you've successfully imported your data, you don't have to keep an
original copy on disk. In my case, I issued the command
Next, notice the syntax I used when specifying the full path to the
repository. Subversion supports multiple URL schemas or "repository access" RA
modules. Verify which schemas your
svn supports with:
% svn --version svn, version 1.1.3 (r12730) compiled Mar 20 2005, 11:04:16 Copyright (C) 2000-2004 CollabNet. Subversion is open source software, see http://subversion.tigris.org/ This product includes software developed by CollabNet (http://www.Collab.Net/). The following repository access (RA) modules are available: * ra_dav : Module for accessing a repository via WebDAV (DeltaV) protocol. - handles 'http' schema - handles 'https' schema * ra_local : Module for accessing a repository on local disk. - handles 'file' schema * ra_svn : Module for accessing a repository using the svn network protocol. - handles svn schema
Because I wished to access the repository on the local disk, I used the
file:/// schema. I also appended
www at the very end
of the URL, as I wish that particular part of the repository to be available by
that name. Yes, you can import multiple directory structures into the same
Subversion repository, so give each one a name that is easy for you and your
users to remember.
Finally, I used the
-m message switch to append the comment
"initial import" to the repository log. If I hadn't included this switch,
svn would have opened the log for me in the user's default editor
vi) and asked me to add a comment before continuing.
This is a very important point. The whole reason to install a revision
control system is to allow multiple users to modify files, possibly even
simultaneously. It's up to each user to log clearly which changes they made to
which files. It's your job to make your users aware of the importance of adding
useful comments whenever an
svn command prompts them to do so.
Deciding Upon a URL Schema
Congratulations! You now have a working repository. Now's the best time to take a closer look at the various URL schemas and choose the access method that best suits your needs.
Chapter 6 of the freely available e-book Version Control with
Subversion gives details about the possible configurations. You can choose
to install the book when you compile the FreeBSD port by adding
-DWITH_BOOK to your
If all of your users log in to the system either locally or through
ssh, use the
file:/// schema. Because users are
"local" to the repository, this scenario doesn't open a TCP/IP port to listen
for Subversion connections. However, it does require an active shell account
for each user and assumes that your users are comfortable logging in to a Unix
server. As with any shell account, your security depends upon your users
choosing good passwords and you setting up repository permissions and group
memberships correctly. Having users
ssh to the system does ensure
that they have encrypted sessions.
Another possibility is to integrate Subversion into an existing Apache
server. By default, the FreeBSD port of Subversion compiles in SSL support,
meaning your users can have the ability to access your repository securely from
their browsers using the
https:// schema. However, if you're
running Apache 2.x instead of Apache 1.x, remember to pass the
-DWITH_MOD_DAV_SVN option to
make when you compile
your FreeBSD port.
If you're considering giving browser access to your users, read carefully through the Apache httpd configuration section of the Subversion book first. You'll have to go through a fair bit of configuration; fortunately, the documentation is complete.
A third approach is to use
svnserve to listen for network
connections. The book suggests running this process either through
inetd or as a stand-alone daemon. Both of these approaches allow
either anonymous access or access once the system has authorized a user using
CRAM-MD5. Clients connect to
svnserve using the
Anonymous access wasn't appropriate in my scenario, so I followed the configuration options for CRAM-MD5. However, I quickly discovered that CRAM-MD5 wasn't on my FreeBSD system. When a Google search failed to find a technique for integrating CRAM-MD5 with my Subversion binary, I decided to try the last option.
This was to invoke
svnserve in tunnel mode, which allows user
authentication through the normal SSH mechanism as well as any restrictions you
have placed in your /etc/ssh/sshd_config file. For example, I could
AllowUsers keyword to control which users can authenticate
to the system. Note that this schema uses
The appeal of this method is that I could use an existing authentication
scheme without forcing the user to actually be "on" the repository system.
However, this network connection is unencrypted; the use of SSH is only to
authenticate. If your data is sensitive, either have your users use
sshing in or use
after you've properly configured Apache.
If you decide to use the
svnserve server and you compiled in
the wrapper, it created a binary called svnserve.bin. Users won't be
able to access the repository until:
# cp /usr/local/bin/svnserve.bin /usr/local/bin/svnserve
That's it for this installment. In the next column, I'll show how to start accessing the repository as a client.
Dru Lavigne is a network and systems administrator, IT instructor, author and international speaker. She has over a decade of experience administering and teaching Netware, Microsoft, Cisco, Checkpoint, SCO, Solaris, Linux, and BSD systems. A prolific author, she pens the popular FreeBSD Basics column for O'Reilly and is author of BSD Hacks and The Best of FreeBSD Basics.
Return to the BSD DevCenter
Return to O'Reilly SysAdmin