Apache Rewrite rule pointing to password protected directory - apache

Consider the following structure of a directory, which is served by an apache webserver under the URL sample.com :
/local/path/index.html
/local/path/.htaccess
/local/path/admin
/local/path/admin/.htaccess
/local/path/admin/projects/project1/index.html
/local/path/admin/projects/project2/index.html
/local/path/admin/projects/project3/index.html
Whereas /local/path/projects is a symlink pointing to some other directory.
Thus the contents of /local/path/.htaccess is basically this rule:
Options SymLinksIfOwnerMatch
The other .htaccess ensures that the admin directory is password protected.
When http://sample.com is requested index.html is served.
When e.g. http://sample.com/admin/projects/project1 is requested, the contents of /local/path/admin/projects/project1/index.html are served, after the user has entered the correct password.
Requesting http://sample.com/admin of course leads to an 404 Error.
My intention is now to to make the address http://sample.com/admin serve /local/path/admin/projects/project1/index.html. But this should be nor redirection, meaning that e.g. in a browser url-bar the url remains the chosen one. However redirecting to http://sample.com/admin/ would be ok, if necessary.
I tried to enhance the /local/path/admin/.htaccess file with the following:
RewriteEngine On
RewriteRule ^admin admin/projects/project1
RewriteRule ^admin/(.*) admin/projects/project1/$1
But the rules seem to have no effect. Is it maybe because it points to a password protected area?
On the other hand, it was not possible to create a rule inside the admin/.htaccess like this:
RewriteRule ^(.*)$ projects/project1/$1
What am I'm doing wrong here?

I'll suggest to give a better look at the documentation here:
When using the rewrite engine in .htaccess files the per-directory
prefix (that is, the URI path that lead to the directory containing
this .htaccess file) is automatically removed for the RewriteRule
pattern matching and automatically added after any relative (not
starting with a slash or protocol name) substitution encounters the
end of a rule set. See the RewriteBase directive for more information
regarding what prefix will be added back to relative substitutions.
And again:
The removed prefix always ends with a slash, meaning the matching
occurs against a string which never has a leading slash. Therefore, a
Pattern with ^/ never matches in per-directory context.
So given that the per-directory prefix is automatically removed, you should try your rewrite rules without the admin prefix when you are writing /local/path/admin/.htaccess.

Try this rule inside /local/path/admin/.htaccess:
RewriteEngine On
RewriteRule ^/?$ /admin/projects/project1/index.html [L]
RewriteRule ^(?!projects/project1/).+$ /admin/projects/project1/$0 [L,NC]

Related

Simulate directory with htaccess

When my main website opens, it retrieves content from /home/parsa/public_html.
I have tried this: rewriteRule "^/(.*)$" "/ppyazi.com/$1"
I need it to retrieve the files from /home/parsa/public_html/ppyazi.com without redirecting to it on the user side.
Here are some examples:
index.php to display contents of ppyazi.com/index.php
users/index.php to display contents of ppyazi.com/users/index.php
I have tried this: rewriteRule "^/(.*)$" "/ppyazi.com/$1"
In .htaccess the URL-path that is matched by the RewriteRule pattern does not start with a slash. So, the pattern ^/(.*)$ will never match and your directive does nothing.
However, unless there is also a .htaccess file in the /ppyazi.com subdirectory with mod_rewrite directives then you need to be careful of rewrite loops.
Try the following instead:
RewriteEngine On
rewriteRule !^ppyazi\.com\ /ppyazi.com%{REQUEST_URI} [L]
The RewriteRule pattern simply checks that the URL does not already start with the directory we are rewriting to. Instead of the $1 backreference (since we are not capturing anything in the RewriteRule pattern) we use the REQUEST_URI server variable instead. Note that REQUEST_URI contains the full URL-path, including the slash prefix, so the slash should be omitted from the susbstitution string.
The L (last) flag is required to prevent any further directives being processed that occur later in the file (in the current round of processing). If this is the last mod_rewrite directive in the file then it is superfluous. Note, however, that in .htaccess the rewriting process essentially starts over (until the URL passes through unchanged), so other directives might still process the request.

