RewriteRule creates 404 in SSL access log - .htaccess

I'm trying to get some nice URLs. I want to use
https://sub.domain.edu/fs/7356
for
https://sub.domain.edu/fs/index.php?ind=7356
My .htaccess for this directory is:
RewriteEngine On
RewriteBase /fs/
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php?ind=$1 [L,QSA]
The page works fine in the browser. The PHP script works. It all looks great. But the ssl_access_log shows every page access as a 404.
"GET /fs/7356 HTTP/1.1" 404 9241
This would only be mildly annoying except logwatch flags all these 404s as possibly malicious probes. Every morning I get an email saying dozens of IPs tried to probe the site. I have tried adding R=301 to the RewriteRule but it does a full redirect to the full URL I am trying to avoid.

I had to make a custom log format. In /etc/httpd/conf.d/ssl.conf, I commented out the entry that created the ssl_acess-log file and replaced it with LogFormat and Customlog directives.
#TransferLog logs/ssl_access_log
LogFormat "%h %l %u %t \"%r\" %s %b" logwatchfix
CustomLog logs/ssl_access_log logwatchfix
http://httpd.apache.org/docs/current/mod/mod_log_config.html
This resulted in a near-identical output as the original with the only exception being the "%>s" replaced with "%s" It works opposite the way I understand the documentation.
"%s Status. For requests that have been internally redirected, this is the status of the original request. Use %>s for the final status."
I would have thought the "status of the original request" would have been "404" and the "final status" after .htaccess redirection would be "200" In practice, in my case, it worked the opposite. I also placed similar .htaccess files in the other directories that worked the same way. I set the directory index to index.php instead of index.html in the httpd.conf file, but it seemed to make no difference.

Related

Using htaccess how do I RewriteRule/RewriteCond with no filename?

