Sophie

Sophie

distrib > Mandriva > 2008.1 > x86_64 > by-pkgid > 0b38be552745286620faf2138b9468d0 > files > 183

subversion-doc-1.4.6-5.1mdv2008.1.x86_64.rpm

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>httpd, the Apache HTTP server</title><link rel="stylesheet" href="styles.css" type="text/css" /><meta name="generator" content="DocBook XSL Stylesheets V1.73.2" /><link rel="start" href="index.html" title="Version Control with Subversion" /><link rel="up" href="svn.serverconfig.html" title="Chapter 6. Server Configuration" /><link rel="prev" href="svn.serverconfig.svnserve.html" title="svnserve, a custom server" /><link rel="next" href="svn.serverconfig.pathbasedauthz.html" title="Path-Based Authorization" /></head><body><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">httpd, the Apache HTTP server</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="svn.serverconfig.svnserve.html">Prev</a> </td><th width="60%" align="center">Chapter 6. Server Configuration</th><td width="20%" align="right"> <a accesskey="n" href="svn.serverconfig.pathbasedauthz.html">Next</a></td></tr></table><hr /></div><div class="sect1" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="svn.serverconfig.httpd"></a>httpd, the Apache HTTP server</h2></div></div></div><p>The Apache HTTP Server is a “<span class="quote">heavy duty</span>”
      network server that Subversion can leverage.  Via a custom
      module, <span class="command"><strong>httpd</strong></span> makes Subversion repositories
      available to clients via the WebDAV/DeltaV protocol, which is an
      extension to HTTP 1.1 (see <a class="ulink" href="http://www.webdav.org/" target="_top">http://www.webdav.org/</a>
      for more information).  This protocol takes the ubiquitous HTTP
      protocol that is the core of the World Wide Web, and adds
      writing—specifically, versioned
      writing—capabilities.  The result is a standardized,
      robust system that is conveniently packaged as part of the
      Apache 2.0 software, is supported by numerous operating systems
      and third-party products, and doesn't require network
      administrators to open up yet another custom port.
      <sup>[<a id="id394499" href="#ftn.id394499" class="footnote">45</a>]</sup>
      While an Apache-Subversion server has more features than
      <span class="command"><strong>svnserve</strong></span>, it's also a bit more difficult
      to set up.  With flexibility often comes more complexity.</p><p>Much of the following discussion includes references to
      Apache configuration directives.  While some examples are given
      of the use of these directives, describing them in full is
      outside the scope of this chapter.  The Apache team maintains
      excellent documentation, publicly available on their website at
      <a class="ulink" href="http://httpd.apache.org" target="_top">http://httpd.apache.org</a>.  For example, a general
      reference for the configuration directives is located at <a class="ulink" href="       http://httpd.apache.org/docs-2.0/mod/directives.html" target="_top">       http://httpd.apache.org/docs-2.0/mod/directives.html</a>.</p><p>Also, as you make changes to your Apache setup, it is likely
      that somewhere along the way a mistake will be made.  If you are
      not already familiar with Apache's logging subsystem, you should
      become aware of it.  In your <code class="filename">httpd.conf</code>
      file are directives that specify the on-disk locations of the
      access and error logs generated by Apache (the
      <code class="literal">CustomLog</code> and <code class="literal">ErrorLog</code>
      directives, respectively).  Subversion's mod_dav_svn uses
      Apache's error logging interface as well.  You can always browse
      the contents of those files for information that might reveal
      the source of a problem that is not clearly noticeable
      otherwise.</p><div class="sidebar"><p class="title"><b>Why Apache 2?</b></p><p>If you're a system administrator, it's very likely that
        you're already running the Apache web server and have some
        prior experience with it.  At the time of writing, Apache 1.3
        is by far the most popular version of Apache.  The world has
        been somewhat slow to upgrade to the Apache 2.X series for
        various reasons: some people fear change, especially changing
        something as critical as a web server.  Other people depend on
        plug-in modules that only work against the Apache 1.3 API, and
        are waiting for a 2.X port.  Whatever the reason, many people
        begin to worry when they first discover that Subversion's
        Apache module is written specifically for the Apache 2 API.</p><p>The proper response to this problem is: don't worry about
        it.  It's easy to run Apache 1.3 and Apache 2 side-by-side;
        simply install them to separate places, and use Apache 2 as a
        dedicated Subversion server that runs on a port other than 80.
        Clients can access the repository by placing the port number
        into the URL:</p><pre class="screen">
$ svn checkout http://host.example.com:7382/repos/project
…
</pre></div><div class="sect2" lang="en" xml:lang="en"><div class="titlepage"><div><div><h3 class="title"><a id="svn.serverconfig.httpd.prereqs"></a>Prerequisites</h3></div></div></div><p>To network your repository over HTTP, you basically need
        four components, available in two packages.  You'll need
        Apache <span class="command"><strong>httpd</strong></span> 2.0, the
        <span class="command"><strong>mod_dav</strong></span> DAV module that comes with it,
        Subversion, and the <span class="command"><strong>mod_dav_svn</strong></span>
        filesystem provider module distributed with Subversion.
        Once you have all of those components, the process of
        networking your repository is as simple as:</p><div class="itemizedlist"><ul type="disc"><li><p>getting httpd 2.0 up and running with the mod_dav
            module,</p></li><li><p>installing the mod_dav_svn plugin to mod_dav, which
            uses Subversion's libraries to access the repository,
            and</p></li><li><p>configuring your <code class="filename">httpd.conf</code>
            file to export (or expose) the repository.</p></li></ul></div><p>You can accomplish the first two items either by
        compiling <span class="command"><strong>httpd</strong></span> and Subversion from
        source code, or by installing pre-built binary packages of
        them on your system.  For the most up-to-date information on
        how to compile Subversion for use with the Apache HTTP Server,
        as well as how to compile and configure Apache itself for
        this purpose, see the <code class="filename">INSTALL</code> file in
        the top level of the Subversion source code tree.</p></div><div class="sect2" lang="en" xml:lang="en"><div class="titlepage"><div><div><h3 class="title"><a id="svn.serverconfig.httpd.basic"></a>Basic Apache Configuration</h3></div></div></div><p>Once you have all the necessary components installed on
        your system, all that remains is the configuration of Apache
        via its <code class="filename">httpd.conf</code> file.  Instruct Apache
        to load the mod_dav_svn module using the
        <code class="literal">LoadModule</code> directive.  This directive must
        precede any other Subversion-related configuration items.  If
        your Apache was installed using the default layout, your
        <span class="command"><strong>mod_dav_svn</strong></span> module should have been
        installed in the <code class="filename">modules</code> subdirectory of
        the Apache install location (often
        <code class="filename">/usr/local/apache2</code>).  The
        <code class="literal">LoadModule</code> directive has a simple syntax,
        mapping a named module to the location of a shared library on
        disk:</p><pre class="screen">
LoadModule dav_svn_module     modules/mod_dav_svn.so
</pre><p>Note that if <span class="command"><strong>mod_dav</strong></span> was compiled as a
        shared object (instead of statically linked directly to the
        <span class="command"><strong>httpd</strong></span> binary), you'll need a similar
        <code class="literal">LoadModule</code> statement for it, too.  Be sure
        that it comes before the <span class="command"><strong>mod_dav_svn</strong></span> line:</p><pre class="screen">