.htaccess RewriteRule behavior with existing subdirectories

I've been through many of similar questions but I couldn't find this particular case:
Having this structure:
public_html/
q/
.htaccess
index.php
/dirnofixedname1
/dirnofixedname2
/dirnofixedname3
dirnofixednameN are folders that have files to be used by index.php and not to be directly accessible (called like that as I may not enumerate all in the .htaccess file or it would be impractical)
index.php should process incoming requests
The intention is to process requests like:
http://domain/q/dirnofixedname2 with http://domain/q/index.php?q=dirnofixedname2 while still showing http://domain/q/dirnofixedname2. A popular and already solved case indeed.
So that .htaccess file is:
RewriteEngine On
RewriteCond $1 !^(index\.php)
RewriteRule ^(.*)$ index.php?q=$1 [L]
The problem happens that when the request matches those existing directories (thing I want), it works as intended (index.php executes and gets q) but making a redirect to:
http://domain/q/dirnofixedname2/?q=dirnofixedname2
(and showing that in the URL bar), instead of the intended:
http://domain/q/dirnofixedname2
Particularly, if the directory happens to not exist,
http://domain/q/dirthatdoesnotexist
Gets processed correctly by index.php with q as dirthatdoesnotexist (the script obviously dismisses that and returns nothing).
Do you have any ideas about how to avoid that redirect in cases where the subdir exists? (It's practical to have the same dir name as the parameter)
This is happening due to DirectorySlash directive which is by default in On state since you are requesting an actual directory in your URI.
You can turn it off by using:
DirectorySlash Off
Also to mask directory listing use:
Options -Indexes
at top of your .htaccess

.htaccess issue with RewriteRule for JS files that have a specifc prefix

I'm trying to allow users to access JS files prefixed with wp- by stripping the prefix. However it does affect other files in the directory that do not have the prefix. I know I am missing something somewhere, here is the rule:
RewriteRule ^/?includes/js/(.*).js$ /wp-includes/js/wp-$1.js [QSA,L]
With that rule urls like /wp-includes/js/wp-file.js can be accessed at includes/js/file.js however, files like /wp-includes/js/no-prefix.js cannot be accessed at includes/js/no-prefix.js.
I know it must has to do with my rewrite rule format. Can someone help me please?
Here is the rule you need to add to your /.htaccess (root folder)
RewriteCond %{DOCUMENT_ROOT}/wp-includes/js/wp-$1\.js -f [NC]
RewriteRule ^includes/js/([^/]+)\.js$ /wp-includes/js/wp-$1.js [L]
Note: put this before WP's main rewrite rule.
Short explanation: if url is /includes/js/xxx.js, it first checks that /wp-includes/js/wp-xxx.js physically exists. If so, it is internally rewritten.
Warning: Using mod_rewrite along with WP can lead to issues. Shouldn't be a problem in this context but sometimes it is a better idea to do it thanks to WP's built-in rewrite system.

htaccess - rewrite rule not working when requested URL is a folder on my system

All requests to my site should be rewritten to index.php?page=blah, where blah is the page that's requested (except for css, js, jp(e)g, gif and png files).
This is how my .htaccess file looks like:
RewriteEngine On
RewriteCond %{REQUEST_URI} !\.(?:css|js|jpe?g|gif|png)$ [NC]
RewriteRule ^(.*)$ index.php?page=$1 [L,QSA]
The .htaccess is in this directory: localhost:8080/example/, so when I go to localhost:8080/example/abc, it is (internally) rewritten to localhost:8080/example/index.php?page=abc.
However when I go to localhost:8080/example/res, I get redirected to localhost:8080/example/res/?page=res. I found out that this only happens to directories; when I go to localhost:8080/example/core(also a folder on my file system), I get redirected to localhost:8080/example/core/?page=core while it should be internally rewritten to localhost:8080/example/index.php?page=core and the url visible to the user should stay localhost:8080/example/core/
EDIT:
Thanks to #w3dk, who solved the problem stated above. But I found another problem, which may be related to the problem above:
When I go to:
localhost:8080/example/index/a, it's internally rewritten to localhost:8080/example/index.php?page=index.php/a, while it should be rewritten to localhost:8080/example/index.php?page=index/a.
I found out that this happens when index is a file, cause when I go to localhost:8080/example/exampleFile/abc, it's redirected to localhost:8080/example/index.php?page=exampleFile.php/abc, which shouldn't be the case.
The 2 files in my directory are:
index.php (everything should be directed to this file)
example.php
Apache seems to ignore the php file extension, cause this also works for exampleFile.txt
This is probably happening because of a conflict with mod_dir. The default behaviour (DirectorySlash On) is for mod_dir to automatically "fix" the URL when you request a physical directory without a trailing slash. It does this with an external 301 redirect, before your rule is processed. Your rule then fires, which modifies the target URL, a Location header gets returned to the client and the browser redirects.
This won't happen if you include the trailing slash on the original request. eg. localhost:8080/example/core/. mod_dir then does not need to "fix" the URL and issue a redirect. Although this may not be desirable for you?
Since you are wanting to internally rewrite all directories then the simple fix is to disable this behaviour in .htaccess:
DirectorySlash Off
You will need to clear your browser cache before testing, as the earlier 301s by mod_dir will have been cached locally.
Reference (note the security warning):
https://httpd.apache.org/docs/current/mod/mod_dir.html#directoryslash
You can use this
.htaccess file
Note: The directory folder1 must be unique in the URL. It won't work for http://domain.com/folder1/folder1.html. The directory folder1 must exist and have content in it.
RewriteEngine On
RewriteCond %{HTTP_HOST} domain.com$ [NC]
RewriteCond %{HTTP_HOST} !folder1
RewriteRule ^(.*)$ http://domain.com/folder1/$1 [R=301,L]

What's wrong with my RewriteRule via .htaccess? (Why does it need RewriteBase?)

rewriteengine on
rewriterule ^/a/b$ ^/c$
not working,but
rewriteengine on
rewritebase /
rewriterule ^a/b$ ^c$
works.
It's probably not the RewriteBase that makes the rule work so much as the leading slash. Also, the second argument to RewriteRule isn't a regular expression. Instead, try:
RewriteRule ^/?a/b$ c
When applying a RewriteRule from .htaccess, the leading slash will be stripped from the URL, which will cause the pattern to fail if you include it. By starting a pattern with "^/?", it will work in the main configuration files and in per-directory config files.
Read over the detailed mod_rewrite documentation for the details of how the rewrite engine works and the significance of RewriteBase.
Edit:
As mentioned in the mod_rewrite technical details and described in the documentation for RewriteRule and RewriteBase, the URL has been translated to a path by the time the per-directory rewrite rules are evaluated. The rewrite engine no longer has a URL to work with. Instead, it removes the local directory prefix (the directory holding the .htaccess file), which ends with a slash. For example, suppose a visitor requests "/var/www/foo/bar/baz.html" and there is a rewrite rule set in "/var/www/foo/.htaccess". Fore each rule, the rewrite engine will strip "/var/www/foo/", leaving "bar/baz.html" to be matched against the rewrite rule. After processing a rule, the local directory prefix is prepended (unless the replacement begins with "http://"). After all the rewriting rules have been processed, the rewrite base, if set, replaces the local directory prefix; if not, the document root is stripped. The rewritten URL is then re-injected as a sub-request.
What version of Apache are you using? RewriteBase should not be necessary when you are rewriting from the root. If you are not, you may need it. For instance, a part of my current configurations (Apache 2.2) for one of my blogs looks as follows, and works:
RewriteEngine On
RewriteRule ^/$ /blog/ [R]
RewriteRule ^/wordpress/(.*) /blog/$1 [R]