Apache FilesMatch directive to match requested domain - apache

I'm trying to setup the FilesMatch directive in such a way that when the user requests a resource that matches the domain name, only then will the resource be served.
For example:
example.com/example.com.html = good
example.com/other.com.html = not allowed, serves error.html instead
I'm currently considering configuring Apache like so:
<FilesMatch regexp+domain_name+regexp>
allow the resource...
</FilesMatch>
But to achieve this effect I would need to have the domain of the request as a variable somehow.
Any advice appreciated.

This option doesn't only check if the file exists, but also if it matches your desired pattern:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f [OR]
RewriteCond %{REQUEST_FILENAME} ^%{SERVER_NAME}\.html$
RewriteRule ^ - [F]
There are more ways to do it, but rewriting gives you the most and probably also the most powerful options. It does require mod_rewrite to be activated though.

Related

How to avoid the need of typing .php on the url?

I'm on MacOs Big Sur, using Apache and PHP. What I want is: not needing to put .php on the end of my files to load it.
For instance, instead of typing this on the URL:
127.0.0.1/public_html/home.php
I want just to type
127.0.0.1/public_html/home
To achieve this, I'm using this code in .htaccess:
RewriteEngine On
Options -Indexes
DirectoryIndex home.php index.php
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}\.php -f
RewriteRule ^(.+)$ $1.php [L]
The code above works on my hosting, but for some reason, it does not work on my development machine. Instead, a get a 404 error.
The .htaccess file with the code is on the root of public_html folder.
What am I missing?
By typing some "nonsense" at the top of the .htaccess file and not getting an error (ordinarily you would get a 500 Internal Server Error) it would seem that .htaccess overrides were not enabled on the server. So, .htaccess files were effectively disabled - which they are by default on Apache 2.4.
To enable .htaccess overrides (to allow .htaccess to override the server config) you need to set the AllowOverride directive in the appropriate <Directory> container in the server config (or <VirtualHost> container). The default on Apache 2.4 is AllowOverride None.
With the directives as posted you would need a minimum of:
AllowOverride FileInfo Indexes Options
FileInfo for mod_rewrite, Indexes for DirectoryIndex and Options for Options and related directives.
Although it is common (and easier) to just set:
AllowOverride All
Reference:
https://httpd.apache.org/docs/2.4/mod/core.html#allowoverride
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}\.php -f
RewriteRule ^(.+)$ $1.php [L]
These directives are not strictly correct. Whilst they may work OK for the URLs you are testing, they would result in a rewrite-loop (500 error response) if you simply append a slash to your URLs (and there is no directory by that name), eg. /home/ (or /home/<anything>). This is because your condition that tests for the presence of the .php file is not necessarily the same as the URL-path you are rewriting to. See my answer to the following question on ServerFault for a thorough explanation of this issue: https://serverfault.com/questions/989333/using-apache-rewrite-rules-in-htaccess-to-remove-html-causing-a-500-error
Also, there's no need to check that the request does not map to a directory to then check if the request + .php extension maps to a file. If the request maps to a file then it can not also be a directory, so if the 2nd condition is true, the 1st condition must also be true and is therefore superfluous.
And there's no need to backslash-escape literal dots in the RewriteCond TestString - this is an "ordinary" string, not a regex.
So, these directives should be written like this instead:
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI}.php -f
RewriteRule (.+) $1.php [L]
(RewriteBase should not be used here.)
You can further optimise this by excluding requests that already contain what looks like a file extension (assuming your URLs that need rewriting do not contain a dot near the end of the URL-path). For example:
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI}.php -f
RewriteRule !\.\w{2,4}$ %{REQUEST_URI}.php [L]
(With this 2nd version, it does not matter if RewriteBase is set - it is not used.)
DirectoryIndex home.php index.php
You gave an example URL of /public_html/home (to which .php is appended). However, this DirectoryIndex directive allows home.php to also be served when simply requesting the directory /public_html/. It should be one or the other, not both.

