.htaccess Apache2 – Multiple Conditional Redirects in a Single .htaccess File

.htaccessApache2

I have a folder that simply has a "Coming Soon" single page html.

I then have several domains that I point to this folder from time to time as needed.

Simple right?

Well what I want to have is a condition where if the original requested page was non-www to go to www (301>
PLUS if not https to go to https (301)
AND then redirect all traffic to https://www.originating-domain.xzy/index.html (302)

the purpose is for this to be a landing page for multiple purpose use
but ALWAYS 301 to https://www
and then 302 to index.html

I already have this non-www to www and http to https working on each site:

RewriteCond %{HTTP_HOST} !^www\. [NC]
RewriteRule ^ https://www.%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
RewriteCond %{HTTP:X-Forwarded-Proto} !https
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}/$1 [L,R=301]

now I want to add the 302 temp redirect to index.html.

or is there just a better way to do this completely?
like since this is all temporary anyway… 302 all traffic to index
I tried this but didn't work

RewriteCond %{REQUEST_URI} !.*index\.html
RewriteRule https://www.%{HTTP_HOST}/index.html [R=302,L]

Best Answer

RewriteCond %{REQUEST_URI} !.*index\.html
RewriteRule https://www.%{HTTP_HOST}/index.html [R=302,L]

There are a couple of issues with this...

  1. You appear to be missing the RewriteRule pattern (first argument) completely, so this directive will fail to match.

  2. If this did match it would prefix the www. subdomain again. I assume you are putting this redirect after the canonical redirects (HTTP to HTTPS and non-www to www) - as you should be. So, this would redirect to https://www.www.example.com/index.html, because by the time this redirect is triggered, the hostname is already canonical.

The condition (RewriteCond directive) is not really needed, since this check (that /index.html is not already requested) could more efficiently be handled by the RewriteRule directive itself.

For example:

RewriteRule !^index\.html$ /index.html [R=302,L]

There's no need to include the scheme+hostname in the substitution string since you are wanting to redirect to the same anyway. If you wanted to be explicit, you could write https://%{HTTP_HOST}/index.html.

Note that, as it stands, index.html cannot reference any other local resources (images, CSS, JavaScript, etc.) since these requests will also be redirected. To allow access to local resources you would need to add a couple of conditions to exclude requests for static resources.

RewriteCond %{REQUEST_URI} !.\.(jpg|png|webp|css|js)$
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule !^index\.html$ /index.html [R=302,L]

Alternatively, host these resources on an external domain. (Or in a subdirectory and exclude the entire subdirectory.)

However, if choosing to "redirect" at all, I would perhaps redirect to a more unique/meaningful named file, eg. /coming-soon.html. The problem with using /index.html is if you later want to serve different content on that URL and it has been cached (for whatever reason). Although /coming-soon.html should probably be "noindex".

HOWEVER, it may be preferable to not redirect at all and instead serve a temporary "503 Service Unavailable" response. See my answer to the following question on the Webmasters stack for more information on this:


Aside:

RewriteCond %{HTTP:X-Forwarded-Proto} !https
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}/$1 [L,R=301]

Are you behind a front-end proxy that manages the SSL connection?

If you are then that's OK, although the second condition that checks the HTTPS server variable is therefore superfluous. However, if you are not behind an SSL proxy then these directives are vulnerable to being circumvented (ie. the user is not redirected to HTTPS) if an X-Forwarded-Proto: https header is injected into the request.


UPDATE:

OK this works as i want it to. But can i combine them in some way?

RewriteCond %{HTTP_HOST} !^www\. [NC]
RewriteRule ^ https://www.%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

RewriteCond %{REQUEST_URI} !.*coming-soon\.html [NC]
RewriteRule ^(.*)$ https://%{HTTP_HOST}/coming-soon.html [R=302,L]

As noted above, the last rule is essentially the same as the following (when used in combination with the preceding canonical redirects), which is simpler and more efficient:

RewriteRule !^coming-soon\.html$ /coming-soon.html [R=302,L]

In the second rule you should also change the RewriteRule pattern from ^(.*)$ to ^ (the same as the first rule). ^(.*)$ unnecessarily captures a backreference and is less efficient.

You mentioned in an earlier comment (now deleted) that you wanted this to work for any subdomain as well. It "works" for any subdomain, however, it will always prepend an additional www subdomain, which may or may not be desirable? (It's not usual to have a www sub-subdomain on subdomains. YMMV.)

There's no real need to "combine" these rules. You certainly can't combine them if you are wanting to 301 redirect to www+HTTPS before 302 redirecting to the "coming soon" page. Whilst the first two rules (301 redirects) can be "combined" into a single rule, it serves no purpose.

The only minor issue here is there are potentially (at most) 2 redirects. First, a 301 to www+HTTPS on the original URL-path and a second 302 to the "coming soon" page.

I would question whether you actually need the initial 301 redirect to www+HTTPS when you are redirecting the user anyway to a temporary "coming soon" page. Once you have implemented the new site (replacing the "coming soon" page) then you would implement the canonical redirect. The 302 redirect can still redirect to www+HTTPS. (There is, however, an edge case when /coming-soon.html is requested directly.)

For example:

# 302 redirect to the coming soon page (www+HTTPS)
RewriteCond %{HTTP_HOST} ^(?:www\.)?(.+?)\.?$
RewriteRule !^coming-soon\.html$ https://www.%1/coming-soon.html [R=302,L]

# Edge case...
# The following two rules only apply if "/coming-soon.html" is requested directly
# and either non-www hostname and/or HTTP is requested
# in which case 301 redirect to the same on www+HTTPS

# www subdomain is missing...
RewriteCond %{HTTP_HOST} !^www\.
RewriteRule ^ https://www.%{HTTP_HOST}%{REQUEST_URI} [R=301,L]

# HTTP + www has been requested
RewriteCond %{HTTPS} off
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]

Any request for http://example.com/foo is 302 redirected straight to https://www.example.com/coming-soon.html.

If http://example.com/coming-soon.html should be requested then it is 301 redirected to https://www.example.com/coming-soon.html (just fixing the HTTPS and www subdomain).

There is only at most 1 external redirect.

Related Topic