Redirect all URLs to HTTPS, but force one to HTTP (Apache)

I have a WordPress Multisite blog which is wholly behind HTTPS.

Now I need to force a single page to HTTP in order to embed an HTTP-only iframe (HTTP embeds do not work inside HTTPS pages). With force I mean to redirect to HTTP in case the page is being loaded with HTTPS.

Read More

The site works fine with HTTPS, but attempting to access the page that should redirect to plain HTTP the server redirects the visitor to the site home.

Here are my current .htaccess rewrite rules:

RewriteEngine On

# Redirect all to HTTPS if not some-page.
RewriteCond %{HTTPS} off
RewriteCond %{HTTP_HOST} ^example.com # Check host as some subdomains are not used with HTTPS.
RewriteCond %{REQUEST_URI} !^/some-page(/.*)?
RewriteRule (.*) https://%{HTTP_HOST}/$1 [R=301,L]

# Redirect some-page to HTTP if HTTPS.
RewriteCond %{HTTPS} on
RewriteCond %{HTTP_HOST} ^example.com
RewriteCond %{REQUEST_URI} ^/some-page(/.*)?
RewriteRule (.*) http://%{HTTP_HOST}/$1 [R=301,L]

# WordPress below here

RewriteBase /

RewriteRule ^index.php$ - [L]

# add a trailing slash to /wp-admin
RewriteRule ^wp-admin$ wp-admin/ [R=301,L]

RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^ - [L]
RewriteRule ^(wp-(content|admin|includes).*) $1 [L]
RewriteRule ^(.*.php)$ $1 [L]
RewriteRule . index.php [L]

What I expect those rules to do:

  1. If not HTTPS, redirect any page except some-page.* in example.com to HTTPS version.
  2. If not HTTPS and accessing some-page.* don’t redirect.
  3. If HTTPS and accessing some-page.*, redirect to HTTP.

What happens:

  1. All pages go to HTTPS as wanted.
  2. All requests to some-page.* just redirects to index.php, meaning all requests to example.com/some-page redirect to example.com/. This happens with both: HTTP and HTTPS requests. In the end the browser ends up to the https://example.com/ page.

Additionally:

  • My .htaccess doesn’t contain anything else besides some Xdebug triggering options.
  • I tried moving the HTTPS rules below the WordPress rules: they dont trigger at all.
  • I moved only the some-page.* -> HTTP redirection under the WordPress rules: no effect, other than HTTPS access to some-page.* works (doesn’t redirect to index).
  • Tried switching the HTTP/S rules around: no effect.

All pointers appreciated.

EDIT:

I tried to validate some WordPress stuff for this. For some reason WordPress might be the one doing the redirect. All attempts to access some-page.* result in a wp_redirect with the site home and status 301 to trigger.

I created the following if-else statement to my WordPress configuration file but it has no effect (I presumed that some HTTP->HTTPS redirection was happening):

if (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') {
    define( 'WP_SITEURL', 'https://example.com' );
    define( 'WP_HOME', 'https://example.com' );
} else {
    define( 'WP_SITEURL', 'http://example.com' );
    define( 'WP_HOME', 'http://example.com' );
}

I also attempted to change my .htaccess rules to the following as per some guide I read online:

RewriteCond %{HTTPS} off
RewriteCond %{HTTP_HOST} ^example.com
RewriteCond %{REQUEST_URI} !^/some-page
RewriteRule !^some-page.* https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]

RewriteCond %{HTTPS} on
RewriteCond %{HTTP_HOST} ^example.com
RewriteCond %{REQUEST_URI} ^/some-page
RewriteRule ^some-page.* http://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]

But it didn’t seem to change anything.

EDIT 2:

Somehow it seems the .htaccess is rewriting some-page.* directly to index.php. After I debugged and hooked into WordPress’ redirect_canonical(), it shows nothing related to some-page.*. Instead it only shows that it is redirecting https://example.com/index.php to https://example.com/. This probably explains the earlier wp_redirect with 301.

I tried to check the rewrites with http://htaccess.madewithlove.be/, and it says the rewrites (should) be working as expected.

EDIT 3:

Did some rewrite debugging. It all works fine, but for some reason the one where some-page.* should be redirected to non-HTTPS, the server value %{HTTPS} is off on all rewrite attempts (even when loading the page with HTTPS), essentially making the rule useless. If I remove the HTTPS check, I get a rewrite loop (from HTTPS to HTTP and so on when on some-page.* URLs.).

Same result with SERVER_PORT rewrite conditional. All requests seem to come as 80.

When would be an appropriate time to check for the connection port/HTTPS?

Related posts