LoadModule dav_module         modules/mod_dav.so
LoadModule dav_svn_module     modules/mod_dav_svn.so
</pre><p>At a later location in your configuration file, you now
        need to tell Apache where you keep your Subversion repository
        (or repositories).  The <code class="literal">Location</code> directive
        has an XML-like notation, starting with an opening tag, and
        ending with a closing tag, with various other configuration
        directives in the middle.  The purpose of the
        <code class="literal">Location</code> directive is to instruct Apache to
        do something special when handling requests that are directed
        at a given URL or one of its children.  In the case of
        Subversion, you want Apache to simply hand off support for
        URLs that point at versioned resources to the DAV layer.  You
        can instruct Apache to delegate the handling of all URLs whose
        path portions (the part of the URL that follows the server's
        name and the optional port number) begin with
        <code class="filename">/repos/</code> to a DAV provider whose
        repository is located at
        <code class="filename">/var/svn/repository</code> using the
        following <code class="filename">httpd.conf</code> syntax:</p><pre class="screen">
&lt;Location /repos&gt;
  DAV svn
  SVNPath /var/svn/repository
&lt;/Location&gt;
</pre><p>If you plan to support multiple Subversion repositories
        that will reside in the same parent directory on your local
        disk, you can use an alternative directive, the
        <code class="literal">SVNParentPath</code> directive, to indicate that
        common parent directory.  For example, if you know you will be
        creating multiple Subversion repositories in a directory
        <code class="filename">/var/svn</code> that would be accessed via
        URLs like <code class="uri">http://my.server.com/svn/repos1</code>,
        <code class="uri">http://my.server.com/svn/repos2</code>, and
        so on, you could use the <code class="filename">httpd.conf</code>
        configuration syntax in the following example:</p><pre class="screen">
&lt;Location /svn&gt;
  DAV svn

  # any "/svn/foo" URL will map to a repository /var/svn/foo
  SVNParentPath /var/svn
&lt;/Location&gt;
</pre><p>Using the previous syntax, Apache will delegate the
        handling of all URLs whose path portions begin with
        <code class="filename">/svn/</code> to the Subversion DAV provider,
        which will then assume that any items in the directory
        specified by the <code class="literal">SVNParentPath</code> directive
        are actually Subversion repositories.  This is a particularly
        convenient syntax in that, unlike the use of the
        <code class="literal">SVNPath</code> directive, you don't have to
        restart Apache in order to create and network new
        repositories.</p><p>Be sure that when you define your new
        <code class="literal">Location</code>, it doesn't overlap with other
        exported Locations.  For example, if your main
        <code class="literal">DocumentRoot</code> is exported to
        <code class="filename">/www</code>, do not export a Subversion
        repository in <code class="literal">&lt;Location /www/repos&gt;</code>.
        If a request comes in for the URI
        <code class="filename">/www/repos/foo.c</code>, Apache won't know
        whether to look for a file <code class="filename">repos/foo.c</code> in
        the <code class="literal">DocumentRoot</code>, or whether to delegate
        <span class="command"><strong>mod_dav_svn</strong></span> to return
        <code class="filename">foo.c</code> from the Subversion repository.
        The result is often an error from the server of the form
        <code class="literal">301 Moved Permanently</code>.</p><div class="sidebar"><p class="title"><b>Server Names and the COPY Request</b></p><p>Subversion makes use of the <code class="literal">COPY</code>
          request type to perform server-side copies of files and
          directories.  As part of the sanity checking done by the
          Apache modules, the source of the copy is expected to be
          located on the same machine as the destination of the copy.
          To satisfy this requirement, you might need to tell mod_dav
          the name you use as the hostname of your server.  Generally,
          you can use the <code class="literal">ServerName</code> directive in
          <code class="filename">httpd.conf</code> to accomplish this.</p><pre class="screen">
ServerName svn.example.com
</pre><p>If you are using Apache's virtual hosting support via
          the <code class="literal">NameVirtualHost</code> directive, you may
          need to use the <code class="literal">ServerAlias</code> directive to
          specify additional names that your server is known by.
          Again, refer to the Apache documentation for full
          details.</p></div><p>At this stage, you should strongly consider the question
        of permissions.  If you've been running Apache for some time
        now as your regular web server, you probably already have a
        collection of content—web pages, scripts and such.
        These items have already been configured with a set of
        permissions that allows them to work with Apache, or more
        appropriately, that allows Apache to work with those files.
        Apache, when used as a Subversion server, will also need the
        correct permissions to read and write to your Subversion
        repository.</p><p>You will need to determine a permission system setup that
        satisfies Subversion's requirements without messing up any
        previously existing web page or script installations.  This
        might mean changing the permissions on your Subversion
        repository to match those in use by other things that Apache
        serves for you, or it could mean using the
        <code class="literal">User</code> and <code class="literal">Group</code>
        directives in <code class="filename">httpd.conf</code> to specify that
        Apache should run as the user and group that owns your
        Subversion repository.  There is no single correct way to set
        up your permissions, and each administrator will have
        different reasons for doing things a certain way.  Just be
        aware that permission-related problems are perhaps the most
        common oversight when configuring a Subversion repository for
        use with Apache.</p></div><div class="sect2" lang="en" xml:lang="en"><div class="titlepage"><div><div><h3 class="title"><a id="svn.serverconfig.httpd.authn"></a>Authentication Options</h3></div></div></div><p>At this point, if you configured
        <code class="filename">httpd.conf</code> to contain something like</p><pre class="screen">
&lt;Location /svn&gt;
  DAV svn
  SVNParentPath /var/svn
&lt;/Location&gt;
</pre><p>…then your repository is “<span class="quote">anonymously</span>”
        accessible to the world.  Until you configure some
        authentication and authorization policies, the Subversion
        repositories you make available via the
        <code class="literal">Location</code> directive will be generally
        accessible to everyone.  In other words,</p><div class="itemizedlist"><ul type="disc"><li><p>anyone can use their Subversion client to check out a
            working copy of a repository URL (or any of its
            subdirectories),</p></li><li><p>anyone can interactively browse the repository's
            latest revision simply by pointing their web browser to
            the repository URL, and</p></li><li><p>anyone can commit to the repository.</p></li></ul></div><p>Of course, you might have already set up
        a <code class="filename">pre-commit</code> hook script to prevent
        commits (see <a class="xref" href="svn.reposadmin.create.html#svn.reposadmin.create.hooks" title="Implementing Repository Hooks">the section called “Implementing Repository Hooks”</a>).
        But as you read on, you'll see that it's also possible use
        Apache's built-in methods to restrict access in specific
        ways.</p><div class="sect3" lang="en" xml:lang="en"><div class="titlepage"><div><div><h4 class="title"><a id="svn.serverconfig.httpd.authn.basic"></a>Setting Up HTTP Authentication</h4></div></div></div><p>The easiest way to authenticate a client is via the
          HTTP Basic authentication mechanism, which simply uses a
          username and password to verify that a user is who she says
          she is.  Apache provides an <span class="command"><strong>htpasswd</strong></span>
          utility for managing the list of acceptable usernames and
          passwords.  Let's grant commit access to
          Sally and Harry.  First, we need to add them to the password
          file.</p><pre class="screen">
$ ### First time: use -c to create the file
$ ### Use -m to use MD5 encryption of the password, which is more secure
$ htpasswd -cm /etc/svn-auth-file harry
New password: *****
Re-type new password: *****
Adding password for user harry
$ htpasswd -m /etc/svn-auth-file sally
New password: *******
Re-type new password: *******
Adding password for user sally
$
</pre><p>Next, you need to add some more
          <code class="filename">httpd.conf</code> directives inside your
          <code class="literal">Location</code> block to tell Apache what to do
          with your new password file.  The
          <code class="literal">AuthType</code> directive specifies the type of
          authentication system to use.  In this case, we want to
          specify the <code class="literal">Basic</code> authentication system.
          <code class="literal">AuthName</code> is an arbitrary name that you
          give for the authentication domain.  Most browsers will
          display this name in the pop-up dialog box when the browser
          is querying the user for his name and password.  Finally,
          use the <code class="literal">AuthUserFile</code> directive to specify
          the location of the password file you created using
          <span class="command"><strong>htpasswd</strong></span>.</p><p>After adding these three directives, your
          <code class="literal">&lt;Location&gt;</code> block should look
          something like this:</p><pre class="screen">
