Endless loop when rewriting to https - apache

I recently bought a wildcard ssl certificate to move my site to https.
Since Apache can't handle multiple Virtual hosts, under the same IP, in separate s, I was forced to use VirtualDocumentRoot from mod_vhost_alias. This at first solved my problems with Apache and the wildcard certificate, but it was not for long.
For a matter of necessity, I decided to move the homepage of my site to the root of the domain (ie, http://domain.com, instead of http://www.domain.com). Once I moved, the rules I established to move to https cause an endless loop on the server, resulting in an error 500. Note that the same rules when applied to any sub-domain still works, rewriting any http to https.
The error:
Request exceeded the limit of 10 internal redirects due to probable configuration error. Use 'LimitInternalRecursion' to increase the limit if necessary.
My VirtualHost config:
<VirtualHost IP:443>
...
VirtualDocumentRoot /.../public_html/%1/
...
VirtualScriptAlias /.../public_html/%1/cgi-bin/
...
</VirtualHost>
My .htaccess config:
SetEnv APPLICATION_ENV development
Options +FollowSymlinks -Indexes
RewriteEngine On
RewriteCond %{HTTP_HOST} ^www.domain.com [NC,OR]
RewriteCond %{HTTP_HOST} ^domain.com [NC]
RewriteCond %{SERVER_PORT} !443
RewriteRule ^(.*)$ https://domain.com/$1 [L,R=301]
RewriteCond %{REQUEST_FILENAME} -s [OR]
RewriteCond %{REQUEST_FILENAME} -l [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^(.*)$ - [NC,L]
RewriteRule ^(.*)$ index.php [NC,L]
<FilesMatch "\\.(js|css)$">
SetOutputFilter DEFLATE
</FilesMatch>
My application was build using the Zend Framework.
The main mystery here is why does it work with any sub-domain, but does not when I'm using the root sub-domain. Any hint in what can be causing the problem? Is there any way I can see all the rewrites de .htacess does?

Try this:
RewriteEngine On
RewriteCond %{HTTP_HOST} ^(www\.)?domain\.com$ [NC]
RewriteCond %{HTTPS} !on
RewriteRule (.*) https://%{HTTP_HOST}/$1 [L,R=301]
RewriteCond %{REQUEST_FILENAME} !-s
RewriteCond %{REQUEST_FILENAME} !-l
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule (.*) index.php [L]
Changes:
www.domain.com and domain.com could be matched in one line, so did it
check for HTTPS instead of SERVER_PORT
redirect to HTTPT on same domain name as requested (change if you want all to point to one name).
instead of making a rule that would "kill" rewriting, with 3 RewriteCond's in OR, negated the cond's to apply to the real rule in question
there is no point of setting NC flag when matching .*
The rest of the .htaccess should stay the same (did not include those parts).

Related

How can I direct all folders on my website to use HTTPS in .htaccess?

Please be kind, this is my first question on here :)
My Setup
Apache served on my Raspberry Pi 4
My .htaccess file
# Force HTTPS on all pages
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{HTTPS} !on
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
</IfModule>
The Problem
Typing in "tyler.cloud" successfully redirects to https://www.tyler.cloud, but typing in "tyler.cloud/react" stays at http://tyler.cloud/react (not HTTPS).
What I've tried in addition to above with the same results
RewriteEngine on
RewriteCond %{SERVER_PORT} 80
RewriteRule ^(.*)$ https://%{SERVER_NAME}%{REQUEST_URI} [R=301,L]
and
RewriteEngine On
RewriteCond %{HTTPS} !on
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI}
and a few other variations.
It turns out "AllowOverride" in /var/www has to be "All" in /etc/apache2/apache2.conf.
It was set to "None", and that means it ignored all of my .htaccess files.
I used this:
RewriteEngine On
RewriteCond %{HTTPS} !on
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI}
and it seems to work!
Consider using apache2.conf instead of .htaccess. Because using .htaccess in a server where you have root access is a bad idea. It can slow your website down unnecessarily.
Try using this instead of .htaccess:
<Directory "/path/to/web/directory">
RewriteEngine On
RewriteCond %{HTTPS} !on
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI}
</Directory>
And if you are using VirtualHosts, add:
RewriteEngine On
RewriteOptions Inherit
inside the virtualhost.
And also, if someone points their domain to your IP address, then they will be able to show your website through their IP address (unless you are using Name based virtual hosting i.e. https://httpd.apache.org/docs/2.4/vhosts/name-based.html, but still they will be able to access your main Apache host with the IP address of course). Although because you are using HTTPS, their domain probably will fail HTTPS. But, because you do not have HSTS (https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Strict-Transport-Security) set up, users can still access the website.
So, I would also suggest you to redirect to your domain if the domain doesn't match https://www.tyler.cloud, using the following: (add the following to inside <Directory> directive)
(If you are planning to add HSTS preload see the next solution please)
#Do not use RewriteEngine On more than once. see the next solution if you are planning to use HSTS preload
RewriteCond %{HTTP_HOST} !^www\.tyler\.cloud [OR]
RewriteCond %{HTTPS} !=on
RewriteRule ^ https://www\.tyler\.cloud%{REQUEST_URI} [R=301,L]
Use the next solution if planning to use HSTS preload:
RewriteCond %{HTTP_HOST} ^tyler\.cloud
RewriteCond %{HTTPS} !=on
RewriteRule ^ https://tyler\.c%{REQUEST_URI} [R=301,L]
RewriteCond %{HTTP_HOST} !^www\.tyler\.cloud [OR]
RewriteCond %{HTTPS} !=on
RewriteRule ^ https://www\.tyler\.cloud%{REQUEST_URI} [R=301,L]
And you are good to go!

Subdomain https www to non-www

I have a domain called example.com and within this domain are two sub-domains called:
qa1.example.com
qa2.example.com
All of which have SSL certification. However, I have a .htaccess file as follows:
UPDATED
Options +FollowSymlinks
Options -Indexes
<FilesMatch "\.(tpl|ini|log|xml)">
Order deny,allow
Deny from all
</FilesMatch>
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !.*\.(ico|gif|jpg|jpeg|png|js|css)
RewriteRule ^([^?]*) index.php?route=$1 [L,QSA]
RewriteCond %{HTTPS} !=on
RewriteRule %{HTTP_HOST} ^www\.
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
RewriteBase /
RewriteRule ^sitemap.xml$ index.php?route=feed/google_sitemap [L]
RewriteRule ^googlebase.xml$ index.php?route=feed/google_base [L]
RewriteRule ^download/(.*) /index.php?route=error/not_found [L]
The following happens:
http://qa1.example.com > redirects to > https://qa1.example.com
http://www.qa1.example.com > redirects to > https://www.qa1.example.com
https://www.qa1.example.com > redirects to > https://www.qa1.example.com
Number 1 is correct, but numbers 2 and 3 need to redirect to https://qa1.example.com without the www.
How can this be achieved? I can include the .htaccess file separately for the two sub-domains.
RewriteCond %{HTTPS} !=on
RewriteRule ^.*$ https://%{SERVER_NAME}%{REQUEST_URI} [R,L]
Your canonical HTTP to HTTPS and www to non-www redirects should come before your internal rewrites (routing directives). After the RewriteBase directive.
Try the following:
# www to non-www canonicalisation (including subdomains)
RewriteRule %{HTTP_HOST} ^www\.(.*)
RewriteRule ^ https://%1%{REQUEST_URI} [R=301,L]
# HTTP to HTTPS
RewriteCond %{HTTPS} !=on
RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [R=301,L]
# Internal rewrites / routing goes here...
If you didn't have additional subdomains it would be relatively trivial to combine these into one rule. Also, this should be a 301 (permanent) redirect, rather than a 302 (temporary), which is what the R flag will default to. (However, it can be easier to test with temporary redirects as they aren't cached by the browser.)
UPDATE: The above directives were assuming these were going in your main domains .htaccess file and the subdomains were all controlled from this (in subdirectories off the main domain's document root). They should still work OK for the subdomains .htaccess file, however, they could be optimised into a single rule (at most one redirect, rather than two). For example:
# www to non-www and HTTP to HTTPS canonicalisation
RewriteCond %{HTTPS} !=on [OR]
RewriteRule %{HTTP_HOST} ^www\.
RewriteRule ^ https://qa1.example.com%{REQUEST_URI} [R=301,L]
The above obviously hardcodes the hostname for the subdomain. If you have only two subdomains then that shouldn't be a problem. It is certainly safer.
To generalise the above, you can use the SERVER_NAME variable. However, you need to ensure that UseCanoncialName On is first set in your server config (default is Off), otherwise this will simply hold the hostname from the request (which is part of the problem you're seeing in your question). The ServerName directive also needs to be set to the correct subdomain. eg. ServerName qa1.example.com.
# www to non-www and HTTP to HTTPS canonicalisation
# UseCanonicalName On - must be set in server config
RewriteCond %{HTTPS} !=on [OR]
RewriteRule %{HTTP_HOST} ^www\.
RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [R=301,L]

.htaccess error 500 in production, not in development. Environment vars

I have a site that loads fine in my local development environment, but bombs out with HTTP Error 500: Internal server error in production. I don't have any access to apache error_log as it is on a shared hosting environment.
I think the issue is with setting of apache environment variables in .htaccess - possibly causing some kind of infinite loop? I require these as they are picked up by PyroCMS and used to determine environment specific settings such as DB config.
<IfModule mod_rewrite.c>
# Make sure directory listing is disabled
Options +FollowSymLinks -Indexes
# disable the Apache MultiViews directive if it is enabled on the server. It plays havoc with URL rewriting
Options -MultiViews
RewriteEngine on
# Automatically determine and set the PYRO_ENV variable
RewriteCond %{HTTP_HOST} ^(localhost|local.mydomain.com|mydomain|mydomain.local)$
RewriteRule (.*) $1 [E=PYRO_ENV:development,L]
RewriteCond %{HTTP_HOST} ^staging.mydomain.com$
RewriteRule (.*) $1 [E=PYRO_ENV:staging,L]
RewriteCond %{HTTP_HOST} ^www.mydomain.com$
RewriteRule (.*) $1 [E=PYRO_ENV:production,L]
# Rewrite "domain.com -> www.domain.com"
RewriteCond %{HTTPS} !=on
RewriteCond %{HTTP_HOST} !^www\..+$ [NC]
RewriteCond %{HTTP_HOST} (.+)$ [NC]
RewriteCond %{HTTP_HOST} ^mydomain.com$ [NC]
RewriteRule ^(.*)$ http://www.mydomain.com/$1 [R=301,E=PYRO_ENV:production,L]
# Keep people out of codeigniter directory and Git/Mercurial data
RedirectMatch 403 ^/.*/(system/cms/cache|system/codeigniter|system/cms/config|system/cms/logs|\.git|\.hg|db).*$
# 301 permanent redirects for old web site pages
RewriteRule ^some/old/path$ /some/new/path [R=301,L]
RewriteRule ^some/other/old/path$ /some/other/new/path [R=301,L]
# Send request via index.php (again, not if its a real file or folder)
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
<IfModule mod_php5.c>
RewriteRule ^(.*)$ index.php/$1 [L]
</IfModule>
<IfModule !mod_php5.c>
RewriteRule ^(.*)$ index.php?/$1 [L]
</IfModule>
</IfModule>
If I comment out the following lines:
RewriteCond %{HTTP_HOST} ^www.mydomain.com$
RewriteRule (.*) $1 [E=PYRO_ENV:production,L]
Then the error 500 disappears and instead I get a DB connection error (as PyroCMS cannot detect the environment).
Usually, I would set the environment variables directly into the vhost config using the SetEnv directive. However, as this particular site is on shared hosting, I have no access to these.
How can I resolve this issue?
On another point, I have sections below that provide 301 redirects for old website pages to new ones (this is a rebuild of an old website). My gut is telling me that even if I resolve this issue, the Environment variable that is set near the top of the .htaccess file will be lost when another RewriteRule is matched further down the .htaccess file. Am I correct in this thinking?
The solution involved removing the L flag from the RewriteRule's on that set the environment. The L flag was stopping further rules from being processed and invoking an infinite loop. By removing the L flag, it means that the environment is set and applies to all further redirects. This also answers my aside question about being able to persist the ENV after another 301 redirect.
# Automatically determine and set the PYRO_ENV variable
# We DON'T use the L flag on RewriteRule here as we want it to persist through redirects.
RewriteCond %{HTTP_HOST} ^(localhost|local.mydomain.com|mydomain|mydomain.local)$
RewriteRule (.*) $1 [E=PYRO_ENV:development]
RewriteCond %{HTTP_HOST} ^staging.mydomain.com$
RewriteRule (.*) $1 [E=PYRO_ENV:staging]
RewriteCond %{HTTP_HOST} ^www.mydomain.com$
RewriteRule (.*) $1 [E=PYRO_ENV:production]

.htaccess redirect http to https

I have an old url (www1.test.net) and I would like to redirect it to https://www1.test.net
I have implemented and installed our SSL certificate on my site.
This is my old file .htaccess:
RewriteEngine On
RewriteRule !\.(js|gif|jpg|png|css|txt)$ public/index.php [L]
RewriteCond %{REQUEST_URI} !^/public/
RewriteRule ^(.*)$ public/$1 [L]
How can I configure my .htaccess file so that url auto redirect to https?
Thanks!
I use the following to successfully redirect all pages of my domain from http to https:
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
Note this will redirect using the 301 'permanently moved' redirect, which will help transfer your SEO rankings.
To redirect using the 302 'temporarily moved' change [R=302,L]
Update 2016
As this answer receives some attention, I want to hint to a more recommended way on doing this using Virtual Hosts: Apache: Redirect SSL
<VirtualHost *:80>
ServerName mysite.example.com
Redirect permanent / https://mysite.example.com/
</VirtualHost>
<VirtualHost _default_:443>
ServerName mysite.example.com
DocumentRoot /usr/local/apache2/htdocs
SSLEngine On
# etc...
</VirtualHost>
Old answer, hacky thing
given that your ssl-port is not set to 80, this will work:
RewriteEngine on
# force ssl
RewriteCond %{SERVER_PORT} ^80$
RewriteRule ^(.*)$ https://%{SERVER_NAME}%{REQUEST_URI} [L,R]
Note that this should be your first rewrite rule.
Edit: This code does the following. The RewriteCond(ition) checks wether the ServerPort of the request is 80 (which is the default http-port, if you specified another port, you would have to adjust the condition to it). If so, we match the whole url (.*) and redirect it to a https-url. %{SERVER_NAME} may be replaced with a specific url, but this way you don't have to alter the code for other projects. %{REQUEST_URI} is the portion of the url after the TLD (top-level-domain), so you will be redirected to where you came from, but as https.
This is the best for www and for HTTPS, for proxy and no proxy users.
RewriteEngine On
### WWW & HTTPS
# ensure www.
RewriteCond %{HTTP_HOST} !^www\. [NC]
RewriteRule ^ https://www.%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
# ensure https
RewriteCond %{HTTP:X-Forwarded-Proto} !https
RewriteCond %{HTTPS} off
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
### WWW & HTTPS
I force the https with following code:
RewriteEngine on
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}/$1 [R=301,L]
Add this code at the end of your .htaccess file
RewriteEngine on
RewriteCond %{HTTPS} off
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI}
In cases where the HTTPS/SSL connection is ended at the load balancer and all traffic is sent to instances on port 80, the following rule works to redirect non-secure traffic.
RewriteEngine On
RewriteCond %{HTTP:X-Forwarded-Proto} !https
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
Ensure the mod_rewrite module is loaded.
Searching for the best way to redirect, i've found this (coming from html5boilerplate) :
# ----------------------------------------------------------------------
# | HTTP Strict Transport Security (HSTS) |
# ----------------------------------------------------------------------
# Force client-side SSL redirection.
#
# If a user types `example.com` in their browser, even if the server
# redirects them to the secure version of the website, that still leaves
# a window of opportunity (the initial HTTP connection) for an attacker
# to downgrade or redirect the request.
#
# The following header ensures that browser will ONLY connect to your
# server via HTTPS, regardless of what the users type in the browser's
# address bar.
#
# (!) Remove the `includeSubDomains` optional directive if the website's
# subdomains are not using HTTPS.
#
# http://www.html5rocks.com/en/tutorials/security/transport-layer-security/
# https://tools.ietf.org/html/draft-ietf-websec-strict-transport-sec-14#section-6.1
# http://blogs.msdn.com/b/ieinternals/archive/2014/08/18/hsts-strict-transport-security-attacks-mitigations-deployment-https.aspx
Header set Strict-Transport-Security "max-age=16070400; includeSubDomains"
Maybe it will help someone in 2017 ! :)
Insert this code in your .htaccess file. And it should work
RewriteCond %{HTTP_HOST} yourDomainName\.com [NC]
RewriteCond %{SERVER_PORT} 80
RewriteRule ^(.*)$ https://yourDomainName.com/$1 [R,L]
This makes sure that redirects work for all combinations of intransparent proxies.
This includes the case client <http> proxy <https> webserver.
# behind proxy
RewriteCond %{HTTP:X-FORWARDED-PROTO} ^http$
RewriteRule (.*) https://%{HTTP_HOST}/$1 [R=301,L]
# plain
RewriteCond %{HTTP:X-FORWARDED-PROTO} ^$
RewriteCond %{REQUEST_SCHEME} ^http$ [NC,OR]
RewriteCond %{HTTPS} off
RewriteRule (.*) https://%{HTTP_HOST}/$1 [R=301,L]
I had a problem with redirection also. I tried everything that was proposed on Stackoverflow. The one case I found by myself is:
RewriteEngine on
RewriteBase /
RewriteCond %{HTTP:SSL} !=1 [NC]
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}/$1 [R=301,L]
Adding the following to the top of the .htaccess
RewriteEngine On
RewriteCond %{ENV:HTTPS} !=on
RewriteRule ^.*$ https://%{SERVER_NAME}%{REQUEST_URI} [R,L]
This is what ended up working for me
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
</IfModule>
Forcing HTTPS with the .htaccess File
==> Redirect All Web Traffic :-
To force all web traffic to use HTTPS, insert the following lines of code in the .htaccess file in your website’s root folder.
RewriteEngine On
RewriteCond %{HTTPS} !on
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
==> Redirect Only Specified Domain :-
To force a specific domain to use HTTPS, use the following lines of code in the .htaccess file in your website’s root folder:
RewriteCond %{REQUEST_URI} !^/[0-9]+\..+\.cpaneldcv$
RewriteCond %{REQUEST_URI} !^/\.well-known/pki-validation/[A-F0-9]{32}\.txt(?:\ Comodo\ DCV)?$
RewriteEngine On
RewriteCond %{HTTP_HOST} ^example\.com [NC]
RewriteCond %{SERVER_PORT} 80
RewriteRule ^(.*)$ https://www.example.com/$1 [R=301,L]
If this doesn’t work, try removing the first two lines.
RewriteEngine On
RewriteCond %{HTTP_HOST} ^example\.com [NC]
RewriteCond %{SERVER_PORT} 80
RewriteRule ^(.*)$ https://www.example.com/$1 [R=301,L]
Make sure to replace example.com with the domain name you’re trying
force to https. Additionally, you need to replace www.example.com with
your actual domain name.
==> Redirect Specified Folder :-
If you want to force SSL on a specific folder, insert the code below into a .htaccess file placed in that specific folder:
RewriteCond %{REQUEST_URI} !^/[0-9]+\..+\.cpaneldcv$
RewriteCond %{REQUEST_URI} !^/\.well-known/pki-validation/[A-F0-9]{32}\.txt(?:\ Comodo\ DCV)?$
RewriteEngine On
RewriteCond %{SERVER_PORT} 80
RewriteCond %{REQUEST_URI} folder
RewriteRule ^(.*)$ https://www.example.com/folder/$1 [R=301,L]
Make sure you change the folder reference to the actual folder name.
Then be sure to replace www.example.com/folder with your actual domain
name and folder you want to force the SSL on.
Replace your domain with domainname.com , it's working with me .
RewriteEngine On
RewriteCond %{HTTP_HOST} ^domainname\.com [NC]
RewriteCond %{SERVER_PORT} 80
RewriteRule ^(.*)$ https://www.domainname.com/$1 [R,L]

