1

I am rewriting the Apache 2.4 configuration that I've received from the old development team.

I have ~200 lines of similar configuration, and I can not understand on what principle I need to change this code to move it from .htaccess to virtualhost.

RewriteCond %{QUERY_STRING} ^$
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_URI} !(.*)/$
RewriteCond %{REQUEST_URI} !^/application-module/(.*)$
RewriteCond %{REQUEST_URI} !(.*)json$ [NC]
RewriteCond %{REQUEST_URI} !playground/local-loader/(.*)$ [NC]
RewriteRule ^(.*)$ /$1/ [R,L,NC]

When I just move it to the virtualhost my site crashes in places I don't understand.

2
  • In .htaccess, rewrite rules applies to the directory where .htaccess is located. In virtualhost, you must set these rules in a <Directory> or <Location> block.
    – Chris
    Sep 21 '21 at 18:16
  • Thanks! I tried to do it this way, but it looks like the rules need to be changed somehow. I also understand that the file paths need to be fixed, but regular expressions drive me crazy. Sep 21 '21 at 18:22
0

It depends where in the <VirtualHost> container you are placing these directives.

If you are using a <Directory> container (ie. a directory context) and disabling .htaccess overrides altogether (otherwise .htaccess will override the <Directory> container!) then you can pretty much copy the directives as-is (assuming the <Directory> container references the same directory as the .htaccess file did).

However, if you are putting these directives directly inside the <VirtualHost> container (outside of a <Directory> container), ie. in a virtualhost context, then you need to make some changes. This is because the directives are processed earlier, before the request is mapped to the filesystem.

In the directives you've posted, only two changes would be required:

  • In a virtualhost context, the REQUEST_FILENAME server variable has not yet been resolved to a filename. It is the same as REQUEST_URI (ie. the URL that is requested). So, your filesystem check will always fail and the condition will always be successful! You either need to use a lookahead. eg. %{LA-U:REQUEST_FILENAME}, or construct the absolute filename yourself. eg. %{DOCUMENT_ROOT}%{REQUEST_URI}. For example:

    RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} !-f
    
  • In a virtualhost context, the URL-path that is matched by the RewriteRule pattern is root-relative (starting with a slash). Whereas in .htaccess it is relative to the directory that contains the .htaccess file - less the slash prefix. So, the rule as written would result in a double slash at the start of the URL-path, it should be rewritten like this instead:

    RewriteRule ^/(.*)$ /$1/ [R,L]
    

    (The NC flag is not required here.)

    Or (preferable) don't use a backreference here and use the REQUEST_URI server variable instead (which would naturally work in .htaccess as well). For example:

    RewriteRule ^ %{REQUEST_URI}/ [R,L]
    

    (Aside: This should probably also be a 301 permanent redirect (ie. R=301). As it stands, this will default to a 302 temporary redirect. But only change to a 301 - if that is the intention - once you have confirmed that it works as intended.)

So, in summary, this would become:

RewriteCond %{QUERY_STRING} ^$
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} !-f
RewriteCond %{REQUEST_URI} !(.*)/$
RewriteCond %{REQUEST_URI} !^/application-module/(.*)$
RewriteCond %{REQUEST_URI} !(.*)json$ [NC]
RewriteCond %{REQUEST_URI} !playground/local-loader/(.*)$ [NC]
RewriteRule ^/(.*)$ /$1/ [R,L]

Aside:

The above can be immediately optimised a bit by moving the filesystem check (which is relatively expensive) to the last condition and moving the condition that checks that the request does not already end in a slash to the RewriteRule directive. Also, the regex subpatterns (.*) in each of the conditions are not required. So, the above could be rewritten more efficiently:

RewriteCond %{QUERY_STRING} ^$
RewriteCond %{REQUEST_URI} !^/application-module/
RewriteCond %{REQUEST_URI} !json$ [NC]
RewriteCond %{REQUEST_URI} !playground/local-loader/ [NC]
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} !-f
RewriteRule !/$ %{REQUEST_URI}/ [R,L]

The filesystem check can perhaps be removed altogether if instead you exclude requests that contain (what looks like) a file extension, but this can depend on your file structure.

The condition that checks !json$ looks like it should really be checking for the .json file extension, ie. !\.json$. (This ties in with my comment above about excluding all requests that have a "file extension".)

The first condition that checks that the query string is empty seems a little odd (since it doesn't really matter whether there is a query string or not when appending a slash to the URL-path), but I assume this must be a specific requirement?

1
  • 1
    this is awesome! everything make sense, and now it all works! Thank you many times! Sep 22 '21 at 6:41

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.