Last Updated: 21 Nov 2020

   |   

Author: (external edit)

Setting Up Subversion (SVN) with SSH (svn+ssh)

This is a quick guide on how to setup subversion using svn+ssh. svn+ssh lets us tunnel a subversion session over the secure SSH protocol, which means all data and passwords are encrypted. I like setting subversion up this way because:

  1. it authenticates against a real user account, so you don't have to maintain a seperate set of subversion logins and passwords.
  2. it is secure, so you don't have to worry about data or passwords being intercepted in transit.

This was done on CentOS, but the instructions apply to most any OS.

Server Setup

  1. Install Subversion. The mechanics of installing it vary OS by OS; see the 'Getting subversion' page for more. On CentOS, you'll do:
    yum install subversion
  2. Create a Repository. This is where all your files will be stored. You can put this anywhere; I generally think /var/svn/repos is a good place. Call your repo whatever you want; I used 'my_code':
    mkdir /var/svn
    mkdir /var/svn/repos
    svnadmin create /var/svn/repos/my_code
  3. Setup a svn group. You'll need all your users to be members of the same group. I generally setup an svn group, and give access to anybody who needs to access subversion.
  4. Give your group ownership of the repos directory. chown -R :svn /var/svn/repos/
  5. Set permissions on same. chmod -R 775 /var/svn/repos/
  6. Setup a user for each person who needs svn access. See Adding a User & Groups in CentOS.
  7. Add those users to the svn group.
  8. Create a wrapper for svnserve. svnserve is the server component of subversion; when your subversion client connects via SSH, it spawns an instance of svnserve running under your user account. The problem here is the 'under your user account' part; that means it is running under your user account's permissions setup. By default, your permissions don't allow anyone else access to your files, and yet svnserve is going to be writing files in the common user directory at /var/svn/repos that everyone needs write access to. Therefore, we can create a wrapper script that sets a umask for group-writable peermissions right before svnserve is called:
    #!/bin/sh 
    
    # set the umask so files are group-wriable
    umask 002
    
    # call the 'real' svnserve, also passing in the default repo location
    exec /usr/bin/svnserve "$@" -r /var/svn/repos

    Save this somewhere, like /var/svn/svnwrapper.sh. Make a symlink in /usr/local/bin:

    cd /usr/local/bin
    ln -s /var/svn/svnwrapper.sh svnserve
    chmod 755 /var/svn/svnwrapper.sh

    Update 2 Dec 2010: Per the comments from Fred & Timothy Boronczyk, I now recommend that you put the symlink in /usr/local/bin rather than /usr/bin as I originally recommended. This means you avoid having to move the original svnserve binary in /usr/bin. The above scripts have been updated to reflect this new approach.

  9. Import your initial directory set. Generally, you'll want a set of directories called 'trunk', 'tags' and 'branches' at the lowest level of your repository. To get this setup:
    mkdir code
    mkdir code/trunk
    mkdir code/tags
    mkdir code/branches
    svn import code svn+ssh://USERNAME@SERVER/my_code -m 'inital import'
    rm -rf code

That's it. The server is now setup.

Client Setup

To checkout files, go to your local machine and issue a checkout command:

svn co svn+ssh://USERNAME@SERVER/my_code my_code_local_dir

In reality, you'll probably want to use a fancy graphical client like TortiseSVN (Windows) or Versions (OS X) to access your subversion server. Getting those setup is beyond the scope of this document, but there are many excellent tutorials.

Discussion

Fred, Jul 2, 2010 10:00 PM

“Note that I really don't like doing this (moving the svnserve binary)” symlinks in /usr/local/bin would have done that job ;)

cd /usr/local/bin
ln -s /home/svn/svnwrapper.sh svn
ln -s /home/svn/svnwrapper.sh svnadmin
ln -s /home/svn/svnwrapper.sh svnlook
ln -s /home/svn/svnwrapper.sh svnserve

dordal, Sep 30, 2010 04:03 AM

Fred-

Yeah, but you still have to move svnserve out of the way before you can create a symlink called 'svnserve'. :-)

David

Truyen Van Le, Jul 19, 2010 03:01 PM

Nice post actually.

So when you have the svn layout including trunk/branches/tags. How do you create/make a tag that is a snapshot of current trunk. I know they user svn cp but I don't know other parameters in case we use svn+ssh not http.

Thanks
Truyenle

Timothy Boronczyk, Nov 27, 2010 03:38 AM

Great write up! But you don't have to move the original svnserve binary. Place a link to svnwrapper.sh in /usr/local/bin, which has priority over /usr/bin in the user's PATH.

$ which svnserve
/usr/bin/svnserve
$ ln -s /var/svn/svnwrapper.sh /usr/local/bin/svnserve
$ which svnserve
/usr/local/bin/svnserve

dordal, Dec 2, 2010 09:57 AM

Yep, hadn't caught that. Nice.

I've updated the main article with this suggestion.

Danny, Mar 18, 2012 04:52 PM

Well, that's a good idea on the surface – until you have something with a different $PATH, like maybe “su -”, or a questionably-coded program, or something which has /usr/bin/svnserve hardcoded. Having multiple binaries with the same name is an accident waiting to happen, and will be something difficult to track down. Your original suggestion to move svnserve to svnserve.orig or similar was a safer option. :)

Never mind that you could also easily make a post-commit script which does a chmod, and leave everything else unchanged…

Something else missing here is the sgid bit on the db and locks directory. If every developer doesn't have the same primary GID, you'll want to make the repository directory mode 2775 (or 2770) so that newly-created entries in the directory will inherit the group membership of their parent.

