Score:1

How to deny access to all but one IP, and allow access to specific URIs for all with Apache 2.4

cz flag

I need to block access to site from public but allow one IP address in. And I need to give access to couple of URI-s for public. But nothing works - either all gets blocked or all is open.

Simplified extract from Apache conf:

<Directory /site/dir>
    Require ip 1.2.3.4
</Directory>

<Location "/open/for/public1">
    Require all granted
</Location>
<Location "/open/for/public2">
    Require all granted
</Location>

Now all gets blocked.

Also tried with old syntax:

<Location "/open/for/public1">
    Order allow,deny
    allow from all
</Location>

Still same.

I've tried blocking site with <Location "/"> directive (instead of <Directory> directive) but then public1 and public2 get also blocked.

I've tried with:

SetEnvIf Request_URI "^/open/for/public1$" NO_AUTH_NEEDED=1
<Directory /site/dir>
    Order Deny,Allow
    Deny from all
    Allow from env=NO_AUTH_NEEDED
    Allow from 1.2.3.4
</Directory>

Doesn't work, all gets blocked.

All suggestions welcome

Chris avatar
it flag
*I've tried blocking site with <Location "/"> directive (instead of <Directory> directive) but then public1 and public2 get also blocked*. I just tested the first method with 3 `Location` blocks instead of `Directory` as for first one, and that works, I get blocked everywhere except the location I defined.
goldie avatar
cz flag
@Chris Thanks for having a look. Tried once more, still all gets blocked. Maybe it's the order of directives? Could you post your conf?
Score:1
cz flag

What finally helped me were Apache Rewrite rules and LogLevel alert rewrite:trace6. In this case it appears that in addition to some .htaccess files (I didn't think had any effect) there were some internal redirects in the code. So I ended up using in the VirtualHost section something like:

RewriteCond %{REMOTE_ADDR} !1.2.3.4
RewriteCond %{REQUEST_URI} !^/open/for/public(.*) [NC]
RewriteRule .* - [F]

and in the .htaccess:

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . index.php [END]

I added that [END] and seems that it is very important, as without it the Rewrite engine keeps going and for some reason, with some internal redirects (from Apache log: ...internal redirect with /index.php [INTERNAL REDIRECT]) the URL gets mangled and RewriteRule . - [F]* fires every time.

Score:0
it flag

In the first example, I think you get blocked because the Directory directive takes over the Location directives:

<Directory /site/dir>
    Require ip 1.2.3.4
</Directory>

<Location "/open/for/public1">
    Require all granted
</Location>

<Location "/open/for/public2">
    Require all granted
</Location>

There are many way to achieve what you want.

  • A first way that works for me is using Location directives only (tested with real and factice IP, public URL were real files on my system) :

      DocumentRoot /site/dir
    
      <Location />
          Require ip 1.2.3.4
      </Location
    
      <Location "/open/for/public1">
          Require all granted
      </Location>
    
      <Location "/open/for/public2">
          Require all granted
      </Location>
    

    With Location directives, order does matter. In the following example, I get blocked everywhere because the last block overrides the others:

      <Location "/open/for/public1">
          Require all granted
      </Location>
    
      <Location "/open/for/public2">
          Require all granted
      </Location>
    
      <Location />
          Require ip 1.2.3.4
      </Location
    
  • I also tested using Directory directives. In this case, order does not matter (the directives are applied in the order of shortest match first)

      <Directory /site/dir>
          Require ip 1.2.3.4
      </Directory>
    
      <Directory "/site/dir/open/for/public1">
          Require all granted
      </Location>
    
     <Directory "/site/dir/open/for/public2">
         Require all granted
     </Directory >
    

    To choose between Directory or Location directives, see apache recommandation.

  • Here is another example tested using mod_rewrite:

      <Directory /var/www/site/>
    
          # first, allow all 
          Require all granted
    
          # Then enable rewrite engine   
          RewriteEngine On
    
          # Requests that: 
          # do not start with 'test' (test is a real folder supposed open to public)
          RewriteCond %{REQUEST_URI} !^/test
    
          # AND that do not start with 'another_test'
          RewriteCond %{REQUEST_URI} !^/another_test
    
          # AND ...
    
          # AND that do not come from given IP
          RewriteCond "%{REMOTE_ADDR}"  !1.2.3.4
    
          # are blocked (403 Forbidden)
          RewriteRule .* - [F]
      </Directory>
    
goldie avatar
cz flag
Thanks for pointing me in right direction! After days(!) of banging my head against the wall I decided to try it with Rewrite rules and LogLevel alert rewrite:trace6. And it appears that in addition to some funky .htaccess files there are some internal redirects in the code. So I ended up using something like: * RewriteCond %{REMOTE_ADDR} !1.2.3.4 RewriteCond %{REQUEST_URI} !^/open/for/public(.*) [NC] RewriteRule .* - [F,END]
mangohost

Post an answer

Most people don’t grasp that asking a lot of questions unlocks learning and improves interpersonal bonding. In Alison’s studies, for example, though people could accurately recall how many questions had been asked in their conversations, they didn’t intuit the link between questions and liking. Across four studies, in which participants were engaged in conversations themselves or read transcripts of others’ conversations, people tended not to realize that question asking would influence—or had influenced—the level of amity between the conversationalists.