&lt;Location /svn&gt;
  DAV svn
  SVNParentPath /var/svn
  AuthType Basic
  AuthName "Subversion repository"
  AuthUserFile /etc/svn-auth-file
&lt;/Location&gt;
</pre><p>This <code class="literal">&lt;Location&gt;</code> block is not
          yet complete, and will not do anything useful.  It's merely
          telling Apache that whenever authorization is required,
          Apache should harvest a username and password from the
          Subversion client.  What's missing here, however, are
          directives that tell Apache <span class="emphasis"><em>which</em></span> sorts
          of client requests require authorization.  Wherever
          authorization is required, Apache will demand
          authentication as well.  The simplest thing to do is protect
          all requests.  Adding <code class="literal">Require valid-user</code>
          tells Apache that all requests require an authenticated
          user:</p><pre class="screen">
&lt;Location /svn&gt;
  DAV svn
  SVNParentPath /var/svn
  AuthType Basic
  AuthName "Subversion repository"
  AuthUserFile /etc/svn-auth-file
  Require valid-user
&lt;/Location&gt;
</pre><p>Be sure to read the next section (<a class="xref" href="svn.serverconfig.httpd.html#svn.serverconfig.httpd.authz" title="Authorization Options">the section called “Authorization Options”</a>) for more detail on the
          <code class="literal">Require</code> directive and other ways to set
          authorization policies.</p><p>One word of warning: HTTP Basic Auth passwords pass in
          very nearly plain-text over the network, and thus are
          extremely insecure.</p><p>Another option is to not use Basic authentication
          but “<span class="quote">Digest</span>” authentication instead.  Digest
          authentication allows the server to verify the client's
          identity <span class="emphasis"><em>without</em></span> passing the plaintext
          password over the network.  Assuming that the client and
          server both know the user's password, they can verify that
          the password is the same by using it to apply a hashing
          function to a one-time bit of information.  The server sends
          a small random-ish string to the client; the client uses the
          user's password to hash the string; the server then looks to
          see if the hashed value is what it expected.</p><p>Configuring Apache for Digest authentication is also
          fairly easy, and only a small variation on our prior
          example.  Be sure to consult Apache's documentation for full
          details.</p><pre class="screen">
&lt;Location /svn&gt;
  DAV svn
  SVNParentPath /var/svn
  AuthType Digest
  AuthName "Subversion repository"
  AuthDigestDomain /svn/
  AuthUserFile /etc/svn-auth-file
  Require valid-user
&lt;/Location&gt;
</pre><p>If you're looking for maximum security, then public-key
          cryptography is the best solution.  It may be best to use
          some sort of SSL encryption, so that clients authenticate
          via <code class="literal">https://</code> instead
          of <code class="literal">http://</code>; at a bare minimum, you can
          configure Apache to use a self-signed server certificate.
          <sup>[<a id="id395341" href="#ftn.id395341" class="footnote">46</a>]</sup>
          Consult Apache's documentation (and OpenSSL documentation)
          about how to do that.</p></div><div class="sect3" lang="en" xml:lang="en"><div class="titlepage"><div><div><h4 class="title"><a id="svn.serverconfig.httpd.authn.sslcerts"></a>SSL Certificate Management</h4></div></div></div><p>Businesses that need to expose their repositories for access
          outside the company firewall should be conscious of the
          possibility that unauthorized parties could be
          “<span class="quote">sniffing</span>” their network traffic.  SSL makes
          that kind of unwanted attention less likely to result in
          sensitive data leaks.</p><p>If a Subversion client is compiled to use OpenSSL, then
          it gains the ability to speak to an Apache server via
          <code class="literal">https://</code> URLs.  The Neon library used by
          the Subversion client is not only able to verify server
          certificates, but can also supply client certificates when
          challenged.  When the client and server have exchanged SSL
          certificates and successfully authenticated one another, all
          further communication is encrypted via a session key.</p><p>It's beyond the scope of this book to describe how to
          generate client and server certificates, and how to
          configure Apache to use them.  Many other books, including
          Apache's own documentation, describe this task.  But what
          <span class="emphasis"><em>can</em></span> be covered here is how to manage
          server and client certificates from an ordinary Subversion
          client.</p><p>When speaking to Apache via <code class="literal">https://</code>,
          a Subversion client can receive two different types of
          information:</p><div class="itemizedlist"><ul type="disc"><li><p>a server certificate</p></li><li><p>a demand for a client certificate</p></li></ul></div><p>If the client receives a server certificate, it needs to
          verify that it trusts the certificate: is the server really
          who it claims to be?  The OpenSSL library does this by
          examining the signer of the server certificate, or
          <em class="firstterm">certifying authority</em> (CA).  If
          OpenSSL is unable to automatically trust the CA, or if some
          other problem occurs (such as an expired certificate or
          hostname mismatch), the Subversion command-line client will
          ask you whether you want to trust the server certificate
          anyway:</p><pre class="screen">
$ svn list https://host.example.com/repos/project

Error validating server certificate for 'https://host.example.com:443':
 - The certificate is not issued by a trusted authority. Use the
   fingerprint to validate the certificate manually!
Certificate information:
 - Hostname: host.example.com
 - Valid: from Jan 30 19:23:56 2004 GMT until Jan 30 19:23:56 2006 GMT
 - Issuer: CA, example.com, Sometown, California, US
 - Fingerprint: 7d:e1:a9:34:33:39:ba:6a:e9:a5:c4:22:98:7b:76:5c:92:a0:9c:7b

(R)eject, accept (t)emporarily or accept (p)ermanently?
</pre><p>This dialogue should look familiar; it's essentially the
          same question you've probably seen coming from your web
          browser (which is just another HTTP client like Subversion).
          If you choose the (p)ermanent option, the server certificate
          will be cached in your private run-time
          <code class="filename">auth/</code> area in just the same way your
          username and password are cached (see <a class="xref" href="svn.serverconfig.netmodel.html#svn.serverconfig.netmodel.credcache" title="Client Credentials Caching">the section called “Client Credentials Caching”</a>).  If cached,
          Subversion will automatically trust this certificate
          in future negotiations.</p><p>Your run-time <code class="filename">servers</code> file also gives
          you the ability to make your Subversion client automatically
          trust specific CAs, either globally or on a per-host basis.
          Simply set the <code class="literal">ssl-authority-files</code>
          variable to a semicolon-separated list of PEM-encoded CA
          certificates:</p><pre class="screen">
[global]
ssl-authority-files = /path/to/CAcert1.pem;/path/to/CAcert2.pem
</pre><p>Many OpenSSL installations also have a pre-defined set
          of “<span class="quote">default</span>” CAs that are nearly universally
          trusted.  To make the Subversion client automatically trust
          these standard authorities, set the
          <code class="literal">ssl-trust-default-ca</code> variable to
          <code class="literal">true</code>.</p><p>When talking to Apache, a Subversion client might also
          receive a challenge for a client certificate.  Apache is
          asking the client to identify itself: is the client really
          who it says it is?  If all goes correctly, the Subversion
          client sends back a private certificate signed by a CA that
          Apache trusts.  A client certificate is usually stored on
          disk in encrypted format, protected by a local password.
          When Subversion receives this challenge, it will ask you for
          both a path to the certificate and the password which
          protects it:</p><pre class="screen">
$ svn list https://host.example.com/repos/project

