htaccess Force SSL if certain file exists - apache

I have the following mod rewrite code that forces SSL on my website:
RewriteCond %{HTTPS} !=on
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
I have to edit the htaccess file if I want to turn this off or on. So what I am thinking is to have a file for example called ssl_on stored in a certain path of the server and if the file ssl_on exists then this rule applies and if the file doesn't exist then the rule shouldnt apply. Is this possible?

You can use your rule like this:
RewriteCond %{HTTPS} off
RewriteCond %{DOCUMENT_ROOT}/ssl_on -f
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=302]
-f condition will ensure that rule will fire only when ssl_on file exists in website root. Also better to use R=302 instead of R=301 to avoid permanent redirects caching in browser.

As per the docs:
One or more RewriteCond can precede a RewriteRule directive. The following rule is then only used if both the current state of the URI matches its pattern, and if these conditions are met.
So going by this, you could have before (or after) your current RewriteCond line a new RewriteCond line:
RewriteCond <HTTPS_TOGGLE_FILE_PATH> -f
And because both rules need to be true in order for the Rule to be matched, the file would have to exist before the 301 header would be issued.
Note that the rules for caching 301 headers in browsers are convoluted- a lot of them cache the redirection indefinitely. So if you want this to truly be toggleable (e.g. browsers that have accessed the site via HTTP when the redirection is enabled then accessing the site via HTTP when it is disabled) then a 302 would be preferable.

Related

htaccess rewrite subdomain to some folder if exists else another

I know there are some similar questions about subdomain -> folder htaccess, but I already have a setup that works for me for that simple case.
What I want to add, is "rewrite to projects/subdomain/current/public/ if that current/public exists, else rewrite to projects/subdomain/"
It's because I'm hosting a laravel application, which is in 'public/', and I deployed it using a tool that symlinks 'current/' to its latest release.
My current setup is:
# Redirect everything non-www to /projects/...
RewriteEngine on
RewriteCond %{HTTP_HOST} !^www.* [NC]
RewriteCond %{HTTP_HOST} ^([^\.]+)\.mydomain\.com
RewriteCond /var/www/mydomain.com/projects/%1 -d
RewriteRule ^(.*) /projects/%1/$1 [L]
Which is something like:
if it doesn't start with www
get the subdomain in a var
if the /projects/subdomain folder exists
rewrite the request to look into that folder
else 404
How would I update this to have an "IF /projects/subdomain/current/public exists, then that, ELSE IF /projects/subdomain exists, then that, ELSE 404"?
Thanks in advance!
Just create another rule before the existing one. For example, following the same pattern as your existing rule:
RewriteEngine on
# Redirect to /projects/<subdomain>/current/public/
RewriteCond %{HTTP_HOST} !^www\. [NC]
RewriteCond %{HTTP_HOST} ^([^\.]+)\.mydomain\.com
RewriteCond /var/www/mydomain.com/projects/%1/current/public -d
RewriteRule (.*) /projects/%1/current/public/$1 [L]
# Redirect everything non-www to /projects/...
RewriteCond %{HTTP_HOST} !^www\. [NC]
RewriteCond %{HTTP_HOST} ^([^\.]+)\.mydomain\.com
RewriteCond /var/www/mydomain.com/projects/%1 -d
RewriteRule (.*) /projects/%1/$1 [L]
I removed the ^ from the RewriteRule pattern (^(.*)) since it was superfluous.
I also changed !^www.* (matches any hostname that simply starts "www") to !^www\. (any hostname that starts "www." - the subdomain only) to avoid potentially spurious matches.
Presumably /var/www/mydomain.com is the document-root, so you could use the DOCUMENT_ROOT server variable instead in the RewriteCond TestString. For example:
RewriteCond %{DOCUMENT_ROOT}/projects/%1/current/public -d
However, by themselves, these directives will result in a rewrite-loop (500 error), so I assume you already have directives in place that prevent this. eg. Another .htaccess file in the directory that you are rewriting to that contains mod_rewrite directives (relevant to the individual projects)? If not then you can either add another condition to each rule that checks against the REDIRECT_STATUS environment variable, or include an exception at the top of the file that prevents further processing after the request is rewritten. For example:
RewriteEngine On
# Stop further processing if the request has already been rewritten
RewriteCond %{ENV:REDIRECT_STATUS} !^$
RewriteRule ^ - [L]
: Remaining directives follow...
UPDATE: If you are on Apache 2.4 you can instead simply change the L flag to END to halt all processing by the rewrite engine, to prevent a rewrite loop. The END flag is a relatively recent addition and consequently often gets overlooked - but it's not strictly necessary as there are always other (perhaps more complex) ways to do this.
Why would it loop?
The L flag does not stop all processing. It simply stops the current round of processing and then the rewrite engine effectively starts over, passing the rewritten URL back into the rewrite engine. In the above example, the rewritten URL also matches the same rules, so the URL would be rewritten again, and again, and again, ....
For example (for simplicity, just using your original rule that rewrites to /projects):
Request subdomain.mydomain.com/foo
<doc-root>/projects/subdomain directory exists
URL rewritten to /projects/subdomain/foo
Rewriting process starts over... passing in the rewritten URL, essentially subdomain.mydomain.com/projects/subdomain/foo, back into the rewrite engine.
<doc-root>/projects/subdomain directory exists (as previous)
URL rewritten to /projects/subdomain/projects/subdomain/foo
Rewriting process starts over... etc. etc.
The Rewriting process loops in this fashion until the URL passes through unchanged, unless something else steps in the way... for example, as mentioned above, if you have another .htaccess file located at /projects/subdomain/.htaccess that also contains mod_rewrite directives then control would pass to this .htaccess file after the first round of rewrite processing and prevent further rewrites (since mod_rewrite directives are not inherited by default).

