.htaccess directives fail to redirect www to non-www URLs

.htaccess directives fail to redirect www to non-www URLs - If a page has internal and external outgoing links to redirecting URLs, it’s returning 3xx (301, 302, etc.) HTTP status codes standing for redirection. This issue means that the page does not exist on a permanent or temporary basis. It appears on most of the popular web browsers, usually caused by a misconfigured website. However, there are some steps you can take to ensure the issue isn’t on your side. You can find more details about redirecting URLs by reading the Google Search Central overview. In this article, we’ll go over how you can fix the .htaccess directives fail to redirect www to non-www URLs error on your web browser. Problem :


I'm trying to redirect https://www.example.com to https://example.com.


I'm running Ubuntu server 2020 lts with Apache 2, PHP 7 and Let's Encrypt SSL.


My file structure:


logs/
private/
public/
└ index.php
.htaccess
index.php

My Apache2 config file (/etc/apache2/sites-available/example.com-le-ssl.conf):


<IfModule mod_ssl.c>
<VirtualHost *:443>

<Directory /var/www/example.com/>
Options Indexes FollowSymLinks
AllowOverride All
Require all granted
Options -Indexes
Options -Includes
Options -ExecCGI
</Directory>

ServerAdmin webmaster@localhost
ServerName example.com
ServerAlias www.example.com
DocumentRoot /var/www/example.com
ErrorLog $APACHE_LOG_DIR/error.log
CustomLog $APACHE_LOG_DIR/access.log combined

Include /etc/letsencrypt/options-ssl-apache.conf
SSLCertificateFile /etc/letsencrypt/live/example.com-0001/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/example.com-0001/privkey.pem
</VirtualHost>
</IfModule>

(/etc/apache2/sites-available/example.conf):


<VirtualHost *:80>

<Directory /var/www/example.com/>
Options Indexes FollowSymLinks
AllowOverride All
Require all granted
Options -Indexes
Options -Includes
Options -ExecCGI
</Directory>

ServerAdmin webmaster@localhost
ServerName example.com
ServerAlias www.example.com
DocumentRoot /var/www/example.com
ErrorLog $APACHE_LOG_DIR/error.log
CustomLog $APACHE_LOG_DIR/access.log combined
RewriteEngine on
RewriteCond %SERVER_NAME =www.example.com [OR]
RewriteCond %SERVER_NAME =example.com
RewriteRule ^ https://%SERVER_NAME%REQUEST_URI [END,NE,R=permanent]
</VirtualHost>

My .htaccess file:


RewriteEngine On

# First rule
RewriteBase /
RewriteCond %HTTP_HOST ^www.(.*)$ [NC]
RewriteRule ^(.*)$ https://%1/$1 [R=301,L]

# Second rule
RewriteCond %THE_REQUEST ^GET /public/ [NC]
RewriteRule ^public/(.*)$ $1 [L,R=301,NE]
RewriteRule ^((?!public/).*)$ public/$1 [L,NC]

cURL output:


curl -I http://www.example.com
HTTP/1.1 301 Moved Permanently
Date: Thu, 01 Apr 2021 13:42:14 GMT
Server: Apache
Location: https://www.example.com/
Content-Type: text/html; charset=iso-8859-1

I don't understand why the first rule doesn't redirect as expected.


The second rule works, it hides public. I'm in the public directory but public is invisible in https://example.com/.


Solution :

There's nothing actually "wrong" with the config/directives you've posted, but it seems you don't have a valid SSL cert that covers the www subdomain so you can't redirect from https://www.example.com/ without the user accepting the invalid cert (this is the "error") - which they should never do.


When requesting HTTPS, the browser establishes a secure connection with the server before any server-side scripts/redirects are even processed. If the security cert is invalid (as in this case), the user sees a warning in the browser and are unable to continue (unless the user jumps through hoops and accepts the invalid cert - which they should never do, as already mentioned). If there is no SSL cert at all then the server simply fails to connect.


So, there's nothing actually "wrong" with the config you've posted. Providing you have a valid cert installed for the www subdomain then a request for http://www.example.com/ would be redirected to https://www.example.com/ by the mod_rewrite directive in the <VirtualHost *:80> container and then your directives in .htaccess would redirect from https://www.example.com/ to https://example.com/ (canonicalising the hostname). Yes, that's two redirects, but there's nothing wrong with two redirects here. And two redirects would actually be a requirement if implementing HSTS.


When testing multiple redirects (a redirect "chain") with CURL then you need to use the -L flag, otherwise it does not follow the first redirect. For example:


curl -I -L http://www.example.com/

But in this case, without a valid cert installed for the www subdomain you get a warning back from CURL and further requests are stopped:



curl: (51) SSL: no alternative certificate subject name matches target host name 'www.example.com'





However, you could optimise this a bit (if HSTS is not a concern) and redirect directly to the canonical hostname (ie. example.com) from the <VirtualHost *:80> container. You can also do this with a simple mod_alias Redirect. You don't need mod_rewrite for this.


For example, instead of the following in <VirtualHost *:80>:



RewriteEngine on
RewriteCond %SERVER_NAME =www.example.com [OR]
RewriteCond %SERVER_NAME =example.com
RewriteRule ^ https://%SERVER_NAME%REQUEST_URI [END,NE,R=permanent]


you replace this with:


Redirect 301 / https://example.com/

There's no need to check the requested host (ie. SERVER_NAME) anyway in the vHost container, since it can't be anything other than the two hostnames you've defined with the ServerName and ServerAlias directives. (Assuming you have a default vHost:80 defined earlier that catches all "invalid" requests? Either way, they will all be redirected to your canonical hostname anyway.)


With this in place, any request for HTTP (ie. http://example.com/ or http://www.example.com/) will be redirected directly to https://example.com in a single redirect (the redirect in .htaccess is not required in this instance). This naturally circumvents the security cert issue for any request to HTTP only.


HOWEVER, any direct request the user makes to https://www.example.com/ will still be subject to the SSL cert warning until a valid cert is installed.




Aside: Due to rewriting all requests to the /public subdirectory (which contains index.php - the "front-controller" I assume), the additional /index.php in the document root is entirely superfluous.


We hope that this article has helped you resolve the htaccess, redirects, no-www error in your web browsers. Enjoy browsing the internet uninterrupted!

Comments

Popular posts from this blog

Redirected urls show in serp, with the original permalink but with the title and meta of the target page

How can I redirect everything but the index as 410?

How do I redirect traffic only if being accessed from a specific port?