With that all said, here's basically how I solve this problem (hopefully the newlines show up in the script). :D

danny@humpy:/srv/svn$ chgrp svngrp db locks
danny@humpy:/srv/svn$ chmod g=u,g+s db locks
danny@humpy:/srv/svn$ cat «ENDSCRIPT > hooks/post-commit
#!/bin/sh REPOS=“$1” REV=“$2” chmod -R g+w,o-w “$REPOS/db” “$REPOS/locks” ENDSCRIPT
danny@humpy:/srv/svn$ chmod 755 hooks/post-commit

Danny, Mar 18, 2012 04:54 PM

Well, the newlines didn't make it. And the double-quotes were turned to “smart quotes” which also won't work. Sigh. The important part is that the post-commit should contain something like:

chmod -R g+w,o-w “$REPOS/db” “$REPOS/locks”

John Smith, Dec 6, 2010 08:02 AM

I've followed this and had no problems getting it working. But when I try to check in my changes I run into problems. See the error below. Do I need to make pub/private keys? Do I need a similar wrapper for

Transmitting file data ……..svn: Commit failed (details follow):
svn: Can't open file '/var/subversion/repo/db/txn-current-lock': Permission denied

dominik, Nov 12, 2011 02:42 PM

Hi
have you fixed this problem?

I have it!

James Player, Dec 28, 2010 03:48 AM

I get this when I try and svn import:

svn: /usr/bin/svnserve-daemon: not found

Anyone know why this might be?

Jeremy Meier, Dec 28, 2010 04:08 PM

I'm having the same issue as the above poster. When I try to do the import, I get the following messages:

/usr/local/bin/svnserve: line 7: /usr/bin/svnserve-daemon: No such file or directory
/usr/local/bin/svnserve: line 7: exec: /usr/bin/svnserve-daemon: cannot execute: No such file or directory
svn: Connection closed unexpectedly

Robert Verspuy, Jan 7, 2011 02:08 PM

In the svnwrapper.sh I think you have to call /usr/bin/svnserve and not svnserve-daemon.

That's propably old, because the first idea of the author was to rename the svnserve to svnserve-daemon.

dordal, Jan 10, 2011 09:40 AM

Robert: Correct. Sorry for not catching that when I updated the article in Dec. I've fixed it now.

Bimal Poudel, Jan 27, 2011 05:34 AM

What to do if the ssh runs on the different port?

Renaud, Jan 27, 2011 05:48 PM

@Bimal :

Update your /home/bimal/.subversion/config and add :

foo = /usr/bin/ssh -oPort=XXX -l your_login -i /home/bimal/.ssh/ssh_key_for_svn

When you want to import, launch : svn co svn+foo:USERNAME@SERVER/my_code my_code_local_dir ;)

Scott Aron Bloom, Mar 20, 2011 01:24 PM

What if you want/need multiple svn repository on the same server?

Currently, using apache/https access its a piece of cake. Each svn repos get their own path

https://name.com/Repo1/svn https://name.com/Repo2/svn

How would you do that with svn+ssh ??

Scott Aron Bloom, Mar 20, 2011 02:38 PM

Answered my own question…

the -r in the script is the “root” of the svn, I just move it up one and everythign worked, with multipel SVN repos…

Earthly Dilemma, May 25, 2011 05:28 PM

This line was causing errors when connecting:

  exec /usr/bin/svnserve "$@" -r /var/svn/repos

I ended up changing it to:

  exec /usr/bin/svnserve -t -r /var/svn/repos

and setting file system permissions instead of umask:

  groupadd svn
  chown root:svn /var/svn/repos/my_code
  chmod 775 /var/svn/repos/my_code

Just wouldn't seem to work on my box otherwise, couldn't figure out why.

Paddy, Jul 1, 2011 12:15 AM

Hey, thanks for this article! I had been looking through all sorts of web resources for setting up svn and they wanted me to do complicated things with Apache etc… All I wanted was svn+ssh. I checked through your simple steps and then, mentally preparing for a lot of troubleshooting, I loaded my private key and pointed TortoiseSVN's repo browser at my home server from work. There it was… My new repository, ready to go! Now I'm going to go persuade my boss to ditch CVS >=)

fyrye, Feb 21, 2012 06:36 PM

If you have issues with permissions collaborating with multiple users
For step 5 use:
chmod -R 2775 /var/svn/repos/

This will put the setgid on the repos directory forcing all folders and files inside of it to always have the group svn

Otherwise when a user commits to the repository svnserve will apply
chown <user>:<user>
making /path/to/repo/rep-cache.db and /path/to/repo/current read-only for others

fyrye, Feb 21, 2012 06:45 PM

Sorry for the double post
To convert your current repository to add the setgid bit as root run execute:

find ”/var/svn/repos” -type d -exec chmod 2775 {} \;

This will find all directories in your repo and change them to 2775
Be careful using this command as a typo could prove to be catastrophic (much like chmod -Rf 2775 but for directories only)

test121.121.7.82,192.168.120.191, Feb 24, 2016 07:17 AM

Hi,

I'm using Linux Debian Wheezy and I have some issue when try to do anything from my SVN server(Neon).

I n this case I try to checkout from my Linux server by running this command:

zr@apricot [769]$ svn co $SVNROOT/deployment/xxxx_xxx_xx

Error:
Permission denied (publickey).
svn: To better debug SSH connection problems, remove the -q option from 'ssh' in the [tunnels] section of your Subversion configuration file.
svn: Network connection closed unexpectedly

What happen?Please advice.Thanks.

Enter your comment. Wiki syntax is allowed: