3

I went through questions/solutions found here, tried numerous approaches (including the [L] directive) but nothing really did the trick.

Situation Overview

Debian running Apache 2.2 proxying through nginx

Goal

Redirect everything to /index.php and assure a trailing slash, always.

Exclude the following directories from the rule:

  • js_static
  • media

Exclude all .css files from the rule.

The Problem

Apache/nginx lead to a 301 redirect loop when i call www.url.com/js_static. (Problem occurs also with trailing slash – makes no difference)

Current Solution Approach

nginx is configured like this:

gzip_proxied any;
rewrite ^/(.*)/$ /$1;
ssl_ciphers 'ECDHE-RSA-AES128-GCM-SHA256:AES256+EECDH:AES256+EDH';

Apache is configured this way:

RewriteEngine On
RewriteCond %{SCRIPT_FILENAME} !^.+\.(css)
RewriteCond %{REQUEST_URI} !^.+js_static
RewriteCond %{REQUEST_URI} !^.+media
RewriteRule ^(.*)$ /index.php/$1
AllowEncodedSlashes On

I fail to see where the problem is. A theory i had was that the combination of nginx/apache rewrites would create the problem, so i fiddled around with the configuration, but to no avail, unfortunately.

Can someone pinpoint the issue here?

  • Please show full nginx configuration. – Tero Kilkanen Dec 03 '16 at 09:54
  • You mean the whole nginx.conf ? I am using Plesk, so the part i posted above is pretty much the only thing that is different from the defaults. – Cummander Checkov Dec 03 '16 at 12:02
  • 1
    I have never used Plesk, so I don't know what the default is. Why are you using both Apache and nginx in the first place? – Tero Kilkanen Dec 04 '16 at 02:18
  • This was the only way that worked for me, to assure that all the goals (those as described above) would be met. I didn't manage to find or come up with a pure nginx or apache rewrite solution. Unfortunately this is far from my field of expertise. – Cummander Checkov Dec 04 '16 at 03:07
  • I don't see any requirements in your initial post that would force you to use both Apache and nginx in your setup. – Tero Kilkanen Dec 04 '16 at 16:15
  • I get better performance from this combination. However, i assume there would have been a way to configure my rewrites either entirely for/in nginx or apache, but i just don't know how. Regardless, this is what i have to work with at this point, and the infinite redirect loop is the only thing that stands in the way of this being a valid and functional configuration. – Cummander Checkov Dec 04 '16 at 16:19
  • So, could you provide the full nginx configuration in the question so I can take a closer look at the issue? – Tero Kilkanen Dec 04 '16 at 17:22

1 Answers1

0

tl;dr "The problem" is likely to be caused by mod_dir (Apache) automatically appending the slash when requesting a physical directory. However, disabling mod_dir (ie. DirectorySlash Off) is not necessarily the answer.


Problem occurs also with trailing slash – makes no difference

In your Nginx config (your frontend proxy), you are unconditionally stripping the trailing slash from all URLs (including directories) via an internal rewrite. So, whether you include the trailing slash on the initial request, it will indeed make no difference.

Apache mod_dir (by default) will automatically append a slash when requesting a physical directory (that does not already have a trailing slash) via an external 301 redirect. It does this in order to "fix" the URL. "A directory" is not strictly a valid resource (what would you expect to be returned?). Once "fixed", mod_dir then tries to return the directory index document (eg. index.html) in that directory:

  1. example.com/directory 301 redirect to example.com/directory/
  2. example.com/directory/ internal rewrite to example.com/directory/index.html (or whatever DirectoryIndex document is found). Or a 403 Forbidden if there is no directory index (unless auto-directory indexes are enabled - not recommended.)

However, after the redirect to example.com/directory/, the request hits your Nginx proxy again which strips the trailing slash.... etc. etc. 301 redirect loop.

My personal preference is to always leave the trailing slash on physical directories. However, if you do want to remove the trailing slash from all URLs then you need to disable mod_dir's automatic behaviour and manually append the trailing slash yourself via an internal rewrite (because requesting a bare directory with no trailing slash is not strictly valid in this instance).

Try changing your Apache config to the following

AllowEncodedSlashes On
DirectorySlash Off

RewriteEngine On

# Internally rewrite any directories that do not have a trailing slash
RewriteCond %{REQUEST_FILENAME} -d
RewriteCond %{REQUEST_URI} (.*)
RewriteRule !/$ %1/ [L]

# Internally rewrite all non-static resources to index.php (with path info)
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^/(.*)$ /index.php/$1 [L]

I assume this is in your server config (and not .htaccess)? However, your previous RewriteRule would have resulted in a double slash in the substitution when used in the server config. This should still have resolved correctly, however, it could break some things.

I've also made this more "generic". Rather than specifically checking for .css files and URLs containing js_static or media, this simply checks to make sure the request is not for a physical file. This is far more common (and flexible) as a "front-controller". However, you can change this back if you specifically need to (but there are potential problems if you do).

...redirect loop when I call www.example.com/js_static

Aside: I wouldn't expect this to be a valid request anyway?

Just to echo TeroKilkanen's concerns in the comments. Using both Nginx and Apache for related rewrites is not recommended.

MrWhite
  • 12,647
  • 4
  • 29
  • 41
  • First – thank you for your detailed and informative response. I tried applying your fix and for the most part it seems to be working. However, there is an issue. I am using a script to merge required JS-files together. So i call upon a ` – Cummander Checkov Dec 06 '16 at 17:13
  • Please note: when trying the above, i did remove the rewrite condition for nginx - as was the intention? – Cummander Checkov Dec 06 '16 at 17:16
  • The above Apache directives are actually assuming that you keep the Nginx `rewrite` directive. (This would require additional Apache directives to strip the slash.) Oh, hang on, since the Nginx directive is an internal rewrite (it is _internal_ isn't?) what is it for exactly - do these URLs need "correcting"? I can't see why `merge.php` and the fonts would break here? These are presumably static files on the file system, so they _shouldn't_ be getting processed by the Apache directives above. What's the URL-path to the `.woff` file? – MrWhite Dec 06 '16 at 17:37
  • In the code posted in your question `/js/generated/merge.php` would get processed by your directives and internally rewritten to `index.php` (which doesn't look correct) - but is this necessary after all?! – MrWhite Dec 06 '16 at 17:38