Jump to Navigation

Mirror an svn repository with svnsync

Image to accompany story

If you like to keep all your work under svn source control, you're probably going to also want to keep a backup of your svn repositories in case of a hardware failure or some other catastrophic event. svn comes with a utility to help you do this - svnsync, which we can use to keep a real-time, read only backup of our svn repositories.

I'm going to assume that you already have your main svn repository set up, and are providing access to it through Apache, however, this will work just as well for repositories served with svnserve.

On the Slave

On your Slave machine, set up a new svn repository. It's very important that you don't make any commits in this repository - it needs to be a blank canvas for svnsync to work with.

svnadmin create /svr/svn/myrepo
chown -R www-data:www-data /svr/svn/myrepo

Since this repository is going to be a read-ony mirror, the best thing is to create a dedicated svnsync user that has read/write access to the repository. This should be the only user that is allowed to write to the repository to avoid accidental repository writes.

Set up Apache to make the repository available over the net.

<Location>
DAV svn
SVNParentPath /srv/svn/repos/
AuthType Basic
AuthName "My Read-only SVN Mirror"
AuthUserFile /srv/svn/dav_svn.passwd
Require valid-user
</Location>

Then create the htpasswd file to allow the svnsync user access to the repository:

htpasswd -c /srv/svn/dav_svn.passwd svnsync

Now, for a little more added security we will limit the repository so that it will only allow our svnsync user to make commits. We do this by creating a start-commit hook (still on the slave machine). Create the file /srv/svn/repos/myproject/hooks/start-commit).

#!/bin/sh
USER="$2"
if [ "$USER" = "svnsync" ];
  then exit 0;
fi
echo "Only the svnsync user may commit new revisions" >&2 exit 1

And by a similar token, we want to be sure that svnsync is the only user that is able to add, modify or delete revision properties. Create the file /srv/svn/repos/myproject/hooks/pre-revprop-change.

#!/bin/sh
USER="$3"
if [ "$USER" = "svnsync" ];
  then exit 0;
fi
echo "Only the svnsync user may change revision properties" >&2 exit 1

Make sure both of these scripts are executable.

chmod 755 /srv/svn/repos/myproject/hooks/start-commit
chmod 755 /srv/svn/repos/myproject/hooks/pre-revprop-change

On the Master

Our Slave machine is now ready, so jump over to the Master machine. First thing we need to do here is to initialise the svnsync target.

svnsync initialize https://target/myproject/ https://source/myproject/ \
--sync-username svnsync --sync-password syncpassword \
--source-username sourceusername --source-password sourcepassword

Next, we want to add a post-commit script to tell our master repository that it should run svnsync after every commit. Create the file /srv/svn/repos/myproject/hooks/post-commit.

#!/bin/sh
SVNSYNC=/usr/bin/svnsync
TO=http://my.slave.machine/myproject/
SYNC_USER=svnsync
SYNC_PASS=syncpassword
SOURCE_USER=me
SOURCE_PASS=mypassword
 
$SVNSYNC --non-interactive sync $TO \
--sync-username $SYNC_USER --sync-password $SYNC_PASS \
--source-username $SOURCE_USER --source-password $SOURCE_PASS &  exit 0

One last thing, we also want to ensure that changes to revision properties are also synced. Create the file /srv/svn/repos/myproject/hooks/post-revprop-change.

#!/bin/sh
SVNSYNC=/usr/bin/svnsync
TO=http://my.slave.machine/myproject/
SYNC_USER=svnsync
SYNC_PASS=syncpassword
SOURCE_USER=me
SOURCE_PASS=mypassword
 
$SVNSYNC --non-interactive copy-revprops $TO \
--sync-username $SYNC_USER --sync-password $SYNC_PASS \
--source-username $SOURCE_USER --source-password $SOURCE_PASS $2 & exit 0

Make sure both of these scripts are executable.

chmod 755 /srv/svn/repos/myproject/hooks/post-commit
chmod 755 /srv/svn/repos/myproject/hooks/post-revprop-change

And that should be it!

Summing up

Hopefully, you should now find that any commits you make on your main svn repository are automatically synced over to a read-only backup. I must say that I haven't tested this extensively - it took me several years to even getting round to setting it up, but I now feel a lot safer in the knowledge that I will always have an up-to-date backup of my work.

Gotchas

Well, this one got me stumped for a good while... On my Master machine, I am serving my repositories with Apache over ssl (https). Apache is running under the www-data user, and since svnsync is being run on a post-commit hook, it too will run as the www-data user. Now in a normal situation, attempting to run svnsync against a server which is using a self-signed certificate like mine, would result in a prompt asking me if I would like to accept the certificate. It is possible to tell svn to accept specific certificates by adding the following to www-data's ~/.subversion/servers file:

ssl-authority-files = /etc/ssl/certs/svn.myserver.mydomain.pem

Comments

Anonymous's picture

SVN is so last year! Get with the times... :D

Anonymous's picture

Thanks for the howto. I might give this a try in the future. Right now I am using a traditional backup scheme.

Thanks!
Shrop

Anonymous's picture

Even better...mirror it with git-svn. Git > SVN in every way possible!

Anonymous's picture

first, can I run this on my post commit file:
svnsync initialize https://target/myproject/ https://source/myproject/ \
--sync-username svnsync --sync-password syncpassword \
--source-username sourceusername --source-password sourcepassword

How does the system know what svnsync is?

then, when I run your code above where SVNSYNC is a variable, how do you know what path to use.../usr/bin/svnsync?
my svnsync.exe file is located in /program files/visualSVN server/bin/

can you help me figure out how to use this code? I have followed the above steps, except for the initialize (i added that into my post commit file since i had not idea how to run it), however, it seems like it all comes down to either the initialize, and then the path to the svnsync.

Can you give me some guidence????

thanks
Dan

Anonymous's picture

Hi,, Thanks for the information. i have tried with my mac and ubuntu machine. in my both the i have configured Subversion on http protocol . and then i have tried with main server .which is on debian. in that i have configure subversion server on svn+ssh protocol and my mirroring machine on http protocol.. all commands are working fine . but mirroring is not going on .. any idea ??

Anonymous's picture

hi While Running Post Commit Script on Master machine.. It is giving Following error "Permission denied (publickey,password). svnsync: Connection closed unexpectedly" My Destination Running on http Protocol and my sourcemachine is running on svn+ssh protocol

Please share your thoughts, comments and suggestions...

The content of this field is kept private and will not be shown publicly. If you have a Gravatar account, used to display your avatar.
If you have your own website, enter its address here and we will link to it for you. (please include http://).
eg. http://www.kirkdesigns.co.uk