1

I'm trying to configure rewrite rules with .htaccess on an Azure Web App with Linux+Apache(+PHP), however I can only get redirects to work (but no rewrites).

The source is structured as following:

./.htaccess
./updates/
./updates/.htaccess
./updates/check/
./updates/check/api.php
./updates/certificates/
./updates/certificates/api.php
./... # other files - must not be downloadable

My ./.htaccess is:

order deny,allow
deny from all
RewriteEngine on
RewriteRule "^updates/([A-Za-z]+)" "/updates/$1/api.php" [L,QSA]

EDIT: The problem also persists with

RewriteRule "^updates/([A-Za-z]+)$" "/updates/$1/api.php" [L,QSA]

My ./updates/.htaccess is:

order allow,deny
allow from all

What I need, is to have an internal rewrite, that rewrites /updates/check?foo=bar to /updates/check/api.php?foo=bar and /updates/certificates?a=b&c=d to /updates/certificates/api.php?a=b&c=d.

What I get is a HTTP 301 Redirect to http://$server/updates/check/?foo=bar. When I add R=301 (or R=302) to the rule flags, I get an 301 (or 302) redirect to http://$server/updates/check/api.php?foo=bar. Note the http in both cases (I make an request to https with curl) and the entirely wrong rewrite in the first case.

I'm not sure if the client can handle redirects. This is why I'm trying to do an internal rewrite.

What do I have to do to get that rewrite working?

1 Answers1

0

What I get is a HTTP 301 Redirect to http://$server/updates/check/?foo=bar

Yes, because check is a physical subdirectory so mod_dir will (by default) "fix" the URL by appending a trailing slash to the URL-path via a 301 external redirect. This is necessary for mod_dir to be able to serve the DirectoryIndex (if you have one).

If you changed your URLs to include the trailing slash then you wouldn't have this problem.

You can avoid this redirect by disabling the DirectorySlash. If you do this you must ensure that directory indexes (mod_autoindex) are disabled to prevent accidental discloser of your filesystem.

For example, at the top of your root .htaccess file:

Options -Indexes
DirectorySlash Off

This also means that any other directories are not going to be directly accessible without manually appending the trailing slash with an internal rewrite (or external redirect) - although that may or may not be an issue for you.

Reference:


UPDATE: Because of this "restriction" I would be inclined to change the file (or URL) structure to avoid such conflicts, rather than disabling DirectorySlash.

For example:

/updates/check-api.php
/updates/certificates-api.php

And rewrite accordingly:

RewriteRule ^updates/([A-Za-z]+)$ /updates/$1-api.php [L]

Aside:

order deny,allow
deny from all

Note that these are Apache 2.2 directives and are formerly deprecated on Apache 2.4. You should be using Require all denied and Require all granted instead. However, you should avoid mixing both old/new auth directives since you can get unexpected results (one does not necessarily override the other).

MrWhite
  • 12,647
  • 4
  • 29
  • 41
  • Thanks so much, the rewrite now works! I wanted to ask a follow up question about the `order` directive, but I missed that they are commented out in Azures `/etc/apache2/conf-enabled/localized-error-pages.conf` so I guess it should be safe to use only `Require` directives. – someoneatmec Mar 19 '21 at 13:36
  • You're welcome. TBH I would probably choose to change the file (or URL) structure to avoid such "conflicts" to begin with, rather than disabling the `DirectorySlash`. I've updated my answer with a suggestion. – MrWhite Mar 19 '21 at 13:48
  • I need to use TLS client auth on one of the endpoints (but not on the other one). Azure has a configuration to exclude specific paths from the client auth, but I'm not sure if its applied to the URL or to the file system. I can test that at some point. I have now tried to access various combinations with and without `/` with curl, and got a 403, so I think I should be good with `Require all denied` in `/` and `Require all granted` in `/updates`. The server doesn't host anything else. – someoneatmec Mar 19 '21 at 14:01
  • To clarify, first I had a `.htaccess` in one of the "API subdirectories" that enabled the client auth and provided the path to the CA, thus the single `api.php` file per directory. However, client auth can't be enabled this way in Azure but must be done via the configuration page of the service. – someoneatmec Mar 19 '21 at 14:11