RewriteRule in Elastic Beanstalk not working - .htaccess

I've created a server.config file within an .ebextensions/ folder with the following content, and deployed it to my Apache/PHP Elastic Beanstalk instance, but it doesn't seem to want to prettify my URLs...
files:
"/etc/httpd/conf.d/ssl_rewrite.conf":
mode: "000644"
owner: root
group: root
content: |
RewriteEngine On
RewriteRule ^(.*)index\.php$ /$1 [R=301,NC]
RewriteRule ^terms$ /tac.php [NC,L]
RewriteRule ^info$ /information.php [NC,L]
RewriteRule ^visit$ /visit.php [NC,L]
It seems simple enough, but for example mysite.com/terms results in a 404 (whereas mysite.com/tac.php works fine).
Have I done something silly that I'm just not seeing (seems likely), or do I need to enable something in my EB instance's config?

It was a silly gotcha. These rules (as written) need to be in .htaccess not a *.conf file.
You can learn more about the differences here: http://tltech.com/info/rewriterule-in-htaccess-vs-httpd-conf/
Apache matches different things depending on whether the RewriteRule or RewriteCond directive is placed inside a <Directory> block. And significantly, everything in an .htaccess file is assumed to be in Directory context.
So rules in a .htaccess file behave the same way as rules in a block, which is different from the way rules behave outside a block. Armed with this knowledge, we can fix our httpd.conf file just by moving the rules into the <Directory> block

Related

I need to .htaccess redirect my subfolder to the root folder, except two folders

The subfolder i want to redirect to the root folder is www.example.com/subfolder
So I need to redirect everything in that subfolder to the url adress https://www.example.com except for these two folders (which are placed in the subfolder): www.example.com/subfolder/folder1 and www.example.com/subfolder/folder2
I spent like 4 hours trying to find the exact code but I could not solve that. Nothing worked for me.
I've tried many codes, but nothing worked for me. For example:
RewriteEngine On
RewriteCond %{REQUEST_URI}!^/subfolder/folder1/
RewriteCond %{REQUEST_URI}!^/subfolder/folder2/
RewriteRule ^(.*)$ /$1 [R=301,L]
and
RewriteEngine on
Options +FollowSymlinks
RewriteCond %{REQUEST_URI}!^/subfolder/folder1/
RewriteCond %{REQUEST_URI}!^/subfolder/folder2/
#RewriteRule (.*) http://www.example.com/subfolder/ [R=301,QSA,L]
RewriteRule (.*) https://www.example.com [R]
Could someone help me with that?
I'd prefer to place the .htaccess file in the subfolder.
Thank you so much.
I'd say that your first attempt looks pretty good. Just make a slight modification since you say you want to redirect to the root path, not something inside the root path:
RewriteEngine On
RewriteCond %{REQUEST_URI}!^/subfolder/folder1/
RewriteCond %{REQUEST_URI}!^/subfolder/folder2/
RewriteRule ^(.*)$ / [R=301,QSD,L]
Since you want to use a distributed configuration file (as opposed to the preferred central configuration for the http host) that rule is meant to be used inside a ".htaccess" file inside the "subfolder".
It is a good idea to start out using a R=302 temporary redirection and to only change that to a R=301 permanent redirection once everything works as intended. Also you need to make sure that you always test using a fresh anonymous browser window to prevent client side caching effects.
And you also need to make sure that such distributed configuration files are considered at all by the http server for that location (see the documentation of the AllowOverride directive).

htaccess rewrite stopped working properly

