Subversion desde Apache usando virtual hosts y locations

July 17, 2009 at 14:41

Aunque hay bastantes guías que cubren cómo configurar un WebDAV para acceder a un repositorio Subversion mediante HTTP usando el servidor Apache, aquí os presento la mía, en la que configuro el acceso a un conjunto de repositorios usando un virtual host y distintas locations (es decir, es una guía más con la configuración que a mi más me gusta 😀 ).

Lo primero que debemos hacer es asegurarnos de que tenemos el módulo adecuado. En Debian, por ejemplo, podemos buscarlo e instalarlo si es necesario usando los siguientes mandatos:

$ aptitude search apache subversion | grep svn
# aptitude install libapache2-svn

Además, deberemos asegurarnos de que Apache habilita el módulo, lo cual, nuevamente en Debian, es trivial gracias a la buena organización que tiene de la configuración de Apache:

$ a2enmod dav_svn
# /etc/init.d/apache2 restart

El siguiente paso es crear un repositorio Subversion. Lo habitual es crear uno por proyecto, aunque en mi caso no lo hago así exactamente. Por ejemplo, tengo un repositorio al que llamo personal en el que tengo mi CV, algunas prácticas y cosas pequeñas en las que es más que improbable que participe nadie más que yo. Depende del criterio de cada uno (por ejemplo, a mi siempre me resulta tentador tener un único respositorio para todo, y a la hora de hacer el checkout, hacerlo con ruta relativa al proyecto que necesito), pero recordad que los usuarios, contraseñas y permisos serán los mismos para todo un repositorio. La creación del repositorio la hacemos con los mandatos:

$ mkdir -p /opt/svn/nombre_del_repositorio/
$ svnadmin create /opt/svn/nombre_del_repositorio/repo

Podemos verificar que funciona intentando hacer un checkout:

$ svn co file:////opt/svn/nombre_del_repositorio/repo /tmp/

Por último, creamos los usuarios y passwords del repositorio:

$ mkdir -p /opt/svn/nombre_del_repositorio/passwords/
$ htpasswd -c /opt/svn/nombre_del_repositorio/passwords/.htpasswd usuario

Y procedemos a crear el fichero de configuración del virtual host de Apache. En el ejemplo, lo voy a hacer para dos repositorios, uno llamado personal y otro llamado público, suponiendo que quiera acceder a ambos a través del mismo dominio (svn.deigote.com) pero con distintas localizaciones (/personal y /publico):

<VirtualHost *:80>
   ServerName svn.deigote.com
   DocumentRoot /opt/websites/svn.deigote.com

Como véis, definimos un virtual host para el dominio elegido, y le asignamos un docroot, en el que podríamos poner una página de inicio o incluso vacía (para que si alguien entra directamente en el dominio, no vea el clásico It works! situado en /var/www 😀 )(1).

A partir de aquí, para cada localización (personal y publico) establecemos que es un WebDAV de tipo Subversion, e indicamos la ruta del repositorio y del fichero de passwords, tanto para el repositorio personal:

   <Location "/personal" >
     DAV svn
     SVNPath /opt/svn/personal/repo

     AuthType Basic
     AuthName "SVN Deigote - Personal"
     AuthUserFile /opt/svn/personal/passwords/.htpasswd
     Require valid-user

     Order deny,allow
     Deny from all
     Allow from unaipdeconfianza.com
   </Location>

como para el repositorio público:

   <Location "/publico" >
     DAV svn
     SVNPath /opt/svn/publico/repo

     AuthType Basic
     AuthName "SVN Deigote - Publico"
     AuthUserFile /opt/svn/publico/passwords/.htpasswd
     <LimitExcept GET PROPFIND OPTIONS REPORT>
       Require valid-user
     </LimitExcept>
   </Location>

Podemos ver un par de diferencias. Mientras que el repositorio personal pide un usuario válido para todos los casos (es decir, un usuario definido en el fichero de passwords), el repositorio público especifica que necesita un usuario válido excepto para algunas acciones. Básicamente, son el conjunto de acciones que permiten lectura y navegación por el repositorio. De esta manera, todo el mundo podrá ver (acciones checkout, update, etcétera) pero sólo los usuarios válidos podrán escribir (acción commit, add, etcétera) (2)

La otra diferencia es que el repositorio personal tiene una sección que especifica que el acceso es denegado para todos, y admitido para una ip o nombre de dominio. Esto te garantiza que la persona que accede a tu repositorio lo está haciendo desde una IP de tu confianza, aumentando ligeramente la paranoia seguridad.

Añadir que el directorio raiz (/) es un location válido, por lo que podemos configurar un único repositorio para el dominio, aunque sería equivalente a poner dicha configuración directamente en el contexto del virtual host en vez de en el del location.

Añadiendo la información de logs y demás, el fichero de virtual host de ejemplo (/etc/apache2/sites-available/svn.deigote.com) queda como se ve a continuación:

<VirtualHost *:80>
   ServerName svn.deigote.com
   DocumentRoot /opt/websites/svn.deigote.com
   <Location "/personal" >
     DAV svn
     SVNPath /opt/svn/personal/repo

     AuthType Basic
     AuthName "SVN Deigote - Personal"
     AuthUserFile /opt/svn/personal/passwords/.htpasswd
     Require valid-user

     Order deny,allow
     Deny from all
     Allow from unaipdeconfianza.com
   </Location>

   <Location "/publico" >
     DAV svn
     SVNPath /opt/svn/publico/repo

     AuthType Basic
     AuthName "SVN Deigote - Publico"
     AuthUserFile /opt/svn/publico/passwords/.htpasswd
     <LimitExcept GET PROPFIND OPTIONS REPORT>
       Require valid-user
     </LimitExcept>
   </Location>

   ErrorLog /var/log/apache2/error_svn.deigote.com.log
   LogLevel warn
   CustomLog /var/log/apache2/access_svn.deigote.com.log combined
</VirtualHost>

Lo añadimos a la lista de sites y reiniciamos Apache, y ya estamos listos para jugar:

$ a2ensite svn.deigote.com
$ /etc/init.d/apache restart
$ svn co http://svn.deigote.com/personal
$ svn co http://svn.deigote.com/publico

Como nota final, ojo con los passwords. Tened en cuenta que estamos configurando un acceso a través de HTTP, por lo que la información no va encriptada. Para que sí lo fuera tendríamos que configurar el virtual host para ir a través de HTTPS, pero eso lo dejamos para un próximo capítulo (más que nada porque todavía no he aprendido a hacerlo 🙂 ).

(1) Tened cuidado de no crear directorios en el document root con el mismo nombre que los location. Os encontraréis con un error de este estilo al hacer el checkout:

$ ls /opt/websites/svn.deigote.com # Docroot
personal
$ svn co http://svn.deigote.com/personal/ /tmp/personal
Authentication realm: SVN Deigote - Personal
Password for 'deigote':
svn: PROPFIND request failed on '/personal'
svn: PROPFIND of '/personal': 301 Moved Permanently (http://svn.deigote.com)
$ rmdir /opt/websites/svn.deigote.com/personal
$ svn co http://svn.deigote.com/personal/ /tmp/personal
...
Checked out revision 1

(2) Se puede afinar más usando mod_authz_svn, que permite establecer qué usuarios pueden escribir y cuáles pueden leer sin complicarse mucho, pero yo de momento no lo he necesitado, así que queda para el siguiente capítulo 🙂