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:
example.com/directory
301 redirect to example.com/directory/
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.