How to ensure that Apache always serves a single page via HTTPS?

I would like to redirect all connections from htt_p://www.example.com/abc.html to HTTP_S://www.example.com/abc.html . What mod_alias or mod_rewrite commands would work for this? I've tried:
RewriteEngine on
RewriteCond %{HTTPS} =off
RewriteRule $abc\.html^ https://www.example.com/abc.html [R]
in both .htaccess and httpd.conf but that doesn't work. It works if the first string in the RewriteRule is anything else (like abz.html) but not if it is abc.html. abc.html is a real file on the server (not another redirect). Options FollowSymlinks is present in the appropriate Directory directive.
Many thanks.
Something along the lines of the following will allow you to redirect non-SSL pages to SSL versions (assuming that you are running SSL on port 443):
RewriteEngine on
# Limited redirects
RewriteCond %{SERVER_PORT} !^443$
RewriteCond %{REQUEST_URI} ^/abc\.html$ [OR,NC]
RewriteCond %{REQUEST_URI} ^/def\.html$ [OR,NC]
RewriteCond %{REQUEST_URI} ^/ghi\.html$ [NC]
RewriteRule ^/(.*)$ https://%{HTTP_HOST}/$1 [R=301,L]
The [OR] flag after the RewriteCond is literally that, "or", which is why the last condition doesn't have it