Inspired by @MikeRockétt's answer, this is a "simplified" version, using just one condition (instead of three). This also canonicalises a FQDN (ie. by removing an optional trailing dot on the hostname):
RewriteEngine On
RewriteCond %{HTTP_HOST}#%{HTTPS}s ^www\.(.+?)\.?#(?:on(s)|)
RewriteRule ^ http%2://%1%{REQUEST_URI} [R=301,L]
This 301 redirects www to non-www while maintaining the same protocol, HTTP or HTTPS. Can be used unaltered in either .htaccess
(directory context) or in the main server config / vhost. (Although, if you are in a virtualhost context you should probably be using a simpler mod_alias Redirect
instead.)
Explanation:
The TestString %{HTTP_HOST}#%{HTTPS}s
(which evaluates to a string of the form "www.example.com#ons") is compared against the CondPattern ^www\.(.+?)\.?#(?:on(s)|)
The condition is successful for any request whose Host
header starts "www.".
^www\.(.+?)\.?
first checks that the Host
starts with "www." (if not, it fails early) and captures the remaining host header (excluding an optional trailing dot) in the %1
backreference. The regex that captures the domain name, ie. (.+?)
is made non-greedy so that it does not capture the optional dot at the end.
#
is just an arbitrary character that is used to separate the two values HTTP_HOST
and HTTPS
. Importantly, #
cannot itself appear in either of these two values.
(?:on(s)|)
is a non-capturing group that uses alternation to match against %{HTTPS}s
. It either matches on(s)
and captures the "s" (in the %2
backreference) or it matches anything and captures nothing (so %2
is empty).
Providing the previous condition is successful then the substitution string (http%2://%1%{REQUEST_URI}
) is evaluated and the request redirected. The backreference %2
, from the preceding CondPattern, either holds an "s" (to make "https" in the substitution) or is empty (ie. "http") and %1
is the hostname less the "www." prefix.
The REQUEST_URI
server variable holds the full URL-path, including the slash prefix.
must my server have an SSL certificate?
Yes, otherwise the browser will block the connection (complaining about an invalid security certificate) - or simply time-out (because your server is not responding on port 443) and the request will not even reach your server.
HTTP_HOST
for the presence ofwww.
. It should work for HTTPS as well. – Mike Rockétthttp|https
to rewriterule target. I'm not sure whats the dynamic way to deal with this. – Rahil Wazir