1

I have Apache2 on Ubuntu serving several hosts. Some of the hosts have Website and API parts and some folders like uploads which should be kept outside of the document root. I would like to organize them in the following file structure:

domain
    uploads
    htdocs  //document root
        api
        site

The questions are:

  1. how can I redirect all requests except api ones from document root to site folder without changing the browser uri
  2. and rewrite browser uri to document root for requests made directly to site folder, i.e. instead of /site/.. show /.. in browser uri

I've tried the following but it causes ERR_TOO_MANY_REDIRECTS

RewriteCond %{REQUEST_URI} !^/api/.*$
RewriteCond %{REQUEST_URI} !^/site.*
RewriteRule ^(.*)$ /site/$1 [L]

RewriteCond %{REQUEST_URI} ^/site/?(.*)
RewriteRule .* /%1 [R]
yaugenka
  • 115
  • 5

1 Answers1

1

You're getting a redirect loop because the rewritten URL matches the URL you want to redirect. In .htaccess the rewrite engine starts-over after the first rewrite, despite the presence of the L flag. The L flag simply stops the current pass, it doesn't stop all processing.

  1. how can I redirect all requests except api ones from document root to site folder without changing the browser uri
  2. and rewrite browser uri to document root for requests made directly to site folder, i.e. instead of /site/.. show /.. in browser uri

You have the terminology reversed. #1 is actually a "rewrite", not a "redirect". You are internally rewriting (URL-rewrite) the request - the visible URL is not changing. And #2 is an external "redirect", not a "rewrite". As in a 3xx external redirect - the browser is being redirected.

I would also reverse the order, so you do #2 - the external redirect - first. Generally, redirects should always go before rewrites.

Try the following instead:

# Redirect direct requests for "/site/<anything>" to "/<anything>"
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteRule ^site/(.*) /$1 [R=302,L]

# Rewrite "/<anything>" to "/site/<anything>"
# except for "/api" and "/site" itself.
RewriteRule !^(api|site)/ /site%{REQUEST_URI} [L]

The RewriteCond directive on the redirect that checks against the REDIRECT_STATUS environment variable prevents a redirect loop. This variable is empty on the initial request and set to "200" (as in 200 OK status) after the first successful rewrite.

The 2nd rule (rewrite) uses a negated pattern to exclude requests to the /api and /site directories. This avoids the need for a separate condition. We then need to use the REQUEST_URI server variable, instead of a backreference, in the substitution string.

MrWhite
  • 12,647
  • 4
  • 29
  • 41