Server Fault is a question and answer site for system and network administrators. It's 100% free, no registration required.

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

We wish to restrict access on our development server to those users who have a valid SSL Client certificate. We are running Apache 2.2.16 on Debian 6.

However, for some sections (mainly git-http, setup with gitolite on https://my.server/git/) we need an exception since many git clients don't support SSL client certificates.

I have succeeded in requiring client cert authentication for the server, and in adding exceptions for some locations. However, it seems this does not work for git.

The current setup is as follows:

SSLCACertificateFile ssl-certs/client-ca-certs.crt
<Location />
  SSLVerifyClient require
  SSLVerifyDepth 2
# this works
<Location /foo>
  SSLVerifyClient none
# this does not
<Location /git>
  SSLVerifyClient none

I have also tried an alternative solution, with the same results:

# require authentication everywhere except /git and /foo
<LocationMatch "^/(?!git|foo)">
  SSLVerifyClient require
  SSLVerifyDepth 2

In both these cases, a user without client certificate can perfectly access my.server/foo/, but not my.server/git/ (access is refused because no valid client certificate is given). If I disable SSL client certificate authentication completely, my.server/git/ works ok.

The ScriptAlias problem

Gitolite is setup using the ScriptAlias directive. I have found that the problem occurs with any similar ScriptAlias:

# Gitolite
ScriptAlias /git/ /path/to/gitolite-shell/
ScriptAlias /gitmob/ /path/to/gitolite-shell/
# My test
ScriptAlias /test/ /path/to/test/script/

Note that /path/to/test/script is a file, not a directory, the same goes for /path/to/gitolite-shell/

My test script simply prints out the environment, super simple:


print "Content-type:text/plain\n\n";
print "TEST\n";
@keys = sort(keys %ENV);
foreach (@keys) {
    print "$_ => $ENV{$_}\n";

It seems that if I go to https://my.server/test/someLocation, that any SSLVerifyClient directives are being applied which are in Location blocks that match /test/someLocation or just /someLocation.

If I have the following config:

<LocationMatch "^/f">
        SSLVerifyClient require
        SSLVerifyDepth 2

Then, the following URL requires a client certificate: https://my.server/test/foo. However, the following URL does not: https://my.server/test/somethingElse/foo

Note that this only seems to apply for SSL configuration. The following has no effect whatsoever on https://my.server/test/foo:

<LocationMatch "^/f">
        Order allow,deny
        Deny from all

However, it does block access to https://my.server/foo.

This presents a major problem for cases where I have some project running at https://my.server/project (which has to require SSL client certificate authorization), and there is a git repository for that project at https://my.server/git/project which cannot require a SSL client certificate. Since the /git/project URL also gets matched agains /project Location blocks, such a configuration seems impossible given my current findings.

Question: Why is this happening, and how do I solve my problem?

In the end, I want to require SSL Client certificate authorization for the whole server except for /git and /someLocation, with as minimal configuration as possible (so I don't have to modify the configuration each time something new is deployed or a new git repository is added).

Update More information: Note that in some cases, https://my.server/project is actually reverse proxied so that a <Directory /path/to/project> directive is impossible. If I want to protect that application with a SSL client certificate, this must by necessity be with a <Location /project> (or more general <Location />) block.

Update 2 I just tested this in apache 2.4.3, with the same result. If this were due to some bug, it's at least present in two versions.

Note: I rewrote my question (instead of just adding more updates at the bottom) to take into account my new findings and hopefully make this more clear.

share|improve this question

According to the current Apache documentation this might be a problem:

In per-server context it applies to the client authentication process used in the standard SSL handshake when a connection is established. In per-directory context it forces a SSL renegotiation with the reconfigured client verification level after the HTTP request was read but before the HTTP response is sent.

What about using the the <Directory> context instead of <Location>. One entry for the root level and the other for the Script-Alias path: /path/to/gitolite-shell/


I found some advices to this case -> Question/Answer at Stackoverflow

share|improve this answer
The server does indeed force an SSL renegotiation, but that in itself is not a problem. I work around the perceived limitation from the StackOverflow question by including the SSLVerifyClient require directive in a <Location /> block instead of directly in the server context. This way, the different Location blocks get processed and merged, and a certificate is only asked if necessary. In addition, if that were the problem, my exception for my.server/foo would not work, whereas this currently works perfectly (see the first config block in my question). – brain99 Aug 29 '12 at 13:10
I also just updated my question with a note explaining why a <Directory> block is not a solution in my case. – brain99 Aug 29 '12 at 13:17

Your Answer


By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.