Hoping this isn't a duplicate, done a lot of looking and I just get more confused as I don't use .htaccess often.
I would like to have some pretty URLs and see lots of help regarding getting information where for example index.php is passed a parameter such as page. So I can currently convert www.example.com/index.php?page=help to www.example.com/help.
Obviously I'm not clued up on this but I would like to parse a URL such as www.example.com/?page=help.
Can't seem to find much info and adapting the original I am obviously going wrong somewhere.
Any help or pointers in the right direction would be greatly appreciated. I'm sure its probably stupidly simple.
My alterations so far which do not seem to work are:
RewriteCond %{THE_REQUEST} ^.*/?page=$1
RewriteRule ^(.*)/+page$ /$1[QSA,L]
Also recently tried QUERY_STRING but just getting server error.
RewriteCond %{QUERY_STRING} ^page=([a-zA-Z]*)
RewriteRule ^(.*) /$1 [QSA,L]
Given up as dead to the world so thought I would ask. Hoping to ensure the request/url etc starts ?page and wanting to make a clean URL from the page parameter.
This is the whole/basic process...
1. HTML Source
Make sure you are linking to the "pretty/canonical" URL in your HTML source. This should be a root-relative URL starting with a slash (or absolute), in case you rewrite from different URL path depths later. For example:
Help Page
2. Rewrite the "pretty" URL
In .htaccess (using mod_rewrite), internally rewrite the "pretty" URL back to the file that actually handles the request, ie. the "front-controller" (eg. index.php, passing the page URL parameter if you wish). For example:
DirectoryIndex index.php
RewriteEngine On
# Rewrite URL of the form "/help" to "index.php?page=help"
RewriteRule ^[^.]+$ index.php?page=$0 [L]
The RewriteRule pattern ^[^.]+$ matches any URL-path that does not include a dot. By excluding a dot we can easily omit any request that would map to a physical file (that includes a file extension delimited by a dot).
The $0 backreference contains the entire URL-path that is matched by the RewriteRule pattern.
The DirectoryIndex is required when the "homepage" (root-directory) is requested, when the URL-path is otherwise empty. In this case the page URL parameter is not passed to our script.
3. Implement the front-controller / router (ie. index.php)
In index.php (your "front-controller" / router) we read the page URL parameter and serve the appropriate content. For example:
<?php
$pages = [
'home' => '/content/homepage.php',
'help' => '/content/help-page.php',
'about' => '/content/about-page.php',
'404' => '/content/404.php',
];
// Default to "home" if "page" URL param is omitted or is empty
$page = empty($_GET['page']) ? 'home' : $_GET['page'];
// Default to 404 "page" if not found in the array/DB of pages
$handler = $pages[$page] ?? $pages['404'];
include($_SERVER['DOCUMENT_ROOT'].$handler);
As seen in the above script, the actual "content" is stored in the /content subdirectory. (This could also be a location outside of the document root.) By storing these files in a separate directory they can be easily protected from direct access.
4. Redirect the "old/ugly" URL to the "new/pretty" URL [OPTIONAL]
This is only strictly necessary (in order to preserve SEO) if you are changing an existing URL structure and the "old/ugly" (original) URLs have been exposed (indexed by search engines, linked to by third parties, etc.), otherwise the "old" URL (ie. /index.php?page=abc) is accessible. This is the same whenever you change an existing URL structure.
If the site is new and you are implementing the "new/pretty" URLs from the start then this is not so important, but it does prevent users from accessing the old URLs if they were ever exposed/guessed.
The following would go before the internal rewrite and after the RewriteEngine directive. For example:
# Redirect "old" URL of the form "/index.php?page=help" to "/help"
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteCond %{REQUEST_URI} ^/index\.php$ [OR]
RewriteCond %{QUERY_STRING} ^page=([^.&]*)
RewriteRule ^(index\.php)?$ /%1 [R=301,L]
The check against the REDIRECT_STATUS environment variable prevents a redirect-loop by not redirecting requests that have already been rewritten by the later rewrite.
The %1 backreference contains the value of the page URL parameter, as captured from the preceding CondPattern (RewriteCond directive). (Note how this is different to the $n backreference as used in the rewrite above.)
The above redirects all URL variants both with/without index.php and with/without the page URL parameter. For example:
/index.php?page=help -> /help
/?page=help -> /help
/index.php -> / (homepage)
/?page= -> / (homepage)
TIP: Test first with 302 (temporary) redirects to prevent potential caching issues.
Comments / improvements / Exercises for the reader
The above does not handle additional URL parameters. You can use the QSA (Query String Append) flag on the initial rewrite to append additional URL parameters on the initially requested URL. However, implementing the reverse redirect is not so trivial.
You don't need to pass the page URL parameter in the rewrite. The entire (original) URL is available in the PHP superglobal $_SERVER['REQUEST_URI'] (which also includes the query string - if any). You can then parse this variable to extract the required part of the URL instead of relying on the page URL parameter. This generally allows greatest flexibility, without having to modify .htaccess later.
However, being able to pass a page URL parameter can be "useful" if you ever want to manually rewrite (override) a URL route using .htaccess.
Incorporate regex (wildcard pattern matching) in the "router" script so you can generate URLs with "parameters". eg. /<page>/<param1>/<param2> like /photo/cat/large.
Reference:
https://httpd.apache.org/docs/2.4/rewrite/
https://httpd.apache.org/docs/2.4/rewrite/intro.html
https://httpd.apache.org/docs/2.4/mod/mod_rewrite.html
RewriteCond %{QUERY_STRING} ^page=([^&]+)
RewriteRule ^$ /%1? [R=302,L]
Can't delete and didn't want to waste anyones time responding.

Rewrite rule for name.123456.js in htaccess

