Apache 2.4 how to Require valid-user only for specific hosts

.htaccess, apache, basic-authentication, httpd.conf, server-configuration

Solution

This is how I do it. (Using Cj Case's nice citation as a comment to explain details. :D )

SetEnvIfNoCase HOST ^dev\.example\.com$ env_is_protected
SetEnvIfNoCase HOST ^test\.example\.com$ env_is_protected
<RequireAny>
    <RequireAll>
        # when the Require directive is negated it can only fail or return a neutral result, 
        # and therefore may never independently authorize a request
        # (reason why we need an additional "all granted" here!)
        Require all granted
        Require not env env_is_protected
    </RequireAll>
    AuthType Basic
    AuthName "Speak, friend, and enter."
    AuthUserFile /sites/example/conf/.htpasswd
    Require valid-user
</RequireAny>

Problem

I want to tell Apache 2.4.9 to require valid-user if host is dev.example.com or test.example.com. This doesn't work: ``` AuthType Basic AuthName "Speak, friend, and enter." AuthBasicProvider file AuthUserFile /sites/example/conf/.htpasswd AuthGroupFile /dev/null SetEnvIfNoCase Host ^dev\.example\.com$ env_is_protected SetEnvIfNoCase Host ^test\.example\.com$ env_is_protected Require valid-user Require not env env_is_protected ``` It causes a server error; evidently `not env` is not valid contrary to the documentation. In the following examples, the first five lines are always the same as in the first example. This doesn't work: ``` SetEnvIfNoCase Host ^dev\.example\.com$ env_is_protected SetEnvIfNoCase Host ^test\.example\.com$ env_is_protected <RequireAny> Require valid-user <RequireNone> Require env env_is_protected </RequireNone> </RequireAny> ``` It causes a server error. The documentation explains: Because negated authorization directives are unable to return a successful result, they can not significantly influence the result of <RequireAny> directive. (At most they could cause the directive to fail in the case where they failed and all other directives returned a neutral value.) Therefore negated authorization directives are not permitted within a <RequireAny> directive. This doesn't work: ``` SetEnv env_is_unprotected 1 SetEnvIfNoCase Host ^dev\.example\.com$ !env_is_unprotected SetEnvIfNoCase Host ^test\.example\.com$ !env_is_unprotected Require valid-user Require env env_is_unprotected ``` The documentation explains about SetEnv: The internal environment variables set by this directive are set after most early request processing directives are run, such as access control and URI-to-filename mapping. If the environment variable you're setting is meant as input into this early phase of processing such as the RewriteRule directive, you should instead set the environment variable with SetEnvIf. This works: ``` SetEnvIf Host . env_is_unprotected SetEnvIfNoCase Host ^dev\.example\.com$ !env_is_unprotected SetEnvIfNoCase Host ^test\.example\.com$ !env_is_unprotected Require valid-user Require env env_is_unprotected ``` This looks like a hack and takes hours to figure out. Have I failed to discover the proper way of accomplishing my very simple purpose? Is there a better way?

Original source