Preface
Firstly: A simply Port 80 -> Port 443 Rewrite WILL NOT fix this. In almost every previous question, mail thread, forum thread, etc., I have found this was the first ignorant response and was parroted several times.
Secondly: Yes I know you cannot serve HTTP and HTTPS traffic on the same port. This is not that.
Scenario:
Apache Server hosting multiple sites via port multiplication. Port 80 serves a public site. Port 443 serves the secure version of that site.
Ports 7443, 8443, and 9443 each serve separate SSL-Secured sites.
If a user mistypes the URL, or is given a link that isn't valid, say http://hostname.tld:7443, they are given the following ridiculous page:
Instead of the server just redirecting them over to https://hostname.tld:7443.
My Question is, how in the name of Zeus's butthole can you modify Apache's behavior or this error message to redirect the user automagically?
Apache is obviously serving a non-https request (to display that error message) even though it is configured for HTTPS. It seems remarkably dumb to me to not just do the redirect by default, but I can understand why they went with the behavior they did, even if I don't agree with it. So my question is: can you change it? They are handling the error SOMEWHERE, and with Apache being the configuration cornucopia that it is, it stands to reason there is some directive somewhere to handle this behavior, but I have been unable to find it in several hours of tinkering so far.
Update:
I have attempted a variety of things including:
using
ErrorDocument 400
directives to get to a CGI and a PHP script that just sendStatus 301
andLocation
headers. This results in a blank page. UsingErrorDocument 400 https://hostname.tld:7443
simply results in that link being displayed on the page.Using almost every combination of
mod_rewrite
I or Google can come up with, including blanket statements that direct the site entirely; these never work. Literally, they do nothing. I'm surmising that Apache is kicking to the above error before even attempting to process the rewrite directives.
I can't use port-based redirects, because of the custom port use. I can't use script-based redirects because they never get served because of the http/https mismatch. I'm almost willing to chalk this up to a bug, or an unintended behavior, but somebody had the forethought to put a very custom error message in there, they didn't bother thinking that maybe you'd want to just cart to the URL they are already providing?
I think this is probably a bug in how Apache 2.2 and lower handles this particular circumstance.
It seems that on an SSL read
400 Bad Request
error, Apache 2.2 doesn't return the HTTP response code or headers, only the HTTP response body. I test by telnetting to port 443 and sending:The server immediately returns (for me):
Note the lack of an HTTP response code or any HTTP headers.
When I do this to an Apache 2.4 server, I get:
If I setup an ErrorDocument line like you did:
Then I get the HTML for a 302 redirect, but again, none of the headers. Without the 302 redirect response code and the
Location:
header, the browser won't redirect.Try upgrading to Apache 2.4 and see if it works. I've tested and confirmed with at least Apache 2.4.3, but I haven't gone through the effort of finding exactly when this was behavior was updated. I suspect that in the large amount of work they did preparing 2.4, they corrected the undesirable behavior as a side-effect.
Relevant Apache httpd bugs:
UPDATE
You can force a buggy Apache to give you the behavior you want (the redirect) by having the script print out its headers (which will not be sent to the client), and then manually print out again the headers you want. Here's a basic Perl script that works under Apache 2.2.22:
You should be aware that there are other reasons a 400 may be generated besides just talking to an SSL port without SSL. The easy way to determine this is to look for the
HTTPS
environment variable. If it's set, then SSL was negotiated properly and something else is causing the 400 (don't do the double header trick if that's the case). IfHTTPS
is not set, return your redirect as above.You can fix this with mod-rewrite. Set a rule to match anything. See this answer on Stackoverflow