I have this file in my webserver:
http://example.com/static/js/min/common.min.js
Since all files inside /static/ are cached with CloudFlare's Edge Cache, I need a way to change the url with something like this, so if the file is modified, the new version will be automatically fresh served:
http://example.com/static/js/min/common.min.1234567890.js
Where 1234567890 is the timestamp of the file's date modification. I already generate the filename according to the modification date, the issue I'm having is in the .htaccess file.
This works fine:
RewriteRule ^(.*)\.[\d]{10}\.(js)$ $1.$2 [L]
That means that:
http://example.com/static/js/min/common.min.1234567890.js
Is redirected to:
http://example.com/static/js/min/common.min.js
But, that will catch all .js requests from the domain, I just want to catch .js requests from within /static/js/min/*.js -- but this is failing:
RewriteRule ^static/js/min/(.*)\.[\d]{10}\.(js)$ $1.$2 [L]
What should the rule be like?
From your question,
You want to redirect
http://example.com/static/js/min/common.min.1234567890.js
to
http://example.com/static/js/min/common.min.js
So, How to do that
the .htaccess
First add
RewriteEngine On
To turn on the rewrite engine
Then the next important line comes
RewriteRule ^static/js/min/([^\d]*)(\d{10}).js$ static/js/min/$1js [L]
Explanation
Set the path as static/js/min/
Then we use RegEx to take the string until a non digit. ([^\d]*).
That is common.min. is captured.
Now $1 is common.min.
Then to match the url, we use (\d{10}) to capture the digits.
That is 1234567890 is captured.
Now $2 is 1234567890 which we don't want anymore
Then redirect to
static/js/min/$1js
Not that here we didn't added the . after the $1 because $1 ending with a . (common.min.)
So, the code will be
RewriteEngine On
RewriteRule ^static/js/min/([^\d]*)(\d{10}).js$ static/js/min/$1js [L]
Working Screenshot
My File Structure
The Address in Browser

Htaccess caching system in subfolder not working

Sorry if this is a duplicate: I found many questions about caching system, but my problem seems to tied to the fact that the whole script is working within a subfolder.
All I need to do is implementing a simple caching system for my website, but I can't get this to work.
Here's my .htaccess file (widely commented to be clear - sorry if too many comments are confusing):
RewriteEngine on
# Map for lower-case conversion of some case-insensitive arguments:
RewriteMap lc int:tolower
# The script lives into this subfolder:
RewriteBase /mydir/
# IMAGES
# Checks if cached version exists...
RewriteCond cache/$1-$2-$3-{lc:$4}.$5 -f
# ...if yes, redirects to cached version...
RewriteRule ^(hello|world)\/image\/([a-zA-Z0-9\.\-_]+)\/([a-zA-Z0-9\.\-_]+)\/([a-zA-Z0-9\.\-_\s]+)\.(png|gif|jpeg?|jpg)$ cache/$1-$2-$3-{lc:$4}.$5 [L]
# ...if no, tries to generate content dynamically.
RewriteRule ^(hello|world)\/image\/([a-zA-Z0-9\.\-_]+)\/([a-zA-Z0-9\.\-_]+)\/([a-zA-Z0-9\.\-_\s]+)\.(png|gif|jpeg?|jpg)$ index.php?look=$1&action=image&size=$2&data=$3&name=$4&format=$5 [L,QSA]
# OTHER
# This is always non-cached.
RewriteRule ^(hello|world)\/([a-zA-Z0-9\.\-_\s]+)\/([a-zA-Z0-9\.\-_\s]+)?\/?$ index.php?look=$1&action=$2&name=$3 [QSA]
Now, the issue is that the RewriteCond seems to be always failing, as the served image is always generated by PHP. I also tried prepending a %{DOCUMENT_ROOT}, but is still not working. If I move the whole script to the root directory, it magically starts working.
What am I doing wrong?
Well one thing that you are doing wrong is trying to use a rewrite map in an .htaccess file. in the first place. According to the Apache documentation:
The RewriteMap directive may not be used in <Directory> sections or .htaccess files. You must declare the map in server or virtualhost context. You may use the map, once created, in your RewriteRule and RewriteCond directives in those scopes. You just can't declare it in those scopes.
If your ISP / sysadmin has already defined the lc map then you can use it. If not then you can only do case-sensitive file caching on Linux, because its FS naming is case sensitive. However, since these are internally generated images, just drop the case conversion and stick to lower case.
%{DOCUMENT_ROOT} may not be set correctly at time of mod_rewrite execution on some shared hosting configurations. See my Tips for debugging .htaccess rewrite rules for more hints. Also here is the equivalent lines from my blog's .htaccess FYI. The DR variable does work here, but didn't for my previous ISP, to I had to hard-code the parth
# For HTML cacheable blog URIs (a GET to a specific list, with no query params,
# guest user and the HTML cache file exists) then use it instead of executing PHP
RewriteCond %{HTTP_COOKIE} !blog_user
RewriteCond %{REQUEST_METHOD}%{QUERY_STRING} =GET [NC]
RewriteCond %{DOCUMENT_ROOT}html_cache/$1.html -f
RewriteRule ^(article-\d+|index|sitemap.xml|search-\w+|rss-[0-9a-z]*)$ \
html_cache/$1.html [L,E=END:1]
Note that I bypass the cache if the user is logged on or for posts and if any query parameters are set.
Footnote
Your match patterns are complicated because you are not using the syntax of regexps: use the \w and you don't need to escape . in [ ] or / . Also the jpeg isn't right is it? So why not:
RewriteRule ^(hello|world)/image/([.\w\-]+)/([.\w\-]+)/([\w\-]+\.(png|gif|jpe?g))$ \
cache/$1-$2-$3-$4 [L]
etc.. Or even (given that the file rule will only match for valid files in the cache)
RewriteRule ^(hello|world)/image/(.+?)/(.+?)/(.*?\.(png|gif|jpe?g))$ \
cache/$1-$2-$3-$4 [L]
The non-greedy modifier means that (.+?) is the same as ([^/]+) so doing hacks like ../../../../etc/passwd won't walk the file hierarchy.

Is it possible to wildcard a filename string to password protect a file with htaccess?

Example: wp_file*.log -- what that should do is to password protect every file whose filename start with wp_file and ends with .log -- for example wp_file-22.log and wp_file_randomfile.log.
Possible?
The way I would make this, is by adding a rewrite rule for those files, redirect to some PHP file with the origional request in the GET. The PHP file can than show a password box and eventually the content of the log file once logged in.
RewriteEngine On
RewriteRule wp_file(.*)\.log /somePHPfile.php?logFile=wp_file$1 [L]
(not tested)
If you dont need access to the log files via your website (but use e.g. ftp), than you can rewrite the requests to those files to another page
RewriteEngine On
RewriteRule wp_file(.*)\.log /index.php [L]

what is line in the htaccess doing?

I was having problems with an img folder having a 403 forbidden and come to find out the issue was caused by this line....what is this doing
RewriteRule .*\.(jpg|jpeg|gif|png|bmp|pdf|exe|zip)$ - [F,NC]
and why would it cause a 403 forbidden on a /something/img folder that had images
See http://httpd.apache.org/docs/1.3/mod/mod_rewrite.html
F = forbidden, forces 403 errors on all URLs ending with one of these extensions.
NC = no case (ie. also works on .GIF for example.
RewriteRule .*\.(jpg|jpeg|gif|png|bmp|pdf|exe|zip)$ Matches any file names containing any number of characters followed by a period and one of those file extionsions.
- Tells mod_rewrite to keep the URL untouched; a technicality emplofed when showing a 403 forbidden page.
[F,NC] F=Forbidden, NC=No case; a case-insensitive match.
Most likely this rule follows (or is supposed to follow) one or more RewriteConds, which are conditions under which the RewriteRule will trigger. The intention of the rule was probably to block images and other files from being hotlinked. Without the RewriteCond, images will always be blocked.
A well designed rule for preventing hotlinking will look something like this:
# Only apply the rule if the referrer isn't empty...
RewriteCond %{HTTP_REFERER} !^$
# ... and doesn't match your site.
RewriteCond %{HTTP_REFERER} !\.?mysite.com/$
# Also, only apply the rule for the specified file types.
RewriteRule \.(jpg|jpeg|gif|png|bmp|pdf|exe|zip)$ - [F,NC]

Resources