How can I redirect an entire site to a single page?

Solution 1:

If you are "shutting down a site" then you probably should not be "redirecting" the old site pages to a single page. An HTTP redirect sends a 301 response code, informing users and search engines the pages have moved. (Although mass redirects to a single page are likely to be seen as soft-404s by Google.)

Instead, you should be serving a custom "410 Gone" response instead. A 410 informs search engines the pages are gone and not coming back. Your "single page" is the custom error document.

For example:

ErrorDocument 410 /single-page.html

RewriteEngine On

# Trigger a 410 Gone for all user requests
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteRule ^ - [G]

The additional condition that checks against the REDIRECT_STATUS environment variable is to ensure that direct requests for /single-page.html itself also trigger a 410 without creating a rewrite loop. The REDIRECT_STATUS env var is empty on the initial request, but set to "410" after the RewriteRule is triggered and the HTTP response status is set.

(Aside: The technique of using REDIRECT_STATUS in this way to detect an already triggered "error state" does not work on LiteSpeed servers since the env var is not updated during the request in the case of 4xx responses. However, it is updated for internal rewrites, ie. 200 OK responses, so it's still a good solution to prevent internal rewrite-loops. It is bizarre why there would be this difference though. Seems like a bug.)

Solution 2:

The reason http://www.example.com/ is working and https://www.example.com/doesnotexist.html isn't is because your rewrite condition explicitly disables the rewriting if the client is accessing the site via HTTPS (which I believe several major browsers do by default now, but I don't have a source for this right off the top of my head).

I'm assuming you did that to prevent an infinite loop, which would otherwise infinitely rewrite and redirect every request to (what I assume is) the canonical url, with the client never being able to actually view the page.

I believe the following configuration is what you're looking for. Please note that I tested this on my local server, but I'm running version 2.4.46. As best as I can tell from an admittedly semi-half-assed glance over the version 2.2 mod_rewrite documentation, there weren't any significant changes in the upgrade to version 2.4, at least as it pertains to mod_rewrite specifically.

RewriteEngine On
RewriteCond expr "! %{REQUEST_URI} -strmatch '/'"
RewriteRule (.*) https://www.example.com/ [L,R=301,NE]

This configuration enables the rewrite engine, obviously, after which it checks the URI of the request. If it's not equal to "/", it rewrites the entire thing to only the document root, issues a 301 redirect like you did in your original, and stops processing any further rules. You may or may not need a RewriteBase "/" directive declaration right after the RewriteEngine On. It didn't seem to matter when I tested this, as I was able to rewrite nested-directory URI's with no problem (i.e... /a/b/c successfully redirected to /), but the documentation does make a note to point this out, so here I am passing the warning down.

Again, I did test this, but the server version is different so hopefully you don't run into any problems from that. Please note that in order for this to work (barring technical limitations or differences stemming from the aforementioned version difference), your hosting provider needs to have enabled the AllowOverride directive, probably with the All option, although I wasn't able to pin down exactly what the minimum requirement for the rewrite directives to work was.