I’m trying to set an HTTPS-only header with .htaccess.
This works on MAMP Pro, but on the live server the header is missing on 301 redirect responses:
Header always set Strict-Transport-Security '...' env=HTTPS
The issue can be fixed with this:
Header always set Strict-Transport-Security '...' "expr=%{HTTPS} == 'on'"
But it doesn’t work with MAMP: 500 Internal Server Error is returned.
Can I make expressions (like that "expr=%{HTTPS} == 'on'") work on MAMP? How?
In my experience, MAMP/MAMP Pro does not necessarily work with .htaccess. Mainly due to the fact that MAMP makes your machine a local server, so depending on your .htaccess some rules may be conflicting with MAMP's setup. Every time I run a local instance of one of my sites on MAMP I have to temporarily remove any and all .htaccess files.
In terms of getting your server to force ssl connections, I used these lines of code at the top of .htaccess below "Options -Indexes":
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
Related
Quick summary, I have implemented the following .htaccess file which successfully redirects http:// and any www. searches to https://
My issue - After redirectrule has been applied it then leaves a trailing //? so for example: http://www.example.com becomes https://example.com//?
Another example of another page: http://www.example.com/test becomes https://example.com//test?
So to clarify further. I am happy with the http to https redirect however I only need one final trailing slash and nothing else to my URL, any help and advice would be great as I cannot for the life of me find any other example like this.
Required - http://www.example.com to become https://example.com/
Here is my .htaccess code...
RewriteEngine On
RewriteCond %{SERVER_PORT} !=443
RewriteRule ^(.*)$ https://settlerslodge.co.uk/$1 [R,L]
Use below rewrite rule and test.
RewriteEngine On
RewriteCond %{SERVER_PORT} !^443$
RewriteRule ^/?(.+)/?$ https://%{HTTP_HOST}/$1 [L,R]
This would be a clean setup:
RewriteEngine On
RewriteCond %{HTTPS} !=on
RewriteRule ^/?(.+)/?$ https://example.com/$1 [R=301,QSD,END]
It is a good idea to start out with a 302 temporary redirection and only change that to a 301 permanent redirection later, once you are certain everything is correctly set up. That prevents caching issues while trying things out...
In case you receive an internal server error (http status 500) using the rule above then chances are that you operate a very old version of the apache http server. You will see a definite hint to an unsupported [END] flag in your http servers error log file in that case. You can either try to upgrade or use the older [L] flag, it probably will work the same in this situation, though that depends a bit on your setup.
This implementation will work likewise in the http servers host configuration or inside a distributed configuration file (".htaccess" file). Obviously the rewriting module needs to be loaded inside the http server and enabled in the http host. In case you use a distributed configuration file you need to take care that it's interpretation is enabled at all in the host configuration and that it is located in the host's DOCUMENT_ROOT folder.
And a general remark: you should always prefer to place such rules in the http servers host configuration instead of using distributed configuration files (".htaccess"). Those distributed configuration files add complexity, are often a cause of unexpected behavior, hard to debug and they really slow down the http server. They are only provided as a last option for situations where you do not have access to the real http servers host configuration (read: really cheap service providers) or for applications insisting on writing their own rules (which is an obvious security nightmare).
After switching to https and adding following lines to .htaccess
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteCond %{HTTPS} !=on
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
Header set Strict-Transport-Security "max-age=31536000" env=HTTPS
Everything seems to be working fine - even if someone type http://mywebsite.com will be redirected to https://.
However, as per my understanding, HSTS should also enforce all content to be loaded via https if possible. Unfortunately, every now and then if someone makes a mistake and load some image (hosted on the same domain) via http:// instead of https:// Chrome will show a mixed content warning.
Did I make some mistake or my understanding of HSTS is wrong?
The Apache documentation states that RewriteRule and the should be put in the server configuration, but they can be put in htaccess because of shared hosting situations. I am in such a situation.
I am trying to set up a transparent proxy:
RewriteEngine On
RewriteCond %{REQUEST_URI} ^/foo [OR]
RewriteCond %{REQUEST_URI} ^/bar
RewriteRule ^(.*)$ http://example.com/$1 [P]
This is working fine...except for redirects (like if /foo redirects to /bar). Redirects go back to example.com, not my server.
I understand the the ProxyPassReverse directive will solve this, but I get an "Internal Server Error" page when I add this to .htaccess
Unlike the Rewrite directives, ProxyPassReverse will not work in htaccess.
How do I set up a transparent proxy in shared hosting situation, or is this not possible?
(This seems reasonable, since Rewrite already gets 80% of the way there, and having a transparent proxy in one htaccess would not interfere with having it in another.)
Unfortunately, I'm fairly sure what you want to do isn't possible: I'm trying to do the exact same thing! From my research, I'm fairly confident it's not possible.
Put simply, you need to use ProxyPassReverse, which is only available at a VirtualHost level (or similar); not a htaccess level.
Edit: the only way I have achieved this is by also configuring the responding server/application to know it's behind a proxy, and serving pages appropriately. That is, I use .htaccess to redirect to another server as follows:
RewriteEngine on
RewriteRule (.*) http://localhost:8080/$1 [P,L]
Then on the application server -- in this case, a JIRA installation -- I configured the Java Tomcat/Catalina appropriately to serve pages with the proxied information:
proxyName="my.public.address.com"
proxyPort="80"
However, that's not completely transparent; the app server needs to serve pages in a proxied manner. It might be of some use, though.
I managed to gather a few sources to figure out how to do this. I use a shared hosting provider, so I don't have access to server configuration (httpd.conf). I can only use .htaccess to accomplish the proxying. This example is for a WordPress site where I want most of the content served by origin.example.com, but will have some pages served locally, sort of like an overlay. You could go the other way and ONLY proxy specific subdirectories using different RewriteCond rules.
Things to know:
You can’t use ProxyPass or ProxyPassReverse in .htaccess, so we have to use other methods to mimic what they do.
You can’t make proxy calls over HTTPS if SSLProxyEngine is not turned on by your provider, so you will lose some security if you have concerns about MITM attacks. If the origin server is internal, this may not be an issue. You could also use .htaccess on the origin server to enforce HTTPS from everywhere except the proxy server.
You need to rewrite headers
You need to rewrite the HTML that comes back from the origin server, and that needs to be done on the origin server. You can restrict it to certain IPs (i.e. the IP of the proxy) so it won’t break if you access it elsewhere.
What I want:
I want calls to proxy.example.com to serve content origin.example.com. In my case, I want to map everything with a few exceptions. If you only want to map a portion of your site, adjust your rules accordingly.
How to do it:
Configure the .htaccess file on proxy.example.com to proxy all URIs to origin.example.com. I want to be able to log into proxy.example.com, so I don’t rewrite /wp-admin or /wp-login.php. In my case, I have a /programs/ section that I want served by the proxy server itself (also a WordPress instance). Prevent looping by checking REDIRECT_STATUS.
# I force everything coming into proxy.example.com to be HTTPS <IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{HTTP:X-Forwarded-Proto} !https
RewriteCond %{HTTPS} off
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301] </IfModule> <IfModule mod_proxy.c>
# Redirect access for / (or any index) to the origin. NOTE target is http:// without SSLProxyEngine
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteRule ^(index\.(php|html|cgi))?$ http://origin.example.com/ [P]
# Do NOT redirect these patterns
RewriteCond %{REQUEST_URI} !^/wp-admin/
RewriteCond %{REQUEST_URI} !^/wp-login.php
RewriteCond %{REQUEST_URI} !^/programs/
# Redirect everything else. NOTE target is http:// without SSLProxyEngine
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteRule ^(.+)$ "http://origin.example.com/$1" [P]
# Mimic ProxyPassReverse. Fix the headers. Force to be https.
Header edit Location ^https?://origin\.example\.com/(.*)$ https://proxy.example.com/$1
Header edit* Link https?://origin\.example\.com/ https://proxy.example.com/ </IfModule>
ONLY for the IP of the PROXY server, rewrite any references in the HTML itself. This example is for a WordPress site.
Stolen from WordPress filter to modify final html output
2a) Add a Must Use plugin to add a ‘final_output’ hook. Add a file in wp-content/mu-plugins/buffer.php:
<?php
/** * Output Buffering * * Buffers the entire WP process, capturing
the final output for manipulation. */
ob_start();
add_action('shutdown', function() {
$final = '';
// We'll need to get the number of ob levels we're in, so that we can iterate over each, collecting
// that buffer's output into the final output.
$levels = ob_get_level();
for ($i = 0; $i < $levels; $i++) {
$final .= ob_get_clean();
}
// Apply any filters to the final output
echo apply_filters('final_output', $final); }, 0); ?>
2b) Add the following PHP to the wp-content/themes/yourthemenamehere/functions.php. It uses the ‘final_output’ hook above. (PHP 5.3 or later required for use of anonymous function.)
add_filter('final_output', function($output) {
// IP of the proxy server
$WWW_IP = “4.4.4.4”;
//$WWW_IP = “4.4.2.2”; // My workstation, for testing purpose only
if ($_SERVER['REMOTE_ADDR'] == $WWW_IP) {
// Force HTTPS when rewriting
$output = str_replace('http://origin.example.com', 'https://proxy.example.com’, $output);
// Catch anything that wasn’t a URL
return str_replace(‘origin.example.com, 'proxy.example.com', $output);
}
return $output;
});
If all goes well, you should now see the content from origin.example.com served from proxy.example.com.
I'm still testing this, so if you find errors or omissions, please add a comment.
I set up a virtual server using virtualmin, it didn't create the .htaccess file so I created one in the public_html folder and put the following code
RewriteEngine On
RewriteCond % ^megahotserved.com [NC]
RewriteRule ^(.*)$ http://www.megahotserved.com/$1 [L,R=301]
restarted apache and no effect and then tried
<VirtualHost *:80>
ServerName megahotserved.com
Redirect permanent / http://www.megahotserved.com/
</VirtualHost>
in the httpd.conf file, when I restarted apache firefox came up with an error
The page isn't redirecting properly.
Firefox has detected that the server is redirecting the request for this address in a way that will never complete.
What should I do ?
your code is correct, you just need to follow the next paragraph which I quoted from http://httpd.apache.org/docs/current/mod/mod_rewrite.html
By default, mod_rewrite configuration settings from the main server context are not inherited by virtual hosts. To make the main server settings apply to virtual hosts, you must place the following directives in each section:
RewriteEngine On
RewriteOptions Inherit
Seems like you don't have a VirtualHost that properly matches the www. address, so requests for http://www.megahotserved.com/ are hitting the very same vhost and getting into a circular redirect. So the redirect is working fine; you just have a different part of the server config to fix.
Agree with the above, and a small addition: it is better to redirect non-www to www rather than rewrite, otherwise you have two complete views ("copies") of your entire website; each page has two URLs, instead of one canonical one. This can be bad for search engines and other things.
Is it possible to redirect all requests to x.domain.com/.* to y.domain.com/.* WITHOUT letting this redirection be visible in the url?
I have unsuccessfully tried several things in .htaccess. Just specifying the [L] flag still shows this redirection in the url (as it does when I use the [R] flag additionally).
EDIT: as somebody claimed there being no reason for this, let me give some more information :)
I have one nice url: x.domain.com , which is well known.
Then there are a number of other domains: spring.domain.com , summer.domain.com , autumn.domain.com, winter.domain.com .
Depending on the time of the year, a specific y.domain.com becomes the current one. The x.domain.com should always map to the current one.
EDIT2:
I'll write here, as the code isn't nicely rendered in the comments...
I tried what Arjan suggested:
RewriteCond %{HTTP_HOST} ^x.domain.com$
RewriteRule ^(.*)$ /path/to/y.domain.folder/$1
Unfortunatly though this keeps redirecting forever. :(
Request exceeded the limit of 10 internal redirects due to probable configuration error. Use 'LimitInternalRecursion' to increase the limit if necessary. Use 'LogLevel debug' to get a backtrace.
Putting the [R] flag behind, I see in the url something like:
http://x.domain.com/path/to/y.domain.folder/path/to/y.domain.folder/path/to/y.domain.folder/ ...
Any suggestions?
Now that I can read the errorlogs, I can give a direct response, as what a possible 500 error refers to.
Assuming you have access to the Apache configuration, create the following virtual host for domain x.domain.com. Then simply update y to whatever you need each season.
<VirtualHost ...:80>
ServerName x.domain.com
UseCanonicalName Off
ProxyRequests Off
<Proxy *>
Order Allow,Deny
Allow from all
</Proxy>
ProxyPreserveHost Off
RewriteEngine On
RewriteRule ^$ http://y.domain.com/ [P,NC]
RewriteRule ^/(.*)$ http://y.domain.com/$1 [P,NC]
ProxyPassReverse / http://y.domain.com/
</VirtualHost>
Also to pick up the Alias suggestions, if you have multiple virtual hosts (one for each season) then you could put a server alias into the current domain. E.g.
<VirtualHost ...:80>
ServerName summer.domain.com
ServerAlias x.domain.com
...
</VirtualHost>
<VirtualHost ...:80>
ServerName spring.domain.com
...
</VirtualHost>
...
This would make Apache deliver the summer.domain.com pages if you go to x.domain.com. If your seasonal subdomains depend on the HOST header line to be set correctly (i.e. to season.domain.com) you would need to use the first suggestion above, though.
If these are not hosted on the same server, then you'd need the Proxy flag. This also requires the proxy module to be running. Not tested:
RewriteCond %{HTTP_HOST} ^x.domain.com$
RewriteRule ^(.*)$ http://y.domain.com/$1 [P]
EDIT: Given the edits to your question they're probably just on the same server. So then indeed, as jetru suggested an Alias might do. Or:
# No RewriteCond required; serve all content from other folder:
RewriteRule ^(.*)$ /path/to/y.domain.folder/$1
EDIT: The above would not change the HTTP_HOST header that was sent by the browser (maybe that can be done as well). This implies that it would only work if the subdomains are represented on the file system as separate directories. So, as the .htaccess would then be placed in the directory holding the website for x.domain.com, the RewriteCond wouldn't even be required. Also, the directory for this x.domain.com subdomain would in fact not need any HTML content then; in the end all content would be served from the directory of another subdomain.
EDIT: As the above does not seem to work either, and yields endless rewrite loops even when adding [NS], maybe simply adding [L] helps here:
RewriteRule ^(.*)$ /path/to/y.domain.folder/$1 [NS,L]
Or maybe one can set an environment variable to stop the loop:
RewriteCond %{ENV:MY_VAR} !=1
RewriteRule ^(.*)$ /path/to/y.domain.folder/$1 [E=MY_VAR:1]
But, for both [L] and [E]: I'm just guessing; I've never made mod_rewrite jump into the directory of another virtual host. I am not sure it can be done to start with.
Unfortunately, it's unclear how one would add a new subdomain. If one would just need to create a new directory with the name of the subdomain (without any use of some administrative tool) then the provider might be be using system wide rewriting as well. In fact, even without subdomains the provider might be doing some Mass Virtual Hosting as described in the URL Rewrite Guide.
I guess the best solution would be to change the value of HTTP_HOST on the fly, to solve issues with any system wide rewriting. Maybe the following is allowed to achieve that:
RewriteCond %{HTTP_HOST} ^x.domain.com$
RewriteRule ^(.*)$ /path/to/y.domain.folder/$1 [E=HTTP_HOST:y.domain.com]
Again, as the above would only be present in the .htaccess in the x.domain.folder, the RewriteCond is probably not needed at all.
Have you tried
Alias /dir/file.html /full/path/to/other/file.html
??
To my knowledge and testing with firebug a redirect via .htaccess is always announced to the client and it's up to him how to proceed. It is therefore not an alternative to some sort of SSI functionality. To prevent a "fake" address modern browser should always make the REAL address visible to the user, however I think I have seen some misbehavior in programs like "feeddemon" where IE is embedded. If you - for whatever reason - really want to show content from one subdomain on another you can try using Javascript or (i)frames on the user side or some include functionality on the server site (eg. file_get_contents with php). However, I don't recommend this.