.htaccess redirection not working in ubuntu

To remove multiple slashes I wrote this condition that is working in windows system but not in Ubuntu 18.04 I don't know why..?
RewriteCond %{HTTP_HOST} !=""
RewriteCond %{THE_REQUEST} ^[A-Z]+\s//+(.*)\sHTTP/[0-9.]+$
RewriteRule .* %{HTTP_HOST}/%1 [R=301,L]
I am getting this error in ubuntu system..
Forbidden
You don't have permission to access this resource.
And my URL changed this
http://in.decashop.localhost/p/8489882_500-boys-gym-short-sleeved-t-shirt-grey.html
to this
http://in.decashop.localhost/var/www/html/decashopglobal/www/in.decashop.localhost/p/8489882_500-boys-gym-short-sleeved-t-shirt-grey.html
if I put multiple slashes like
http://in.decashop.localhost///p/8489882_500-boys-gym-short-sleeved-t-shirt-grey.html
At first, you can check apache's log. try to access your website using URL or IP and check your Webserver's log information.
In ubuntu you can try:
sudo tail -f /var/log/apache2/error.log
In most cases wrong permission is the main cause of this problem.
RewriteCond %{HTTP_HOST} !=""
RewriteCond %{THE_REQUEST} ^[A-Z]+\s//+(.*)\sHTTP/[0-9.]+$
RewriteRule .* %{HTTP_HOST}/%1 [R=301,L]
The output you are seeing is consistent with the directives you have posted, as you are missing the scheme (ie. http) on the substitution string in the RewriteRule directive (which presumably should be an absolute URL) - so I don't see how this would have "worked" on the Windows server? Unless you had a very different config (but even then it couldn't have worked the same way).
With the RewriteRule directive as written, the substitution string (ie. %{HTTP_HOST}/%1) would be seen as a relative URL and Apache would then add back the directory-prefix ie. /var/www/html/decashopglobal/www/ prior to issueing the redirect - which naturally results in the malformed redirect you are seeing. If you had set a RewriteBase directive elsewhere in the config file, then this would have overridden this behaviour (although still wouldn't have produced the output you seem to be expecting).
Also note that these directives are intended to remove multiple slashes from the start of the URL-path only, not elsewhere in the URL-path.
So, you would need to change the RewriteRule directive to read:
RewriteRule ^ http://%{HTTP_HOST}/%1 [R=301,L]
OR, remove the HTTP_HOST server variable altogether (to make the substitution string root-relative):
RewriteRule ^ /%1 [R=301,L]
You will need to clear your browser cache before testing, as the erroneosu 301 (permanent) redirects will be cached persistently by the browser. (Test with 302s to avoid caching issues in the future.)
This Rule worked for me..
RewriteBase /
RewriteCond %{THE_REQUEST} ^[A-Z]{3,}\s/+(.*?)/+(/[^\s]+) [NC]
RewriteRule ^ %1%2 [R=302,L,NE]
Thanks To All.

Editing .htaccess file to modify URL

I'm trying to modify my .htaccess file to modify my URL and have tried many methods but cannot achieve exactly what I want. For example I have this URL:
http://mywebsite.com/FOLDER/index.php?id=5
Now I want it to look like:
http://mywebsite.com/FOLDER/5
or
http://mywebsite.com/FOLDER/ID/5
My .htaccess contains the following code:
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}\.php -f
RewriteRule ^index/([0-9]+)/([0-9a-zA-Z_-]+) index.php?id=$1 [NC]
I cannot figure out what's wrong. Thanks.
You can use:
RewriteEngine on
# external redirect from actual URL to pretty one
RewriteCond %{THE_REQUEST} \s/+FOLDER/index\.php\?id=(\d+) [NC]
RewriteRule ^ /FOLDER/%1? [R=301,L,NE]
# internal forward from pretty URL to actual one
RewriteRule ^FOLDER/(\d+)/?$ FOLDER/index.php?id=$1 [L,QSA,NC]
The first argument of RewriteRule is what the incoming url without domain and without preceding paths (more on that later) is going to be matched against. This url is, in your case, http://mywebsite.com/FOLDER/5. Assuming that your .htaccess file is in your DocumentRoot, the regex will match against FOLDER/5.
You are currently trying to match FOLDER/5 with ^index/([0-9]+)/([0-9a-zA-Z_-]+), which is not going to work. A better regex would be ^(.*)/([0-9]+)$ or ^(.*)/ID/([0-9]+)$. You can then rewrite to $1/index.php?id=$2. I would recommend using the [L] flag to stop rewriting for this round to avoid common problems with multiple rules matching while you do not expect them to.
Besides this, make sure that your .htaccess files are being read (e.g. by checking that if you enter garbage, you get a 500 internal server error), that mod_rewrite is enabled, that you are allowed to override FileInfo. You also may need to turn AcceptPathInfo off.