Authentication realm: https://host.example.com:443
Client certificate filename: /path/to/my/cert.p12
Passphrase for '/path/to/my/cert.p12':  ********
…
</pre><p>Notice that the client certificate is a
          “<span class="quote">p12</span>” file.  To use a client certificate with
          Subversion, it must be in PKCS#12 format, which is a
          portable standard.  Most web browsers are already able to
          import and export certificates in that format.   Another
          option is to use the OpenSSL command-line tools to convert
          existing certificates into PKCS#12.</p><p>Again, the runtime <code class="filename">servers</code> file
          allows you to automate this challenge on a per-host basis.
          Either or both pieces of information can be described in
          runtime variables:</p><pre class="screen">
[groups]
examplehost = host.example.com

[examplehost]
ssl-client-cert-file = /path/to/my/cert.p12
ssl-client-cert-password = somepassword
</pre><p>Once you've set the
          <code class="literal">ssl-client-cert-file</code> and
          <code class="literal">ssl-client-cert-password</code> variables, the
          Subversion client can automatically respond to a client
          certificate challenge without prompting you.
          <sup>[<a id="id395569" href="#ftn.id395569" class="footnote">47</a>]</sup>
        </p></div></div><div class="sect2" lang="en" xml:lang="en"><div class="titlepage"><div><div><h3 class="title"><a id="svn.serverconfig.httpd.authz"></a>Authorization Options</h3></div></div></div><p>At this point, you've configured authentication, but not
        authorization.  Apache is able to challenge clients and
        confirm identities, but it has not been told how to allow or
        restrict access to the clients bearing those identities.  This
        section describes two strategies for controlling access to
        your repositories.</p><div class="sect3" lang="en" xml:lang="en"><div class="titlepage"><div><div><h4 class="title"><a id="svn.serverconfig.httpd.authz.blanket"></a>Blanket Access Control</h4></div></div></div><p>The simplest form of access control is to authorize
          certain users for either read-only access to a repository,
          or read/write access to a repository.</p><p>You can restrict access on all repository operations by
          adding the <code class="literal">Require valid-user</code> directive
          to your <code class="literal">&lt;Location&gt;</code> block.  Using
          our previous example, this would mean that only clients that
          claimed to be either <code class="literal">harry</code> or
          <code class="literal">sally</code>, and provided the correct
          password for their respective username, would be allowed to
          do anything with the Subversion repository:</p><pre class="screen">
&lt;Location /svn&gt;
  DAV svn
  SVNParentPath /var/svn

  # how to authenticate a user
  AuthType Basic
  AuthName "Subversion repository"
  AuthUserFile /path/to/users/file

  # only authenticated users may access the repository
  Require valid-user
&lt;/Location&gt;
</pre><p>Sometimes you don't need to run such a tight ship.  For
          example, Subversion's own source code repository at
          <a class="ulink" href="http://svn.collab.net/repos/svn" target="_top">http://svn.collab.net/repos/svn</a> allows anyone
          in the world to perform read-only repository tasks (like
          checking out working copies and browsing the repository with
          a web browser), but restricts all write operations to
          authenticated users.  To do this type of selective
          restriction, you can use the <code class="literal">Limit</code> and
          <code class="literal">LimitExcept</code> configuration directives.
          Like the <code class="literal">Location</code> directive, these blocks
          have starting and ending tags, and you would nest them
          inside your <code class="literal">&lt;Location&gt;</code>
          block.</p><p>The parameters present on the <code class="literal">Limit</code>
          and <code class="literal">LimitExcept</code> directives are HTTP
          request types that are affected by that block.  For example,
          if you wanted to disallow all access to your repository
          except the currently supported read-only operations, you
          would use the <code class="literal">LimitExcept</code> directive,
          passing the <code class="literal">GET</code>,
          <code class="literal">PROPFIND</code>, <code class="literal">OPTIONS</code>, and
          <code class="literal">REPORT</code> request type parameters.  Then the
          previously mentioned <code class="literal">Require valid-user</code>
          directive would be placed inside the
          <code class="literal">&lt;LimitExcept&gt;</code> block instead of just
          inside the <code class="literal">&lt;Location&gt;</code> block.</p><pre class="screen">
&lt;Location /svn&gt;
  DAV svn
  SVNParentPath /var/svn

  # how to authenticate a user
  AuthType Basic
  AuthName "Subversion repository"
  AuthUserFile /path/to/users/file

  # For any operations other than these, require an authenticated user.
  &lt;LimitExcept GET PROPFIND OPTIONS REPORT&gt;
    Require valid-user
  &lt;/LimitExcept&gt;
&lt;/Location&gt;
</pre><p>These are only a few simple examples.  For more in-depth
          information about Apache access control and the
          <code class="literal">Require</code> directive, take a look at the
          <code class="literal">Security</code> section of the Apache
          documentation's tutorials collection at <a class="ulink" href="http://httpd.apache.org/docs-2.0/misc/tutorials.html" target="_top">http://httpd.apache.org/docs-2.0/misc/tutorials.html</a>.</p></div><div class="sect3" lang="en" xml:lang="en"><div class="titlepage"><div><div><h4 class="title"><a id="svn.serverconfig.httpd.authz.perdir"></a>Per-Directory Access Control</h4></div></div></div><p>It's possible to set up finer-grained permissions using
          a second Apache httpd module,
          <span class="command"><strong>mod_authz_svn</strong></span>.  This module grabs the
          various opaque URLs passing from client to server, asks
          <span class="command"><strong>mod_dav_svn</strong></span> to decode them, and then
          possibly vetoes requests based on access policies defined in
          a configuration file.</p><p>If you've built Subversion from source code,
          <span class="command"><strong>mod_authz_svn</strong></span> is automatically built
          and installed alongside <span class="command"><strong>mod_dav_svn</strong></span>.
          Many binary distributions install it automatically as well.
          To verify that it's installed correctly, make sure it comes
          right after <span class="command"><strong>mod_dav_svn</strong></span>'s
          <code class="literal">LoadModule</code> directive in
          <code class="filename">httpd.conf</code>:</p><pre class="screen">
LoadModule dav_module         modules/mod_dav.so
LoadModule dav_svn_module     modules/mod_dav_svn.so
LoadModule authz_svn_module   modules/mod_authz_svn.so
</pre><p>To activate this module, you need to configure your
          <code class="literal">Location</code> block to use the
          <code class="literal">AuthzSVNAccessFile</code> directive, which
          specifies a file containing the permissions policy for paths
          within your repositories.  (In a moment, we'll discuss the
          format of that file.)</p><p>Apache is flexible, so you have the option to configure
          your block in one of three general patterns.  To begin,
          choose one of these basic configuration patterns.  (The
          examples below are very simple; look at Apache's own
          documentation for much more detail on Apache authentication
          and authorization options.)</p><p>The simplest block is to allow open access to everyone.
          In this scenario, Apache never sends authentication
          challenges, so all users are treated as
          “<span class="quote">anonymous</span>”.</p><div class="example"><a id="svn.serverconfig.httpd.authz.perdir.ex-1"></a><p class="title"><b>Example 6.1. A sample configuration for anonymous access.</b></p><div class="example-contents"><pre class="programlisting">
&lt;Location /repos&gt;
  DAV svn
  SVNParentPath /var/svn

  # our access control policy
  AuthzSVNAccessFile /path/to/access/file
&lt;/Location&gt;
          </pre></div></div><br class="example-break" /><p>On the opposite end of the paranoia scale, you can
          configure your block to demand authentication from everyone.
          All clients must supply credentials to identify themselves.
          Your block unconditionally requires authentication via the
          <code class="literal">Require valid-user</code> directive, and defines
          a means to authenticate.</p><div class="example"><a id="svn.serverconfig.httpd.authz.perdir.ex-2"></a><p class="title"><b>Example 6.2. A sample configuration for authenticated access.</b></p><div class="example-contents"><pre class="programlisting">