.htaccess file sub-folder redirect

I know this has been posted in other places, but I have not been able to make it work properly. I am just trying to get a simple redirect from my root / to /html folder and add a .html extension so the url isn’t www.websites.com/html/file.html but rather www.website.com/file. Does anyone have any idea how to do this type of rewrite?
This is about all I have working properly.
RewriteOptions inherit
RewriteEngine on
<FilesMatch "\.(ico|pdf|flv|jpg|jpeg|png|gif|js|css|swf)#$">
Header set Cache-Control "max-age=604800, public"
</FilesMatch>
RewriteBase /html/
This probably is what you are looking for:
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond /html%{REQUEST_URI}.html -f
RequestRule ^ /html%{REQUEST_URI}.html [END]
For this to work the rewriting module needs to be loaded into the http server. Best is to implement such rules in the actual host configuration of the http server. If you do not have access to that (cheap hosting provider), then you can use a distributed configuration file (".htaccess"), but that needs to be enabled too.

Rewriting URL over a file .htaccess

Here is my problem.
I know how to rewrite a URL only if the file doesn't exist.
But I came across a problem that I have never encountered before.
Given the URL : http://www.my-host.com/agences/my-agencies
With at the directory root 2 files :
agences.php
.htaccess
In the .htaccess :
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^agences/(.*) /agences.php?agence=$1
This does not redirect to the /agences.php and is not even interpreted.
If I change the RewriteRule by:
RewriteRule ^agences/(.*) $1
It doesn't even process the rewrite rules.
And so even if I prepend the slash to the regex condition like this :
RewriteRule ^/agences/(.*) $1
I run on an apache 2.4.10, with the AllowOverride all configure in the vhost.
Thanks for the help.
Add that at the beginning of the code:
Options -MultiViews
The effect of MultiViews is as follows: if the server receives a
request for /some/dir/foo, if /some/dir has MultiViews enabled, and
/some/dir/foo does not exist, then the server reads the directory
looking for files named foo.*, and effectively fakes up a type map
which names all those files, assigning them the same media types and
content-encodings it would have if the client had asked for one of
them by name. It then chooses the best match to the client's
requirements. http://httpd.apache.org/docs/2.0/en/content-negotiation.html

mod_rewrite: Make rules apply to both subdomains and subfolders

