Installer un serveur Subversion et USVN (UserFriendly SVN) sur Debian
Subversion (SVN de son petit nom) est un outil de gestion de version concurrentes (et un concurrent à CVS... comprenne qui pourra ;D). Il permet d'historiser les différentes évolutions du code source d'un logiciel, ainsi que de gérer les éventuels conflits entre les modifications effectuées par plusieurs développeurs. Tout seul ou en équipe, un tel outil devient vite indispensable pour gérer les sources. USVN quand à lui est une interface Web d'administration de Subversion. Elle autorise l'administration des utilisateurs, groupes, et projets de votre dépôt sans avoir à utiliser un outil d'administration en ligne de commande. Ce guide vous aide à effectuer une installation complète de Subversion et USVN sur Debian.
Pré-requis
Ce guide nécessite un serveur MySQL disposant du script mysql-tools disponible dans le guide Installer et configurer MySQL sur Debian.
Ce guide nécessite un serveur Apache 2 avec support du PHP disposant du script a2tools disponible dans mon guide Installer Apache 2 sur Debian.
Paramètres
Renseignez le nom de domaine ou sera disponible l'application USVN :
USVN_DOMAIN="usvn.domaine-exemple.fr"
Renseignez le nom de domaine ou seront disponibles les dépôts SVN :
SVN_DOMAIN="svn.domaine-exemple.fr"
Si vous utilisez un reverse proxy HTTPS en facade de votre serveur SubVersioN, ou que vous comptez modifier la configuration Apache pour utiliser HTTPS, veuillez modifier la commande suivante en remplaçant "http" par "https" :
SVN_PROTOCOL="http"
Renseignez le nom d'hôte de votre serveur MySQL (si vous ne savez pas de quoi il s'agit, ne modifiez pas cette valeur) :
MYSQL_HOST="localhost"
Si votre serveur MySQL n'est pas local, ce guide effectuera une connexion SSH pour y créer la base de données.
Installation
Serveur HTTP
Installez les dépendances de l'application:
command apt-get install subversion libapache2-svn \ php5-mysql php5-cli apg mysql-client apache2-utils
Activez les modules d'Apache 2 nécessaires à l'application (le module de réécriture d'URL et le module du serveur SubVersioN) :
command a2enmod rewrite command a2enmod dav_svnRedémarrez le serveur HTTP pour prendre en compte les nouveaux paramètres :
/etc/init.d/apache2 force-reload
Installation de USVN
Récupérez l'URL de la dernière version de USVN :
SOURCE_URL="$(command wget --quiet --output-document=- "http://www.usvn.info/download" \ | command grep '/tgz.dl' | command tail -n 1 \ | command sed -e 's|.*href="\([^"]*\)".*|http://www.usvn.info/\1|')"
Téléchargez USVN :
command wget "${SOURCE_URL}" \ --output-document="/tmp/usvn.tgz"
Décompressez l'archive :
command tar --directory "/tmp" -xzf "/tmp/usvn.tgz"
Déplacez le dossier obtenu vers son emplacement final :
command mv "/tmp/usvn-"* "/opt/${USVN_DOMAIN}"
Corrigez les permissions par défaut des dossiers :
command chown -R root:root "/opt/${USVN_DOMAIN}"
Nous créons le dossier destiné à recevoir les fichiers du dépôt Subversion, ainsi que quelques fichiers de configuration de USVN:
command mkdir --parent "/var/lib/usvn/${USVN_DOMAIN}/svn" command chown -R www-data:www-data "/var/lib/usvn/${USVN_DOMAIN}"
Créez la base de données :
if [ "${MYSQL_HOST}" = "localhost" ]; then MYSQL_PARAMS=$(command mysql-tools create-domain-db "${USVN_DOMAIN}") else command echo "Saisissez le mot de passe de l'utilisateur root MySQL :" command read PASSWORD MYSQL_PARAMS=$(command ssh "root@${MYSQL_HOST}" "command mysql-tools create-domain-db '${USVN_DOMAIN}' '$(command cat /etc/mailname)' '${PASSWORD}'") fi
Récupérez les paramètres de la nouvelle base de données :
MYSQL_DB="$(echo "${MYSQL_PARAMS}" | command grep -e "^MYSQL_DB" \ | command cut --delimiter="=" --fields="2-")" MYSQL_USER="$(echo "${MYSQL_PARAMS}" | command grep -e "^MYSQL_USER" \ | command cut --delimiter="=" --fields="2-")" MYSQL_PASSWORD="$(echo "${MYSQL_PARAMS}" | command grep -e "^MYSQL_PASSWORD" \ | command cut --delimiter="=" --fields="2-")" echo "${MYSQL_PARAMS}"
Nous générons un préfixe de table aléatoire :
MYSQL_PREFIX="$(command apg -q -a 0 -n 1 -M NCL)_"
Initialisez le contenu de la base de données :
command cat "/opt/${USVN_DOMAIN}/library/SQL/mysql.sql" \ | command sed -e "s/usvn_/${MYSQL_PREFIX}/g" \ | command mysql --user="${MYSQL_USER}" --password="${MYSQL_PASSWORD}" \ --host="${MYSQL_HOST}" "${MYSQL_DB}"
Choisissez un mot de passe pour le compte d'administration :
ADMIN_PASSWORD="$(command apg -q -a 0 -n 1 -M NCL)"
Créez le fichier htpasswd de votre installation SubVersioN :
command htpasswd -cbm "/var/lib/usvn/${USVN_DOMAIN}/${SVN_DOMAIN}.htpasswd" "admin" "${ADMIN_PASSWORD}"
Ajustez les permissions du fichier ainsi créé :
command chown www-data:www-data "/var/lib/usvn/${USVN_DOMAIN}/${SVN_DOMAIN}.htpasswd"
Récupérez la version chiffrée du mot de passe du compte admin :
ADMIN_SECRET="$(command grep "admin" "/var/lib/usvn/${USVN_DOMAIN}/${SVN_DOMAIN}.htpasswd" \ | command cut --delimiter=":" --fields="2-")"
Créez le compte d'administration :
command echo "INSERT INTO ${MYSQL_PREFIX}users (users_login, users_password, users_lastname, users_firstname, users_email, users_is_admin, users_secret_id) VALUES ('admin', '${ADMIN_SECRET}', 'Systeme', 'Administrateur', 'root@localhost', 1, '$(command apg -q -m 32 -x 32 -a 1 -n 1 -M NL)');" \ | command mysql --user="${MYSQL_USER}" --password="${MYSQL_PASSWORD}" \ --host="${MYSQL_HOST}" "${MYSQL_DB}"
Créez la configuration de USVN :
command cp "/opt/${USVN_DOMAIN}/config/config.ini.exemple" "/opt/${USVN_DOMAIN}/config/config.ini" command sed -i -e 's|^url.base.*$|url.base = ""|' \ -e "s|system.locale.*$|system.locale = \"${LANG}\"|" \ -e "s|template.name.*$|template.name = \"usvn\"|" \ -e "s|site.ico.*$|site.ico = \"medias/usvn/images/logo_small.tiff\"|" \ -e "s|site.logo.*$|site.logo = \"medias/usvn/images/logo_trans.png\"|" \ -e "s|subversion.path.*$|subversion.path = \"/var/lib/usvn/${USVN_DOMAIN}\"|" \ -e "s|subversion.passwd.*$|subversion.passwd = \"/var/lib/usvn/${USVN_DOMAIN}/${SVN_DOMAIN}.htpasswd\"|" \ -e "s|subversion.authz.*$|subversion.authz = \"/var/lib/usvn/${USVN_DOMAIN}/${SVN_DOMAIN}.authz\"|" \ -e "s|subversion.url.*$|subversion.url = \"${SVN_PROTOCOL}://${SVN_DOMAIN}/\"|" \ -e "s|database.adapterName.*$|database.adapterName = \"PDO_MYSQL\"|" \ -e "s|database.prefix.*$|database.prefix = \"${MYSQL_PREFIX}\"|" \ -e "s|database.options.host.*$|database.options.host = \"${MYSQL_HOST}\"|" \ -e "s|database.options.username.*$|database.options.username = \"${MYSQL_USER}\"|" \ -e "s|database.options.password.*$|database.options.password = \"${MYSQL_PASSWORD}\"|" \ -e "s|database.options.dbname.*$|database.options.dbname = \"${MYSQL_DB}\"|" \ "/opt/${USVN_DOMAIN}/config/config.ini" echo 'update.checkforupdate = "1" update.lastcheckforupdate = "0"' >> "/opt/${USVN_DOMAIN}/config/config.ini"
Mettez en place le fichier htaccess :
command echo '<Files *.ini> Order Allow,Deny Deny from all </Files> php_flag short_open_tag on php_flag magic_quotes_gpc off RewriteEngine on #RewriteCond RewriteBase "/" RewriteCond %{REQUEST_FILENAME} -f [OR] RewriteCond %{REQUEST_FILENAME} -l [OR] RewriteCond %{REQUEST_FILENAME} -d RewriteRule ^.*$ - [NC,L] RewriteRule ^.*$ index.php [NC,L]' \ > "/opt/${USVN_DOMAIN}/public/.htaccess"
Mettez en place la configuration d'Apache 2 :
command a2tools add-vhost "${USVN_DOMAIN}" "/opt/${USVN_DOMAIN}/public/" "Limit FileInfo Options"
Mettez en place la configuration du serveur SubVersioN :
command a2tools add-vhost "${SVN_DOMAIN}" "/var/lib/usvn/${USVN_DOMAIN}/svn" command sed -i -e "0,/<\/Location>/{//i\\ ErrorDocument 404 default\\ DAV svn\\ #SSLRequireSSL\\ Require valid-user\\ SVNParentPath /var/lib/usvn/${USVN_DOMAIN}/svn\\ SVNListParentPath off\\ AuthType Basic\\ AuthName \"USVN\"\\ AuthUserFile /var/lib/usvn/${USVN_DOMAIN}/${SVN_DOMAIN}.htpasswd\\ AuthzSVNAccessFile /var/lib/usvn/${USVN_DOMAIN}/${SVN_DOMAIN}.authz };" \ -e 's/DocumentRoot/#DocumentRoot/g' \ "/etc/apache2/sites-available/http-${SVN_DOMAIN}"
Rechargez la configuration de votre serveur HTTP :
/etc/init.d/apache2 force-reload
Nettoyez le dossier USVN en retirant les fichiers liés à l'installation :
command rm "/opt/${USVN_DOMAIN}/public/dot.htaccess" command rm "/opt/${USVN_DOMAIN}/public/install.php"
Vous pouvez à présent vous connecter à votre application en utilisant les paramètres affichés par la commande :
command echo "Les identifiants de connexion à l'administration d'USVN sont: * URL d'accès : http://${USVN_DOMAIN} * Identifiant : admin * Mot de passe : ${ADMIN_PASSWORD}"
Important : Conservez précieusement le login et mot de passe affichés par cette ligne de commande !
Sécurisation de l'installation
Afin de sécuriser notre dépôt SVN contre les attaques en force brute, nous installons fail2ban:
command apt-get install fail2ban
Et nous le configurons pour surveiller les logs d'Apache:
command sed -i -e '/\[apache\]/, /filter/ {0,/^enabled.*/ s//enabled = true/ }' \ /etc/fail2ban/jail.conf
Il vous faut maintenant redémarrer fail2ban:
/etc/init.d/fail2ban restart
Sauvegardes
Pour sauvegarder votre installation USVN, élément très important puisque le SVN est déjà la sauvegarde des différentes version de votre code, je vous propose d'utiliser Backup Manager. Pour l'installer, vous pouvez suivre mon guide :
Installer et configurer Backup Manager sur Debian 4.0 Etch
Important: Sauvegarder les fichiers ne suffit pas ! Il faut aussi sauvegarder la base de données. Une procédure pour ce faire est disponible dans l'article MySQL sur Debian 4.0 Etch.
Une fois Backup Manager installé, vous pouvez configurer la sauvegarde des fichiers de USVN avec les commandes suivantes:
command update-bm-folders add "/opt/${USVN_DOMAIN}" command update-bm-folders add "/var/lib/usvn/${USVN_DOMAIN}"
Il faut aussi sauvegarder les dépôts Subversion gérés par USVN. Comme leur nombre peut varier en fonction de vos opération d'administration de USVN, nous devons configurer Backup Manager pour obtenir automatiquement la liste des dépots présents. Cela se fait grâce à la ligne de commande suivante:
command sed -i -e "s|\\(BM_SVN_REPOSITORIES=\\).*$|\\1\$(command find /var/lib/usvn/${USVN_DOMAIN}/svn/ -mindepth 1 -maxdepth 1 -type d)|" \ /etc/backup-manager.conf
Activez la sauvegarde des dépôts Subversion:
command sed -i -e 's/[#]*\(.*BM_ARCHIVE_METHOD=.*".*\)"$/\1 svn"/' \ /etc/backup-manager.conf
Reverse proxy HTTPS vers HTTP Apache et SubVersioN
Si vous souhaitez mettre en place un Reverse Proxy HTTPS devant votre serveur SubVersioN, voici un exemple de configuration fonctionnelle. Les lignes importantes sont graissées :
<VirtualHost *:443> # Uncomment this line and set it up with your actual webmaster email # or with your real email. #ServerAdmin webmaster@my-domain.com # Your actual domain name, on witch this virtual host is available. ServerName svn.landure.fr # You may want your site to be available on other domain names, this is # what alias are for. # You can use the * wildcard caracter to match multiple sub-domains. #ServerAlias www2.my-domain.com www.my-other-domain.com *.yet-another-domain.com # The error log and access log. This can be used by awstats # Note : since we keed theses logs in /var/log/apache2, they are # automaticaly rotated by logrotate :D. ErrorLog /var/log/apache2/svn.landure.fr-error.log LogLevel warn CustomLog /var/log/apache2/svn.landure.fr-access.log combined <IfModule mod_ssl.c> # # SSL magic # # We enable the SSL engine. Without this line, we use HTTP, not HTTPS. SSLEngine On # We allow only "high" and "medium" security key lengths. SSLCipherSuite HIGH:MEDIUM # We allow SSLv3 and TLSv1 only, we reject the old SSLv2. SSLProtocol all -SSLv2 # Server public certificate file: SSLCertificateFile /etc/apache2/ssl/https_cert.pem # Server private key file: SSLCertificateKeyFile /etc/apache2/ssl/https_key.pem </IfModule> # Theses lines only apply of the rewrite module is enabled. # This is a security enhancement recommanded by the nessus tool. <IfModule mod_rewrite.c> RewriteEngine on RewriteCond %{REQUEST_METHOD} ^(TRACE|TRACK) RewriteRule .* - [F] </IfModule> <IfModule mod_rewrite.c> <IfModule mod_proxy.c> # Do not ever never comment this line ! # This line prevent your web server to be used # as a proxy server by lurkers and other lamers. ProxyRequests Off # This little option pass the hostname to the proxyfied server. # This allow you to setup virtual hosts on the proxyfied server. # Yay ! This can be a life saver, so trust me, you want this option On. ProxyPreserveHost On # We use a HTTP subversion server behind a HTTPS reverse proxy ? # We need to fix the Destination header. # For details, please visit : http://silmor.de/49 # This configuration need the mod headers : a2enmod headers. # We replace all https in destination hearder by http. RequestHeader edit Source ^https:// http:// early RequestHeader edit Destination ^https:// http:// early # This do the same thing as over but allow Destination url to be different from the frontend ones. # RewriteCond %{HTTP:Destination} http[s]?://[^/]*/(.*$) # RewriteRule ^/.* - [E=MyDestination:http://svn.landure.fr/%1,PT] # RequestHeader set Destination %{MyDestination}e env=MyDestination # RewriteCond %{HTTP:Source} http[s]?://[^/]*/(.*$) # RewriteRule ^/.* - [E=MySource:http://svn.landure.fr/%1,PT] # RequestHeader set Source %{MySource}e env=MySource # Here is the magic that proxyfy the LAN server. # The first line is .... i don't remember what... # but trust me, it is usefull ;p. # The second line is a rewrite rule that do the proxy # magic. I was used to use a ProxyPass rule to do this work, but it # turned out that sometimes ProxyPass give you a 503 error when under # heavy load. The RewriteRule does not have this flow. ProxyPassReverse / http://subversion.landure.xen/ RewriteRule ^/(.*) http://subversion.landure.xen/$1 [P,L] # RewriteLog /var/log/apache2/svn.landure.fr-rewrite.log # RewriteLogLevel 9 </IfModule> </IfModule> # This Location directives allow users to access to the proxyfied contents. # Do not remove this if you want your site to work :). <Location /> # This allow SVN protocol specific methods. Without this, the reverse proxy reject svn commands. <Limit OPTIONS PROPFIND GET REPORT MKACTIVITY PROPPATCH PUT CHECKOUT MKCOL MOVE COPY DELETE LOCK UNLOCK MERGE> Order deny,allow Allow from all Satisfy Any </Limit> Order deny,allow Allow from all </Location> </VirtualHost>
Migration vers le nouveau serveur
Cas simple : organisation similaire
Si vous disposiez déjà d'un serveur Subversion organisé de manière à ce qu'à chaque projet corresponde un dépôt, la migration se fait très simplement.
- La première étape est de recréer vos projets via l'interface USVN, en prenant bien garde de décocher l'option de création des répertoires standards (/trunk, /branches et / tags).
- Une
fois tous vos projets créés, ouvrez une ligne de commande sur l'ancien
serveur SVN, et créez une sauvegarde du contenu de chacun de vos dépôt
en exécutant autant de fois que nécessaire la commande:
svnadmin dump /path/to/repository/for/project | gzip -9 - > project.dump.gz
- Copiez les fichiers de sauvegarde ainsi obtenus sur le nouveau serveur (scp est votre ami :)).
- Sur le nouveau serveur, importez les sauvegardes en exécutant autant de fois que nécessaire la commande:
su www-data -c "zcat project.dump.gz | svnadmin load /var/lib/subversion/svn/project"
- Une fois l'import terminé, vérifiez que tout s'est bien déroulé en récupérant votre projet, et en vérifiant que tout s'y trouve:
svn checkout http://svn.domaine.com/project ./project
Remarque: Si vous disposez d'une copie de travail qui utilise l'ancien dépôt, vous pouvez la faire pointer vers le nouveau dépôt à l'aide de la commande:
svn switch --relocate http://svn.vieux-server.com/project/trunk http://svn.domaine.com/project/trunk
Source: Merci à Ned Batchelder pour son article How to move a subversion repository.
Cas complexe : modification de l'organisation
C'est un cas que j'ai rencontré. L'ancien serveur SVN possédait une organisation de projet basée non pas sur "un dépôt par projet", mais sur "un dossier par projet".
Dans ce cas, il est nécessaire de modifier l'organisation de ce dépôt pour la faire correspondre à la méthode "un dépôt par projet".
- La première étape est de recréer vos projets via l'interface USVN, en prenant bien garde de décocher l'option de création des répertoires standards (/trunk, /branches et / tags).
- Une fois tous vos projets créés, ouvrez une ligne de commande sur
l'ancien serveur SVN, et créez une sauvegarde du contenu de chacun de
vos dépôt en exécutant autant de fois que nécessaire la commande:
svnadmin dump /path/to/repository \ | svndumpfilter include /folder/for/project/ \ | gzip -9 - > project.dump.gz
Remarque: La commande svndumpfilter ne conserve que les changements effectués dans le dossier spécifié. CEPENDANT, elle ne supprime pas les révisions vides , c'est à dire ne contenant aucun changements dans le dossier spécifié. Si vous souhaitez supprimer les révisions vides, et renuméroter les révisions sauvegardées, utilisez la commande suivante pour la sauvegarde du projet:
svnadmin dump /path/to/repository \ | svndumpfilter include --drop-empty-revs --renumber-revs /folder/for/project/ \ | gzip -9 - > project.dump.gz
- Copiez les fichiers de sauvegarde ainsi obtenus sur le nouveau serveur (scp est votre ami :)).
- Il
vous faut maintenant préparer l'import de votre dossier dans le nouveau
serveur Subversion. Pour ce faire, 2 solutions s'offrent à vous.
- Solution simple: Conserver le même emplacement dans le
nouveau serveur, et déplacer après import. Pour ce faire, si le dossier
de votre projet sur l'ancien dépôt était /folder/for/project/, il vous faut recréer l'arborescence /folder/for/ sur le nouveau serveur (on ne crée pas le dossier "project". Cela peut se faire simplement avec la commande:
svn mkdir -m "* Recréation de l'arborescence." http://svn.domaine.com/folder/ svn mkdir -m "* Recréation de l'arborescence." http://svn.domaine.com/folder/for/
- Solution complexe: Si vous ne souhaitez pas déplacer vos
dossiers importés après l'import, vous pouvez modifier manuellement le
fichier de dump pour obtenir le résultat souhaité. Par exemple, pour
placer le contenu du dossier "project" à la racine du nouveau dépôt SVN,
vous pouvez utiliser la commande suivante (résultats non garantis):
zcat project.dump.gz | sed -e 's|folder/for/project/||g' | gzip -9 - > moved-project.dump.gz
- Solution simple: Conserver le même emplacement dans le
nouveau serveur, et déplacer après import. Pour ce faire, si le dossier
de votre projet sur l'ancien dépôt était /folder/for/project/, il vous faut recréer l'arborescence /folder/for/ sur le nouveau serveur (on ne crée pas le dossier "project". Cela peut se faire simplement avec la commande:
- Sur le nouveau serveur, importez les sauvegardes en exécutant autant de fois que nécessaire la commande:
su www-data -c "zcat project.dump.gz | svnadmin load /var/lib/subversion/svn/project"
- Une fois l'import terminé, vérifiez que tout s'est bien déroulé en récupérant votre projet, et en vérifiant que tout s'y trouve:
svn checkout http://svn.domaine.com/project ./project
Sources:
- Merci à Mostly Harmless pour l'article Moving a folder across SVN repositories.
- Merci à Stéphane Bortzmeyer pour son excellent article Copier un sous-arbre d'un dépôt Subversion vers un autre dépôt.
Remarque: si vous souhaitez passer de l'organisation "un dépot par projet" à une organisation "un dossier par projet", cela se fait très simplement grâce à l'option de --parent-dir de svnadmin load:
zcat project.dump.gz | svnadmin load --parent-dir /dossier/dans/projet /var/lib/subversion/svn/project
Remerciements
- Merci aux développeurs de Subversion.
- Merci aux développeurs de UserFriendly SVN.
- Merci aux auteurs du Livre rouge Subversion (anglais).
- Merci à Aurélien Joga pour m'avoir signalé un problème d'encodage qui peut se poser dans certaines configurations.
sous domaines etc...
usvn.domaine.com est un exemple. Pour suivre ce tuto, il vous faut posséder un nom de domaine, ou utiliser votre fichier hosts. Intéressez vous aux documentations concernant les domaines et sous domaines.
Vous devez créez les sous-domaines svn et usvn sur votre domaine et les faire pointer vers votre serveur.
Bon courage
web usvn
Toutefois, dans la théorie, que je tape http://usvn.domaine.com ou http://<adressIpServeur> cela ne devrait rien changer, je me trompe ?
hotes virtuels
Hotes Virtuels
Cependant, durant l'exploitation du tuto, j'obtiens ceci :
srvsvn:/etc/apache2/sites-available# /usr/sbin/apache2ctl -t
Warning: DocumentRoot [/opt/usvn] does not exist
[Fri Dec 18 17:32:01 2009] [warn] NameVirtualHost *:80 has no VirtualHosts
Syntax OK
Après ce que vous venez de me dire, je suppose que ça ne peut pas fonctionner avec cette erreur !?
bon ....
Avez vous utilisé un dossier d'installation différent ?
Pour ce qui est du *:80, ce guide est prévu pour un dépot svn en https (*:443), de mémoire du moins. Trouvez un howto sur la configuration d'apache. cela sera très formateur.
Bon courrage
Petite erreur dans une commande (avec USVN 1.0.5+Boo en tout cas)
command cp "/opt/${USVN_DOMAIN}/config/config.ini.exemple" "/opt/${USVN_DOMAIN}/config/config.ini"
doit être remplacée par
command cp "/opt/${USVN_DOMAIN}/config/config.ini.example" "/opt/${USVN_DOMAIN}/config/config.ini"
avec une install USVN 1.0.5+Boo
Petite erreur dans une commande (avec USVN 1.0.5+Boo en tout cas)
-e "s|system.locale.*$|system.locale = \"${LANG}\"|" \
qui fait directement planter la version 1.0.5 sur une installation Debian fr_CH.
Autre petite amélioration :
Ajouter
# Ajustez les permissions du fichier ainsi créé :
chown www-data:www-data "/opt/${USVN_DOMAIN}/config/config.ini"
après la création du fichier de config de USVN
Mais sinon c'est un super tuto. Bravo !
(mon commentaire précédent est parti tout seul et trop tôt ;)
domaine usvn