&lt;Location /repos&gt;
  DAV svn
  SVNParentPath /var/svn

  # our access control policy
  AuthzSVNAccessFile /path/to/access/file

  # only authenticated users may access the repository
  Require valid-user

  # how to authenticate a user
  AuthType Basic
  AuthName "Subversion repository"
  AuthUserFile /path/to/users/file
&lt;/Location&gt;
          </pre></div></div><br class="example-break" /><p>A third very popular pattern is to allow a combination
          of authenticated and anonymous access.  For example, many
          administrators want to allow anonymous users to read certain
          repository directories, but want only authenticated users to
          read (or write) more sensitive areas.  In this setup, all
          users start out accessing the repository anonymously.  If
          your access control policy demands a real username at any
          point, Apache will demand authentication from the client.
          To do this, you use both the <code class="literal">Satisfy Any</code>
          and <code class="literal">Require valid-user</code> directives
          together.</p><div class="example"><a id="svn.serverconfig.httpd.authz.perdir.ex-3"></a><p class="title"><b>Example 6.3. A sample configuration for mixed
            authenticated/anonymous access.</b></p><div class="example-contents"><pre class="programlisting">
&lt;Location /repos&gt;
  DAV svn
  SVNParentPath /var/svn

  # our access control policy
  AuthzSVNAccessFile /path/to/access/file

  # try anonymous access first, resort to real
  # authentication if necessary.
  Satisfy Any
  Require valid-user

  # how to authenticate a user
  AuthType Basic
  AuthName "Subversion repository"
  AuthUserFile /path/to/users/file
&lt;/Location&gt;
          </pre></div></div><br class="example-break" /><p>Once you've settled on one of these three
          basic <code class="filename">httpd.conf</code> templates, you need to
          create your file containing access rules for particular
          paths within the repository.  This is described in
          <a class="xref" href="svn.serverconfig.pathbasedauthz.html" title="Path-Based Authorization">the section called “Path-Based Authorization”</a>.</p></div><div class="sect3" lang="en" xml:lang="en"><div class="titlepage"><div><div><h4 class="title"><a id="svn.serverconfig.httpd.authz.pathauthzoff"></a>Disabling Path-based Checks</h4></div></div></div><p>The <span class="command"><strong>mod_dav_svn</strong></span> module goes through a
          lot of work to make sure that data you've marked
          “<span class="quote">unreadable</span>” doesn't get accidentally leaked.
          This means that it needs to closely monitor all of the paths
          and file-contents returned by commands like <span class="command"><strong>svn
          checkout</strong></span> or <span class="command"><strong>svn update</strong></span>
          commands.  If these commands encounter a path that isn't
          readable according to some authorization policy, then the
          path is typically omitted altogether.  In the case of
          history or rename tracing—e.g. running a command like
          <span class="command"><strong>svn cat -r OLD foo.c</strong></span> on a file that was
          renamed long ago—the rename tracking will simply halt
          if one of the object's former names is determined to be
          read-restricted.</p><p>All of this path-checking can sometimes be quite
          expensive, especially in the case of <span class="command"><strong>svn
          log</strong></span>.  When retrieving a list of revisions, the server
          looks at every changed path in each revision and checks it
          for readability.  If an unreadable path is discovered, then
          it's omitted from the list of the revision's changed paths
          (normally seen with the <code class="option">--verbose</code> option),
          and the whole log message is suppressed.  Needless to say,
          this can be time-consuming on revisions that affect a large
          number of files.  This is the cost of security: even if you
          haven't configured a module like
          <span class="command"><strong>mod_authz_svn</strong></span> at all, the
          <span class="command"><strong>mod_dav_svn</strong></span> module is still asking Apache
          <span class="command"><strong>httpd</strong></span> to run authorization checks on
          every path.  The <span class="command"><strong>mod_dav_svn</strong></span> module has
          no idea what authorization modules have been installed, so
          all it can do is ask Apache to invoke whatever might be
          present.</p><p>On the other hand, there's also an escape-hatch of
          sorts, one which allows you to trade security features for
          speed.  If you're not enforcing any sort of per-directory
          authorization (i.e. not using
          <span class="command"><strong>mod_authz_svn</strong></span> or similar module), then
          you can disable all of this path-checking.  In your
          <code class="filename">httpd.conf</code> file, use the
          <code class="literal">SVNPathAuthz</code> directive:</p><div class="example"><a id="svn.serverconfig.httpd.authz.pathauthzoff.ex-1"></a><p class="title"><b>Example 6.4. Disabling path checks altogether</b></p><div class="example-contents"><pre class="programlisting">
&lt;Location /repos&gt;
  DAV svn
  SVNParentPath /var/svn

  SVNPathAuthz off