I have the following code block in my .htaccess file:
RewriteEngine on
RewriteCond %{REQUEST_URI} !^(.*)2021layout(.*)$
[other directories to omit, like assets and admin]
RewriteRule ^(.*) RESThandler.php
Basically I want certain directories to be processed normally, like 2021layout, while others use the REST handler. In the 2021layout directory, the member area is in the directory 2021layout/myaccount, and all css/js files are in 2021layout/assets/[whatever directory]. Both the assets and myaccount directories have permissions 0755.
On Friday, everything was working fine. Today, having changed nothing, pages in the 2021layout directory are working, and css and js files loaded by those pages are fine, but pages in the 2021layout/myaccount directory are trying to use the REST handler and getting redirected to my 404 page.
I have tried renaming both the 2021layout and myaccount directories, which didn't work. I have tried adding !^(.*)2021layout/myaccount(.*)$ as a RewriteCond, and that didn't work.
Why would this one specific directory suddenly stop obeying my htaccess instructions? Can I fix this?
Again, to reiterate: I didn't change anything to make this happen. It worked one day, and the next day it didn't, seemingly on its own.
EDIT: I have gotten the directory to work again by renaming the newly-created file settings.php to mysettings.php. So apparently the mere existence of settings.php within the directory was preventing it from loading correctly. Does anyone have any insight into this?
You may try this rule with THE_REQUEST:
RewriteCond %{THE_REQUEST} !\s/2021layout/ [NC]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^ RESThandler.php [L]
THE_REQUEST variable represents original request received by Apache from your browser and it doesn't get overwritten after execution of other rewrite directives. Example value of this variable is GET /index.php?id=123 HTTP/1.1
Make sure to clear your browser cache before testing this change.
So apparently the mere existence of settings.php within the directory was preventing it from loading correctly. Does anyone have any insight into this
I am guessing that you have option MultiViews turned on in your Apache config. To turn it off use this directive at top of your .htaccess:
Option -MultiViews
Option MultiViews (see http://httpd.apache.org/docs/2.4/content-negotiation.html) is used by Apache's content negotiation module that runs before mod_rewrite and makes Apache server match extensions of files. So if /file is the URL then Apache will serve /file.html.

maintenance screen with nested .htaccess files

At the top of the root .htaccess file, I have added
#RewriteCond %{REQUEST_URI} !^/maintenance_503.php [NC]
#RewriteRule .* maintenance_503.php [L]
If uncommented, it redirects the users to a maintenance screen.
However, this doesn't work for subdirectories with their own .htaccess files, and it looks like I cannot use inherit, since it appends parent rules after child rules. I'd rather not add this rule to every single .htaccess file since I want to have a single point of entry for switching it off and on. Are there any best practices for such a case?

Subdomain mod_rewrite (htaccess) to relative directory

I am having a bit of trouble rewriting sub-domains to directories that reside above the web root. I have had plenty of experience with mod_rewrite before, but this particular problem is beyond me.
From what I can tell, mod_rewrite is throwing a tantrum because I insist on using relative directories (..) to determine the directory in which the sub-domain files are located.
Unfortunately, there are two restrictions from my client's specifications:
Putting the sub-domain as a sub-directory of the web root is not an option. The sub-domain must not be accessible from anywhere except the specific sub-domain (there are likely to be directory clashes).
This means http://subdomain.example.com/ must not be accessible from http://example.com/subdomain/ as that directory may be used in the application on the root domain.
An absolute path to the sub-domain files is not known to the client as shared hosting will be used.
If anyone could help me with this problem it would be greatly appreciated! I'd love to start using this in future projects as well, it's quite an elegant solution compared to how we currently deal with sub-domains... If anyone can get it working that is!
Edit: Thought it might be useful to point out that on requesting http://subdomain.example.com/ a 400 Bad Request is returned, rather than a 500 Internal Server Error that I expected. Everything works as expected when requesting the root domain.
Current .htaccess file.
# Begin Rewrite Module for http://*.example.com/
# ==============================================
<IfModule mod_rewrite.c>
# Turn the rewrite engine on.
RewriteEngine On
RewriteBase /
# Map subdomains to their respective directories.
RewriteCond %{HTTP_HOST} ^([^.]+)\.example\.com$
RewriteRule (.*) /../public_subdomains/%1/$1 [L]
# Rewrite all requests for the root domain to always be served through "index.php".
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule (.*) /index.php/$1 [L]
</IfModule>
Current directory structure.
/
application/
cgi-bin/
framework/
public_html
public/
css/
images/
js/
.htaccess
index.php
public_subdomains/
mysubdomain/
index.php
anothersubdomain/
index.php
How you implement this depends on how your host implements subdomains. Some simply map onto your DOCROOT. Others provide a control panel to allow you to do that subdomain -> subdomain docroot yourself. If (2) applies then what you want is already provided, so I'll assume (1) in this ans.
First point to note is that rewriting in an htaccess per-directory context is really URI mapping botched onto the DOCROOT hierarchy. ".." is not allowed and will throw a 500. In practice your are stuck within the domain's DOCROOT.
So public_domains must be a sub directory of DOCROOT -- in your case public_html.
However, you can still simply prevent any direct access to public_html/public_domains by a simple rule:
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteCond %{REQUEST_URI} /public_domains(/|$)
RewriteRule ^ - [F,L]
See my Tips for debugging .htaccess rewrite rules for more hints. You only want to barf on requests with public_domains on the entry pass. Also remember that you don't include the leading / and targets are relative to DOCROOT for a base of /.

How does RewriteBase work in .htaccess

I have seen this in a few .htaccess examples
RewriteBase /
It appears to be somewhat similar in functionality to the <base href=""> of HTML.
I believe it may automatically prepend its value to the beginning of RewriteRule statements (possibly ones without a leading slash)?
I could not get it to work properly. I think it's use could come in very handy for site portability, as I often have a development server which is different to a production one. My current method leaves me deleting portions out of my RewriteRule statements.
Can anyone explain to me briefly how to implement it?
Thanks
RewriteBase is only applied to the target of a relative rewrite rule.
Using RewriteBase like this...
RewriteBase /folder/
RewriteRule a\.html b.html
is essentially the same as...
RewriteRule a\.html /folder/b.html
But when the .htaccess file is inside /folder/ then this also points to the same target:
RewriteRule a\.html b.html
Although the docs imply always using a RewriteBase, Apache usually detects it correctly for paths under the DocumentRoot unless:
You are using Alias directives
You are using .htaccess rewrite rules to perform HTTP redirects (rather than just silent rewriting) to relative URLs
In these cases, you may find that you need to specify the RewriteBase.
However, since it's a confusing directive, it's generally better to simply specify absolute (aka 'root relative') URIs in your rewrite targets. Other developers reading your rules will grasp these more easily.
Quoting from Jon Lin's excellent in-depth answer here:
In an htaccess file, mod_rewrite works similar to a <Directory> or <Location> container. and the RewriteBase is used to provide a relative path base.
For example, say you have this folder structure:
DocumentRoot
|-- subdir1
`-- subdir2
`-- subsubdir
So you can access:
http://example.com/ (root)
http://example.com/subdir1 (subdir1)
http://example.com/subdir2 (subdir2)
http://example.com/subdir2/subsubdir (subsubdir)
The URI that gets sent through a RewriteRule is relative to the directory containing the htaccess file. So if you have:
RewriteRule ^(.*)$ -
In the root htaccess, and the request is /a/b/c/d, then the captured URI ($1) is a/b/c/d.
If the rule is in subdir2 and the request is /subdir2/e/f/g then the captured URI is e/f/g.
If the rule is in the subsubdir, and the request is /subdir2/subsubdir/x/y/z, then the captured URI is x/y/z.
The directory that the rule is in has that part stripped off of the URI. The rewrite base has no affect on this, this is simply how per-directory works.
What the rewrite base does do, is provide a URL-path base (not a file-path base) for any relative paths in the rule's target. So say you have this rule:
RewriteRule ^foo$ bar.php [L]
The bar.php is a relative path, as opposed to:
RewriteRule ^foo$ /bar.php [L]
where the /bar.php is an absolute path. The absolute path will always be the "root" (in the directory structure above). That means that regardless of whether the rule is in the "root", "subdir1", "subsubdir", etc. the /bar.php path always maps to http://example.com/bar.php.
But the other rule, with the relative path, it's based on the directory that the rule is in. So if
RewriteRule ^foo$ bar.php [L]
is in the "root" and you go to http://example.com/foo, you get served http://example.com/bar.php. But if that rule is in the "subdir1" directory, and you go to http://example.com/subdir1/foo, you get served http://example.com/subdir1/bar.php. etc. This sometimes works and sometimes doesn't, as the documentation says, it's supposed to be required for relative paths, but most of the time it seems to work. Except when you are redirecting (using the R flag, or implicitly because you have http://host in your rule's target). That means this rule:
RewriteRule ^foo$ bar.php [L,R]
if it's in the "subdir2" directory, and you go to http://example.com/subdir2/foo, mod_rewrite will mistake the relative path as a file-path instead of a URL-path and because of the R flag, you'll end up getting redirected to something like: http://example.com/var/www/localhost/htdocs/subdir1. Which is obviously not what you want.
This is where RewriteBase comes in. The directive tells mod_rewrite what to append to the beginning of every relative path. So if I have:
RewriteBase /blah/
RewriteRule ^foo$ bar.php [L]
in "subsubdir", going to http://example.com/subdir2/subsubdir/foo will actually serve me http://example.com/blah/bar.php. The "bar.php" is added to the end of the base. In practice, this example is usually not what you want, because you can't have multiple bases in the same directory container or htaccess file.
In most cases, it's used like this:
RewriteBase /subdir1/
RewriteRule ^foo$ bar.php [L]
where those rules would be in the "subdir1" directory and
RewriteBase /subdir2/subsubdir/
RewriteRule ^foo$ bar.php [L]
would be in the "subsubdir" directory.
This partly allows you to make your rules portable, so you can drop them in any directory and only need to change the base instead of a bunch of rules. For example if you had:
RewriteEngine On
RewriteRule ^foo$ /subdir1/bar.php [L]
RewriteRule ^blah1$ /subdir1/blah.php?id=1 [L]
RewriteRule ^blah2$ /subdir1/blah2.php [L]
...
such that going to http://example.com/subdir1/foo will serve http://example.com/subdir1/bar.php etc. And say you decided to move all of those files and rules to the "subsubdir" directory. Instead of changing every instance of /subdir1/ to /subdir2/subsubdir/, you could have just had a base:
RewriteEngine On
RewriteBase /subdir1/
RewriteRule ^foo$ bar.php [L]
RewriteRule ^blah1$ blah.php?id=1 [L]
RewriteRule ^blah2$ blah2.php [L]
...
And then when you needed to move those files and the rules to another directory, just change the base:
RewriteBase /subdir2/subsubdir/
and that's it.
In my own words, after reading the docs and experimenting:
You can use RewriteBase to provide a base for your rewrites. Consider this
# invoke rewrite engine
RewriteEngine On
RewriteBase /~new/
# add trailing slash if missing
rewriteRule ^(([a-z0-9\-]+/)*[a-z0-9\-]+)$ $1/ [NC,R=301,L]
This is a real rule I used to ensure that URLs have a trailing slash. This will convert
http://www.example.com/~new/page
to
http://www.example.com/~new/page/
By having the RewriteBase there, you make the relative path come off the RewriteBase parameter.
AFAIK, RewriteBase is only used to fix cases where mod_rewrite is running in a .htaccess file not at the root of a site and it guesses the wrong web path (as opposed to filesystem path) for the folder it is running in. So if you have a RewriteRule in a .htaccess in a folder that maps to http://example.com/myfolder you can use:
RewriteBase myfolder
If mod_rewrite isn't working correctly.
Trying to use it to achieve something unusual, rather than to fix this problem sounds like a recipe to getting very confused.
RewriteBase is only useful in situations where you can only put a .htaccess at the root of your site. Otherwise, you may be better off placing your different .htaccess files in different directories of your site and completely omitting the RewriteBase directive.
Lately, for complex sites, I've been taking them out, because it makes deploying files from testing to live just one more step complicated.
When I develop, it's on a different domain within a folder. When I take a site live, that folder doesn't exist anymore. Using RewriteBase allows me to use the same .htaccess file in both environments.
When live:
RewriteBase /
# RewriteBase /dev_folder/
When developing:
# RewriteBase /
RewriteBase /dev_folder/
The clearest explanation I found was not in the current 2.4 apache docs, but in version 2.0.
# /abc/def/.htaccess -- per-dir config file for directory /abc/def
# Remember: /abc/def is the physical path of /xyz, i.e., the server
# has a 'Alias /xyz /abc/def' directive e.g.
RewriteEngine On
# let the server know that we were reached via /xyz and not
# via the physical path prefix /abc/def
RewriteBase /xyz
How does it work? For you apache hackers, this 2.0 doc goes on to give "detailed information about the internal processing steps."
Lesson learned: While we need to be familiar with "current," gems can be found in the annals.
This command can explicitly set the base URL for your rewrites. If you wish to start in the root of your domain, you would include the following line before your RewriteRule:
RewriteBase /
I believe this excerpt from the Apache documentation, complements well the previous answers :
This directive is required when you use a relative path in a
substitution in per-directory (htaccess) context unless either of the
following conditions are true:
The original request, and the substitution, are underneath the DocumentRoot (as opposed to reachable by other means, such as Alias).
The filesystem path to the directory containing the RewriteRule, suffixed by the relative substitution is also valid as a URL path on
the server (this is rare).
As previously mentioned, in other contexts, it is only useful to make
your rule shorter. Moreover, also as previously mentioned, you can
achieve the same thing by placing the htaccess file in the
subdirectory.
I simply delete .htaccess file and it runs perfectly

Resources