Apache sends plain-text response when accessing SSL-enabled site without HTTPS

.htaccessapache-2.2mod-rewritemod-ssl

I've never encountered something such as this before. I was attempting to simply redirect the page to the HTTPS version if it determined that HTTPS was off, but instead it's displaying an HTML page rather than actually redirecting; and even odder, it's displaying it as text/plain!

The VirtualHost Declaration (Sort of):

ServerAdmin admin@example.com
DocumentRoot "/path/to/files"
ServerName example.com
SSLEngine On
SSLCertificateFile /etc/ssh/certify/example.com.crt
SSLCertificateKeyFile /etc/ssh/certify/example.com.key
SSLCertificateChainFile /etc/ssh/certify/sub.class1.server.ca.pem
<Directory "/path/to/files/">
    AllowOverride All
    Options +FollowSymLinks
    DirectoryIndex index.php
    Order allow,deny
    Allow from all
</Directory>
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule .* https://example.com:6161 [R=301]

The Page Output:

<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>301 Moved Permanently</title>
</head><body>
<h1>Moved Permanently</h1>
<p>The document has moved <a href="https://example.com:6161">here</a>.</p>
<hr>
<address>Apache/2.2.21 (Unix) mod_ssl/2.2.21 OpenSSL/1.0.0e DAV/2 Server at example.com Port 443</address>
</body></html>

I've tried moving the Rewrite stuff up above the SSL stuff hoping it'd do something and nothing happens. If I view the page with via HTTPS, it displays fine like it should. It's obviously detecting that I'm trying to rewrite the path, but it's not acting.

The Apache error log does not indicate anything to me that might have gone wrong.

When I remove the RewriteRules:

<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>400 Bad Request</title>
</head><body>
<h1>Bad Request</h1>
<p>Your browser sent a request that this server could not understand.<br />
Reason: You're speaking plain HTTP to an SSL-enabled server port.<br />
Instead use the HTTPS scheme to access this URL, please.<br />
<blockquote>Hint: <a href="https://example.com/"><b>https://example.com/</b></a></blockquote></p>
<p>Additionally, a 404 Not Found
error was encountered while trying to use an ErrorDocument to handle the request.</p>
<hr>
<address>Apache/2.2.21 (Unix) mod_ssl/2.2.21 OpenSSL/1.0.0e DAV/2 Server at example.com Port 443</address>
</body></html>

I get the standard "you can't do this because you're not using SSL" response, which is also provided in text/plain rather than being rendered as HTML. This would make sense, it should only work for HTTPS-enabled connections, but I still want to redirect them to the HTTPS connection when it determines that it is not enabled.

Thinking I could circumvent the system:

I tried adding a ErrorDocument 400 https://example.com:6161 to the config file instead of using RewriteRules, and that just gave me a new message, still no cheese.

<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>302 Found</title>
</head><body>
<h1>Found</h1>
<p>The document has moved <a href="https://example.com:6161">here</a>.</p>
<hr>
<address>Apache/2.2.21 (Unix) mod_ssl/2.2.21 OpenSSL/1.0.0e DAV/2 Server at example.com Port 443</address>
</body></html>

How can I force Apache to actually redirect rather than displaying a "301" page that shows HTML in plain-text format?

Best Answer

First: With Apache you cannot have HTTPS and HTTP running on the same port.

See: Apache answer both HTTP and HTTPS on the same port

For handling both SSL and non-SSL traffic you have to define two virtual hosts.

See: Redirect http to https apache on different port

For the redirect from non-SSL virtual host to SSL virtual host we use this:

<VirtualHost *:80>
        RewriteEngine on
        RewriteCond  %{HTTPS} !=on
        RewriteCond  %{HTTP_HOST} ^(.*)$
        RewriteRule  ^(.*)/? https://%1$1 [L,R]
</VirtualHost>

Remains the problem that explicitly sending a non-SSL request to the SSL-enabled port ( http://mydomain.com:443/ ) gives the:

You're speaking plain HTTP to an SSL-enabled server port

page as plain text (in a Firefox browser). Explicitly sending a SSL request to the non-SSL port ( https://mydomain.com:80/ ) gives a:

ssl_error_rx_record_too_long error

(in the Firefox browser).

Why is this occurring?