&lt;/Location&gt;
          </pre></div></div><br class="example-break" /><p>The <code class="literal">SVNPathAuthz</code> directive is “<span class="quote">on</span>” by
          default.  When set “<span class="quote">off</span>”, all path-based
          authorization checking is disabled;
          <span class="command"><strong>mod_dav_svn</strong></span> stops invoking authorization
          checks on every path it discovers.</p></div></div><div class="sect2" lang="en" xml:lang="en"><div class="titlepage"><div><div><h3 class="title"><a id="svn.serverconfig.httpd.extra"></a>Extra Goodies</h3></div></div></div><p>We've covered most of the authentication and authorization
        options for Apache and mod_dav_svn.  But there are a few other
        nice features that Apache provides.</p><div class="sect3" lang="en" xml:lang="en"><div class="titlepage"><div><div><h4 class="title"><a id="svn.serverconfig.httpd.extra.browsing"></a>Repository Browsing</h4></div></div></div><p>One of the most useful benefits of an Apache/WebDAV
          configuration for your Subversion repository is that the
          youngest revisions of your versioned files and directories
          are immediately available for viewing via a regular web
          browser.  Since Subversion uses URLs to identify versioned
          resources, those URLs used for HTTP-based repository access
          can be typed directly into a Web browser.  Your browser will
          issue an HTTP <code class="literal">GET</code> request for that URL, and
          based on whether that URL represents a versioned directory
          or file, mod_dav_svn will respond with a directory listing
          or with file contents.</p><p>Since the URLs do not contain any information about
          which version of the resource you wish to see, mod_dav_svn
          will always answer with the youngest version.  This
          functionality has the wonderful side-effect that you can
          pass around Subversion URLs to your peers as references to
          documents, and those URLs will always point at the latest
          manifestation of that document.  Of course, you can even use
          the URLs as hyperlinks from other web sites, too.</p><div class="sidebar"><p class="title"><b>Can I view older revisions?</b></p><p>With an ordinary web browser?  In one word: nope.  At
            least, not with <span class="command"><strong>mod_dav_svn</strong></span> as your
            only tool.</p><p>Your web browser only speaks ordinary HTTP.  That
            means it only knows how to GET public URLs, which
            represent the latest versions of files and directories.
            According to the WebDAV/DeltaV specification, each server
            defines a private URL syntax for older versions of
            resources, and that syntax is opaque to clients.  To find
            an older version of a file, a client must follow a
            specific procedure to “<span class="quote">discover</span>” the proper
            URL; the procedure involves issuing a series of WebDAV
            PROPFIND requests and understanding DeltaV concepts.  This
            is something your web browser simply can't do.</p><p>So to answer the question, one obvious way to see
            older revisions of files and directories is by passing the
            <code class="option">--revision (-r)</code> argument to
            the <span class="command"><strong>svn list</strong></span> and <span class="command"><strong>svn
            cat</strong></span> commands.  To browse old revisions with your
            web browser, however, you can use third-party software.  A
            good example of this is ViewVC
            (<a class="ulink" href="http://viewvc.tigris.org/" target="_top">http://viewvc.tigris.org/</a>).  ViewVC was
            originally written to display CVS repositories through the
            web,
            <sup>[<a id="id396291" href="#ftn.id396291" class="footnote">48</a>]</sup>
            and the latest releases are able to understand Subversion
            repositories as well.</p></div><div class="sect4" lang="en" xml:lang="en"><div class="titlepage"><div><div><h5 class="title"><a id="svn.serverconfig.httpd.extra.browsing.mimetype"></a>Proper MIME Type</h5></div></div></div><p>When browsing a Subversion repository, the web browser
            gets a clue about how to render a file's contents by
            looking at the <code class="literal">Content-Type:</code> header
            returned in Apache's response to the
            HTTP <code class="literal">GET</code> request.  The value of this
            header is some sort of MIME type.  By default, Apache will
            tell the web browsers that all repository files are of
            the “<span class="quote">default</span>” MIME type,
            typically <code class="literal">text/plain</code>.  This can be
            frustrating, however, if a user wishes repository files to
            render as something more meaningful—for example,
            it might be nice to have a <code class="filename">foo.html</code> file
            in the repository actually render as HTML when
            browsing.</p><p>To make this happen, you only need to make sure that
            your files have the
            proper <code class="literal">svn:mime-type</code> set.  This is
            discussed in more detail in
            <a class="xref" href="svn.advanced.props.file-portability.html#svn.advanced.props.special.mime-type" title="File Content Type">the section called “File Content Type”</a>,
            and you can even configure your client to automatically
            attach proper <code class="literal">svn:mime-type</code> properties
            to files entering the repository for the first time;  see
            <a class="xref" href="svn.advanced.props.html#svn.advanced.props.auto" title="Automatic Property Setting">the section called “Automatic Property Setting”</a>.</p><p>So in our example, if one were to set
          the <code class="literal">svn:mime-type</code> property
          to <code class="literal">text/html</code> on
          file <code class="filename">foo.html</code>, then Apache would
          properly tell your web browser to render the file as
          HTML.  One could also attach
          proper <code class="literal">image/*</code> mime-type properties to
          images, and by doing this, ultimately get an entire web
          site to be viewable directly from a repository!  There's
          generally no problem with doing this, as long as the
          website doesn't contain any dynamically-generated
          content.</p></div><div class="sect4" lang="en" xml:lang="en"><div class="titlepage"><div><div><h5 class="title"><a id="svn.serverconfig.httpd.extra.browsing.xslt"></a>Customizing the Look</h5></div></div></div><p>You generally will get more use out of URLs to
            versioned files—after all, that's where the
            interesting content tends to lie.  But you might have
            occasion to browse a Subversion directory listing, where
            you'll quickly note that the generated HTML used to
            display that listing is very basic, and certainly not
            intended to be aesthetically pleasing (or even
            interesting).  To enable customization of these directory
            displays, Subversion provides an XML index feature.  A
            single <code class="literal">SVNIndexXSLT</code> directive in your
            repository's <code class="literal">Location</code> block of
            <code class="filename">httpd.conf</code> will instruct mod_dav_svn
            to generate XML output when displaying a directory
            listing, and to reference the XSLT stylesheet of your
            choice:</p><pre class="screen">
&lt;Location /svn&gt;
  DAV svn
  SVNParentPath /var/svn
  SVNIndexXSLT "/svnindex.xsl"
  …
&lt;/Location&gt;
</pre><p>Using the <code class="literal">SVNIndexXSLT</code> directive and
           a creative XSLT stylesheet, you can make your directory
           listings match the color schemes and imagery used in other
           parts of your website.  Or, if you'd prefer, you can use
           the sample stylesheets provided in the Subversion source
           distribution's <code class="filename">tools/xslt/</code> directory.
           Keep in mind that the path provided to the
           <code class="literal">SVNIndexXSLT</code> directory is actually a URL
           path—browsers need to be able to read your
           stylesheets in order to make use of them!</p></div><div class="sect4" lang="en" xml:lang="en"><div class="titlepage"><div><div><h5 class="title"><a id="svn.serverconfig.httpd.extra.browsing.reposlisting"></a>Listing Repositories</h5></div></div></div><p>If you're serving a collection of repositories from a
            single URL via the <code class="literal">SVNParentPath</code>
            directive, then it's also possible to have Apache display
            all available repositories to a web browser.  Just
            activate the <code class="literal">SVNListParentPath</code>
            directive:</p><pre class="screen">
&lt;Location /svn&gt;
  DAV svn
  SVNParentPath /var/svn
  SVNListParentPath on
  …
&lt;/Location&gt;
</pre><p>If a user now points her web browser to the
          URL <code class="literal">http://host.example.com/svn/</code>, she'll
          see list of all Subversion repositories sitting
          in <code class="filename">/var/svn</code>.  Obviously, this can
          be a security problem, so this feature is turned off by
          default.</p></div></div><div class="sect3" lang="en" xml:lang="en"><div class="titlepage"><div><div><h4 class="title"><a id="svn.serverconfig.httpd.extra.logging"></a>Apache Logging</h4></div></div></div><p>Because Apache is an HTTP server at heart, it contains
          fantastically flexible logging features.  It's beyond the
          scope of this book to discuss all ways logging can be
          configured, but we should point out that even the most
          generic <code class="filename">httpd.conf</code> file will cause
          Apache to produce two logs:
          <code class="filename">error_log</code>
          and <code class="filename">access_log</code>.  These logs may appear
          in different places, but are typically created in the
          logging area of your Apache installation.  (On Unix, they
          often live
          in <code class="filename">/usr/local/apache2/logs/</code>.)</p><p>The <code class="filename">error_log</code> describes any internal
          errors that Apache runs into as it works.
          The <code class="filename">access_log</code> file records every
          incoming HTTP request received by Apache.  This makes it
          easy to see, for example, which IP addresses Subversion
          clients are coming from, how often particular clients use
          the server, which users are authenticating properly, and
          which requests succeed or fail.</p><p>Unfortunately, because HTTP is a stateless protocol,
          even the simplest Subversion client operation generates
          multiple network requests.  It's very difficult to look at
          the <code class="filename">access_log</code> and deduce what the
          client was doing—most operations look like a series
          of cryptic <code class="literal">PROPPATCH</code>, <code class="literal">GET</code>,
          <code class="literal">PUT</code>, and <code class="literal">REPORT</code>
          requests.  To make things worse, many client operations send
          nearly-identical series of requests, so it's even harder to
          tell them apart.</p><p><code class="literal">mod_dav_svn</code>, however, can come to
          your aid.  By activating an “<span class="quote">operational
          logging</span>” feature, you can
          ask <code class="literal">mod_dav_svn</code> to create a separate log
          file describing what sort of high-level operations your
          clients are performing.</p><p>To do this, you need to make use of
          Apache's <code class="literal">CustomLog</code> directive (which is
          explained in more detail in Apache's own documentation).
          Be sure to invoke this
          directive <span class="emphasis"><em>outside</em></span> of your
          Subversion <code class="literal">Location</code> block:</p><pre class="screen">
&lt;Location /svn&gt;
  DAV svn
  …
&lt;/Location&gt;

CustomLog logs/svn_logfile "%t %u %{SVN-ACTION}e" env=SVN-ACTION
</pre><p>In this example, we're asking Apache to create a special
          logfile <code class="filename">svn_logfile</code> in the standard
          Apache <code class="filename">logs</code> directory.
          The <code class="literal">%t</code> and <code class="literal">%u</code>
          variables are replaced by the time and username of the
          request, respectively.  The really important part are the
          two instances of <code class="literal">SVN-ACTION</code>.
          When Apache sees that variable, it substitutes the value of
          the <code class="literal">SVN-ACTION</code> environment variable,
          which is automatically set by <code class="literal">mod_dav_svn</code>
          whenever it detects a high-level client action.</p><p>So instead of having to interpret a
          traditional <code class="filename">access_log</code> like
          this:</p><pre class="screen">
[26/Jan/2007:22:25:29 -0600] "PROPFIND /svn/calc/!svn/vcc/default HTTP/1.1" 207 398
[26/Jan/2007:22:25:29 -0600] "PROPFIND /svn/calc/!svn/bln/59 HTTP/1.1" 207 449
[26/Jan/2007:22:25:29 -0600] "PROPFIND /svn/calc HTTP/1.1" 207 647
[26/Jan/2007:22:25:29 -0600] "REPORT /svn/calc/!svn/vcc/default HTTP/1.1" 200 607
[26/Jan/2007:22:25:31 -0600] "OPTIONS /svn/calc HTTP/1.1" 200 188
[26/Jan/2007:22:25:31 -0600] "MKACTIVITY /svn/calc/!svn/act/e6035ef7-5df0-4ac0-b811-4be7c823f998 HTTP/1.1" 201 227
…
</pre><p>… you can instead peruse a much more
          intelligible <code class="filename">svn_logfile</code> like this:</p><pre class="screen">
[26/Jan/2007:22:24:20 -0600] - list-dir '/'
[26/Jan/2007:22:24:27 -0600] - update '/'
[26/Jan/2007:22:25:29 -0600] - remote-status '/'
[26/Jan/2007:22:25:31 -0600] sally commit r60
</pre><p>For an exhaustive list of all actions logged, see <a class="xref" href="svn.ref.mod_dav_svn.conf.html#svn.ref.mod_dav_svn.conf.logging" title="High Level Logging">the section called “High Level Logging”</a>.</p></div><div class="sect3" lang="en" xml:lang="en"><div class="titlepage"><div><div><h4 class="title"><a id="svn.serverconfig.httpd.extra.writethruproxy"></a>Write-Through Proxying</h4></div></div></div><p>One of the nice advantages of using Apache as a
          Subversion server is that it can be set up for simple
          replication.  For example, suppose that your team is
          distributed across four offices around the globe.  The
          Subversion repository can only exist in one of those
          offices, and that means the other three offices will not
          enjoy accessing it—they're likely to experience
          significantly slower traffic and response times when
          updating and committing code.  A powerful solution is to set
          up a system consisting of one <em class="firstterm">master</em>
          Apache server and several <em class="firstterm">slave</em>
          Apache servers.  If you place a slave server in each office,
          then users can check out a working copy from whichever slave
          is closest to them.  All read requests go to their local
          slave.  Write requests get automatically routed to the
          single master server.  When the commit completes, the master
          then automatically “<span class="quote">pushes</span>” the new revision to
          each slave server using the <span class="command"><strong>svnsync</strong></span>
          replication tool.</p><p>This configuration creates a huge perceptual speed
          increase for your users, because Subversion client traffic
          is typically 80-90% read requests.  And if those requests
          are coming from a <span class="emphasis"><em>local</em></span> server, it's a
          huge win.</p><p>In this section, we'll walk you through a standard setup
          of this single-master/multiple slave system.  However, keep
          in mind that your servers must be running at least Apache
          2.2.0 (with <span class="command"><strong>mod_proxy</strong></span> loaded) and
          Subversion (<span class="command"><strong>mod_dav_svn</strong></span>) 1.5.</p><div class="sect4" lang="en" xml:lang="en"><div class="titlepage"><div><div><h5 class="title"><a id="svn.serverconfig.httpd.extra.writethruproxy.configure"></a>Configure the Servers</h5></div></div></div><p>First, configure your master server's
            <code class="filename">httpd.conf</code> file in the usual way.
            Make the repository available at a certain URI location,
            and configure authentication and authorization however
            you'd like.  After that's done, configure each of your
            “<span class="quote">slave</span>” servers in the exact same way, but
            add the special <code class="literal">SVNMasterURI</code> directive
            to the block:</p><pre class="screen">
&lt;Location /svn&gt;
  DAV svn
  SVNPath /var/svn/repos
  SVNMasterURI http://master.example.com/svn
  …
&lt;/Location&gt;
</pre><p>This new directive tells a slave server to redirect
            all write requests to the master.  (This is done
            automatically via Apache's <span class="command"><strong>mod_proxy</strong></span>
            module.)  Ordinary read requests, however, are still
            serviced by the slaves.  Be sure that your master and
            slave servers all have matching authentication and
            authorization configurations;  if they fall out of sync,
            it can lead to big headaches.</p><p>Next, we need to deal with the problem of infinite
            recursion.  With the current configuration, imagine what
            will happen when a Subversion client performs a commit to
            the master server.  After the commit completes, the server
            uses <span class="command"><strong>svnsync</strong></span> to replicate the new
            revision to each slave.  But because
            <span class="command"><strong>svnsync</strong></span> appears to be just another
            Subversion client performing a commit, the slave will
            immediately attempt to proxy the incoming write request
            back to the master!  Hilarity ensues.</p><p>The solution to this problem is to have the master
            push revisions to a different
            <code class="literal">&lt;Location&gt;</code> on the slaves.  This
            location is configured to <span class="emphasis"><em>not</em></span> proxy
            write requests at all, but accept normal commits from (and
            only from) the master's IP address:</p><pre class="screen">
&lt;Location /svn-proxy-sync&gt;
  DAV svn
  SVNPath /var/svn/repos
  Order deny,allow
  Deny from all
  # Only let the server's IP address access this Location:
  Allow from 10.20.30.40
  …
&lt;/Location&gt;
</pre></div><div class="sect4" lang="en" xml:lang="en"><div class="titlepage"><div><div><h5 class="title"><a id="svn.serverconfig.httpd.extra.writethruproxy.replicate"></a>Set up Replication</h5></div></div></div><p>Now that you've configured your Location blocks on
            master and slaves, you need to configure the master to
            replicate to the slaves.  This is done the usual way,
            using <span class="command"><strong>svnsync</strong></span>.  If you're not familiar
            with this tool, see <a class="xref" href="svn.reposadmin.maint.html#svn.reposadmin.maint.replication" title="Repository Replication">the section called “Repository Replication”</a> for
            details.</p><p>First, make sure that each slave repository has a
            <code class="filename">pre-revprop-change</code> hook script which
            allows remote revision property changes.  (This is
            standard procedure for being on the receiving end of
            <span class="command"><strong>svnsync</strong></span>) Then log into the master
            server and configure each of the slave repository URIs to
            receive data from the master repository on local
            disk:</p><pre class="screen">
$ svnsync init http://slave1.example.com/svn-proxy-sync file://var/svn/repos
Copied properties for revision 0.
$ svnsync init http://slave2.example.com/svn-proxy-sync file://var/svn/repos
Copied properties for revision 0.
$ svnsync init http://slave3.example.com/svn-proxy-sync file://var/svn/repos
Copied properties for revision 0.

# Perform the initial replication

$ svnsync sync http://slave1.example.com/svn-proxy-sync
Transmitting file data ....
Committed revision 1.
Copied properties for revision 1.
Transmitting file data .......
Committed revision 2.
Copied properties for revision 2.
…

$ svnsync sync http://slave2.example.com/svn-proxy-sync
Transmitting file data ....
Committed revision 1.
Copied properties for revision 1.
Transmitting file data .......
Committed revision 2.
Copied properties for revision 2.
…

$ svnsync sync http://slave3.example.com/svn-proxy-sync
Transmitting file data ....
Committed revision 1.
Copied properties for revision 1.
Transmitting file data .......
Committed revision 2.
Copied properties for revision 2.
…
</pre><p>After this is done, we configure the master server's
            <code class="filename">post-commit</code> hook script to invoke
            <span class="command"><strong>svnsync</strong></span> on each slave server:</p><pre class="programlisting">
#!/bin/sh
# Post-commit script to replicate newly-committed revision to slaves

svnsync sync http://slave1.example.com/svn-proxy-sync &gt; /dev/null 2&gt;&amp;1
svnsync sync http://slave2.example.com/svn-proxy-sync &gt; /dev/null 2&gt;&amp;1
svnsync sync http://slave3.example.com/svn-proxy-sync &gt; /dev/null 2&gt;&amp;1
</pre><p>The extra bits on the end of each line aren't
            necessary, but they're a sneaky way to allow the sync
            commands to run in the background, so that the Subversion
            client isn't left waiting forever for the commit to
            finish.  In addition to this
            <code class="filename">post-commit</code> hook, you'll need a
            <code class="filename">post-revprop-change</code> hook as well, so
            that when a user, say, modifies a log message, the slave
            servers get that change as well:</p><pre class="programlisting">
#!/bin/sh
# Post-revprop-change script to replicate revprop-changes to slaves

REV=${2}
svnsync copy-revprops http://slave1.example.com/svn-proxy-sync ${REV} &gt; /dev/null 2&gt;&amp;1
svnsync copy-revprops http://slave2.example.com/svn-proxy-sync ${REV} &gt; /dev/null 2&gt;&amp;1
svnsync copy-revprops http://slave3.example.com/svn-proxy-sync ${REV} &gt; /dev/null 2&gt;&amp;1
</pre><p>The only thing we've left out here is what to do about
            locks.  Because locks are strictly enforced my the master
            server (the only place where commits happen), we don't
            technically need to do anything.  Many teams don't use
            Subversion's locking features at all, so it may be a
            non-issue for you.  However, if lock changes aren't
            replicated from master to slaves, it means that clients
            won't be able to query the status of locks
            (e.g. <span class="command"><strong>svn status -u</strong></span> will show no
            information about repository locks.)  If this bothers you,
            you can write <code class="filename">post-lock</code> and
            <code class="filename">post-unlock</code> hook scripts which run
            <span class="command"><strong>svn lock</strong></span> and <span class="command"><strong>svn
            unlock</strong></span> on each slave machine, presumably through
            a remote shell method such as SSH.  That's left as an
            exercise for the reader!</p></div><div class="sect4" lang="en" xml:lang="en"><div class="titlepage"><div><div><h5 class="title"><a id="svn.serverconfig.httpd.extra.writethruproxy.caveats"></a>Caveats</h5></div></div></div><p>Your master/slave replication system should now be
            ready to use.  A couple words of warning are in order,
            however.  Remember that this replication isn't entirely
            robust in the face of computer or network crashes.  For
            example, if one of the automated
            <span class="command"><strong>svnsync</strong></span> commands fails to complete for
            some reason, the slaves will begin to fall behind.  For
            example, your remote users will see that they've committed
            revision 100, but then when they run <span class="command"><strong>svn
            update</strong></span>, their local server will tell them than
            revision 100 doesn't yet exist!  Of course, the problem
            will be automatically fixed the next time another commit
            happens and the subsequent <span class="command"><strong>svnsync</strong></span> is
            successful—the sync will replicate all waiting
            revisions.  But still, you may want to set up some sort of
            out-of-band monitoring to notice synchronization failures
            and force <span class="command"><strong>svnsync</strong></span> to run when things go
            wrong.</p><div class="sidebar"><p class="title"><b>Can we set up replication with
            <span class="command"><strong>svnserve</strong></span>?</b></p><p>If you're using <span class="command"><strong>svnserve</strong></span> instead
              of Apache as your server, you can certainly configure
              your repository's hook scripts to invoke
              <span class="command"><strong>svnsync</strong></span> as we've shown here, thereby
              causing automatic replication from master to slaves.
              Unfortunately, at the time of writing there is no way to
              make slave <span class="command"><strong>svnserve</strong></span> servers
              automatically proxy write requests back to the master
              server.  This means your users would only be able to
              check out read-only working copies from the slave
              servers.  You'd have to configure your slave servers to
              disallow write access completely.  This might be useful
              for creating read-only “<span class="quote">mirrors</span>” of popular
              open-source projects, but it's not a transparent
              proxying system.</p></div></div></div><div class="sect3" lang="en" xml:lang="en"><div class="titlepage"><div><div><h4 class="title"><a id="svn.serverconfig.httpd.extra.other"></a>Other Apache Features</h4></div></div></div><p>Several of the features already provided by Apache in
          its role as a robust Web server can be leveraged for
          increased functionality or security in Subversion as well.
          The Subversion client is able to use SSL, (the Secure Socket
          Layer, discussed earlier).  If your Subversion client is
          built to support SSL, then it can access your Apache server
          using <code class="literal">https://</code> and enjoy a high-quality
          encrypted network session.</p><p>Equally useful are other features of the Apache and
          Subversion relationship, such as the ability to specify a
          custom port (instead of the default HTTP port 80) or a
          virtual domain name by which the Subversion repository
          should be accessed, or the ability to access the repository
          through an HTTP proxy.</p><p>Finally, because <span class="command"><strong>mod_dav_svn</strong></span> is
          speaking a subset of the WebDAV/DeltaV protocol, it's
          possible to access the repository via third-party DAV
          clients.  Most modern operating systems (Win32, OS X, and
          Linux) have the built-in ability to mount a DAV server as a
          standard network “<span class="quote">shared folder</span>”.  This is a
          complicated topic, but also wondrous when implemented.  For
          details, read <a class="xref" href="svn.webdav.html" title="Appendix C. WebDAV and Autoversioning">Appendix C, <i>WebDAV and Autoversioning</i></a>.</p><p>Note that there are number of other small tweaks one can
          make to <span class="command"><strong>mod_dav_svn</strong></span> that are too obscure
          to mention in this chapter.  For a complete list of
          all <code class="filename">httpd.conf</code> directives
          that <span class="command"><strong>mod_dav_svn</strong></span> responds to, see
          <a class="xref" href="svn.ref.mod_dav_svn.conf.html#svn.ref.mod_dav_svn.conf.directives" title="Directives">the section called “Directives”</a>.</p></div></div><div class="footnotes"><br /><hr width="100" align="left" /><div class="footnote"><p><sup>[<a id="ftn.id394499" href="#id394499" class="para">45</a>] </sup>They really hate doing that.</p></div><div class="footnote"><p><sup>[<a id="ftn.id395341" href="#id395341" class="para">46</a>] </sup>While self-signed server certificates are still
              vulnerable to a “<span class="quote">man in the middle</span>” attack,
              such an attack is much more difficult for a casual
              observer to pull off, compared to sniffing unprotected
              passwords.</p></div><div class="footnote"><p><sup>[<a id="ftn.id395569" href="#id395569" class="para">47</a>] </sup>More security-conscious folk might not want to store
              the client certificate password in the runtime
              <code class="filename">servers</code> file.</p></div><div class="footnote"><p><sup>[<a id="ftn.id396291" href="#id396291" class="para">48</a>] </sup>Back then, it was called “<span class="quote">ViewCVS</span>”.</p></div></div></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="svn.serverconfig.svnserve.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="svn.serverconfig.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="svn.serverconfig.pathbasedauthz.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">svnserve, a custom server </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> Path-Based Authorization</td></tr></table></div></body></html>