Metadata
My server setup
A shared host with wildcard subdomains and optional preceding www.
I can't touch httpd.conf and have limited .htaccess directives, although RewriteRule and the likes apply.
I use per-directory .htaccess files.
My server layout
Most subfolders (read: some are for gfx and such) are standalone applications, f.ex: A URL shortener, a image upload site.
Usual PHP controller setup
To manipulate applications, f.ex. view a specific file that's been uploaded, I read the $_SERVER['QUERY_STRING'] in order to use URIs like http://s.domain.com/?image.jpg to retrieve it from where it's stored.
This setup may differ from application to application.
Problem
What I have
Examples
URL Shortener:
http://s.domain.com/?xy7r OR http://www.domain.com/s/?xy7r retrieves the hash from a database and redirects the user.
Image Uploader:
http://d.domain.com/?xy7r.png OR http://www.domain.com/d/?xy7r.png redirects to http://d.domain.com/u/xy7r.png
(Note: the www. is optional in all cases)
What I want
Adjust my existing applications to use Apache's mod_rewrite.
Examples
URL Shortener:
http://s.domain.com/xy7r OR http://www.domain.com/s/xy7r
Image Uploader:
http://d.domain.com/xy7r.png OR http://www.domain.com/d/xy7r.png
My approach
At first I was adding RewriteRules like a happy hacker and everything worked fine,
I then noticed that as they were designed for URIs like http://sub.domain.com they did not work for
URIs like http://www.domain.com/sub.
I decided to try and set up conditions so that the rules would work for both URI cases.
So I Google-FUd and read specifications, documentations and tutorials. I do not fully understand this directive but neither do I think I found any appropriate solutions nor similar problems on the net.
I then gave up and thought I'd instead redirect the second URI syntax (http://www.domain.com/sub/) to the preferred one (http://sub.domain.com) (Also http://www.sub.domain.com), to then apply my existing RewriteRule's
My .htaccess so far
(Only for the URL Shortener as I have not moved on until I get it working)
RewriteEngine On
RewriteCond %{HTTP_HOST} !^s\.domain\.com$ [NC] # Exclude correct URI
RewriteCond %{HTTP_HOST} !^$ # Exclude old HTTP requests
RewriteCond %{REQUEST_URI} ^/s($|/.*$) # Rewrite bad URI
RewriteRule ^.* http://s.domain.com/$1 [R=permanent] # Redirect to correct URI
RewriteCond %{REQUEST_URI} !^/fonts/ # Exclude system folder
RewriteCond %{REQUEST_URI} !^/index.php # Exclude system file
RewriteCond %{REQUEST_URI} !^/style.css # -||-
RewriteCond %{REQUEST_URI} !^/script.js # -||-
RewriteCond %{REQUEST_URI} !^/short.php # -||-
RewriteRule ^(.+)$ http://s.domain.com/?$1 # Rewrite to actual URI
What I get
URI's like http://s.domain.com/xy7r work, as do the same preceded by www., but
the http://www.domain.com/s/xy7r URI syntax just redirects to http://s.domain.com and ignores the xy7r part.
Question
Am I on the right track or is there a better/more correct way to do this?
I've been trying to understand the RewriteBase directive but I don't understand it at all, and trying values like RewriteBase /s/ or s or /s don't satisfy.
In any way I am at a fullstop, I do not know how to proceed.
Any help is appreciated!
Thank you!
</WOT>
For the first set of rules, replace
RewriteCond %{REQUEST_URI} ^/s($|/.*$) # Rewrite bad URI
RewriteRule ^.* http://s.domain.com/$1 [R=permanent] # Redirect to correct URI
with
RewriteRule ^s/?(.*) http://s.domain.com/$1 [L,R=302]

Having a CGI script catch all requests to a domain with Apache

Using Apache 2, I want to configure my website so that any requests to the domain are forwarded to a Python CGI script. Basically, if the user goes to http://www.example.com i want the cgi /cgi-bin/cgi.py to execute. If the user goes to http://www.example.com/index.rss I want /cgi-bin/cgi.py to be executed with /index.rss as the argument. I have tried various combinations of ScriptAlias and Rewrite and cannot seem to get them in the right relationship.
RewriteEngine On
RewriteRule ^(.*)$ /cgi-bin/cgi.py?url=$1
This will redirect ALL requests to your python file.
If you're having trouble with the script alias still, try adding the passthrough flag [PT] at the end of the RewriteRule line
If you still want to be able to access images etc then add this before the RewriteRule:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
(not sure on the correct procedure with answering ones own question - but...)
Looks like I was having conflict with ScriptAlias and RewriteRule. In the end the solution was to use AddHandler to create a relationship then use mod_rewrite to pull everything into the CGI. And RewriteCond to avoid catching /resources/ and /media/. My VirtualHost now looks like this:
AddHandler cgi-script .cgi
RewriteEngine on
RewriteCond %{REQUEST_URI} !^/resources/.*$
RewriteCond %{REQUEST_URI} !^/media/.*$
RewriteRule ^(.*)$ /cgi-bin/pyblosxom.cgi$1 [L]
Thanks for your help guys.
While it's not 100% what you're looking for, here's the .htaccess I use for an old abandoned domain of mine to redirect people properly. It basically redirects for any file or directory not found in the local directory structure. It's up to the script itself to figure out what url it was called for:
RewriteEngine On
#if the request isn't for a file or a directory...
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . index.php
I used the capturing rewrite rule and it worked to a degree. The problem was that original query string of the request URI wasn't passed to the cgi when using $1. I ended up removing the capture and just referencing ENV['REQUEST_URI'] in my cgi script to gain access.