No trailing slash causes 404, how to fix using htaccess?

The URLs are:
(Doesn't work) http://example.com/seller/samsung
(Works) http://example.com/seller/samsung/
The .htaccess rule I have for these types of URLs looks like:
RewriteRule ^seller/[^/]+/(.*)$ ./$1
What can I do to make both of these URLs to go to the same page?
You could just force a trailing slash to appear on the end of your URLs. You can do that by using the following in your .htaccess:
RewriteCond %{REQUEST_URI} !(/$|\.)
RewriteRule (.*) %{REQUEST_URI}/ [R=301,L]
Just make sure you clear your cache before you test this.
EDIT:
RewriteCond %{REQUEST_URI} /+[^\.]+$
RewriteRule ^(.+[^/])$ %{REQUEST_URI}/ [R=301,L]
What does the above do? So the condition grabs your directory, so for example /samsung and will check if it has a / on the end. If it does not, it will grab the directory at the end of URL (once again /samsung and add a / on to it. It will do this using a 301 redirect and would leave you with /samsung/.
As for the L flag (taken from official documentation):
The [L] flag causes mod_rewrite to stop processing the rule set. In
most contexts, this means that if the rule matches, no further rules
will be processed. This corresponds to the last command in Perl, or
the break command in C. Use this flag to indicate that the current
rule should be applied immediately without considering further rules.

.htaccess - redirect favicon

How do I redirect all requests for favicon.ico in root directory or any subdirectory to /images/favicon.ico
Try this rule:
RewriteEngine on
RewriteRule ^favicon\.ico$ /images/favicon.ico [L]
Edit    And for favicon.ico with arbitrary path segment depth:
RewriteCond $0 !=images/favicon.ico
RewriteRule ^([^/]+/)*favicon\.ico$ /images/favicon.ico [L]
For a favicon at www.mysite.com/images/favicon.ico
the most robust method would be:
RewriteCond %{REQUEST_URI} !^/images/favicon\.ico$ [NC]
RewriteCond %{HTTP_HOST} (.+)
RewriteRule ^(.*)favicon\.(ico|gif|png|jpe?g)$ http://%1/images/favicon.ico [R=301,L,NC]
Explanation:
RewriteCond %{REQUEST_URI} !^/images/favicon\.ico [NC] :
- ensures that the redirect rule does NOT apply if the correct URI is requested (eg a 301 redirect will write the correct favicon URI to browser cache - and this line avoids processing the rule if the browser requests the correct URI)
- [NC] means it's not case sensitive
RewriteCond %{HTTP_HOST} (.+) :
- retrieves the http host name - to avoid hard coding the hostname into the RewriteRule
- this means you can copy your .htaccess file between local/test server and production server without problems (or the need to re-hardcode your new site base url into your RewriteRule)
RewriteRule ^(.*)favicon\.(ico|gif|png|jpe?g)$ http://%1/images/favicon.ico [R=301, L] :
- ^ is the start of the regex
- (.*) is a wildcard group - which means that there can be zero or any number of characters before the word favicon in the URI (ie this is the part that allows root directory or any subdirectories to be included in the URI match)
- \.(ico|gif|png|jpe?g) checks that the URI extension matches any of .ico, .gif, .png, .jpg, .jpeg
- $ is the end of the regex
- http://%1/images/favicon.ico is the redirect url - and it injects the hostname we retrieved in the previous RewriteCond. Note that the %1 is a called a RewriteCond backreference this means it is the last RewriteCond that has been met. (eg %2 would be the 2nd-last RewriteCond that to have been met)
- R=301 means it's a permanent redirect - which stores the redirect in the browser cache. Be careful when testing - you'll need to delete browser cache between code changes or the redirect won't update. Probably leave this out until you know the rule works.
- L means its the last redirect to be followed in this .htaccess file - you won't need this to get the rule working since line 1 won't be met once the browser is directed to the correct url. Without the either line 1 or L the RewriteRule will result in a permanent loop (since the redirect URL will keep satisfying the RewriteRule conditions). However, it's a good idea to add the L anyway if you have other rules following the favicon rules - since on a favicon.ico request, you can (probably) ignore any following rules.
You can test .htaccess rules at http://htaccess.mwl.be/
Final Note:
- be careful that you don't have any other RewriteRule in an .htaccess file located in any of your sub-directories.
- eg if you put this answer in your www.mysite.com/ root folder .htaccess file, a RewriteRule (.*) xxx type rule in your www.mysite.com/images/ folder can mess with the results.
RewriteEngine on
RewriteRule ^(.*)favicon\.ico /images/favicon.ico [L]
I know the question is tagged .htaccessbut, why not use a symlink?
ln -s images/favicon.ico favicon.ico
This quick rewrite should do the trick:
RewriteRule ^(.*)favicon.ico /images/favicon.ico