http to https AND //domain.com to www.domain.com AND subdomain.domain.com to subdomain.domain.com through htaccess

Viewed 71

I'm hoping someone can help me, as for years I've always tried different approaches to redirecting and came across an interesting one on a project I'm working on.

I need HTTP to redirect to HTTPS AND I need non-www to redirect to www but only if //domain.com without any subdomains AND I need subdomain.domain.com to still work so do not redirect the subdomain, i'm using wildcard (*) in apache to handle any subdomain as these will be detected in php with $_SERVER and handled for specific tasks.

This is what I have so far however the non-www (//domain.com) ends up in an endless redirect

RewriteEngine On
Options -Indexes

RewriteCond %{HTTPS} off [OR]
# add www if not subdomain
RewriteCond %{HTTP_HOST} ^[^.]+\.[^.]+$
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
   
RewriteCond %{HTTPS} off [OR]
# remove www if subdomain
RewriteCond %{HTTP_HOST} ^www\.([^.]+\.[^.]+\.[^.]+)$ [NC]
RewriteRule ^ https://%1%{REQUEST_URI} [R=301,L]

Apache virtual hosts two different files one for non SSL and one for SSL using lets encrypt

<VirtualHost *:80>
    DocumentRoot /var/www/html/www.domain.com
    ServerName domain.com
    RewriteEngine on
    RewriteCond %{SERVER_NAME} =domain.com
    RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent]
</VirtualHost>

<VirtualHost *:80>
    DocumentRoot /var/www/html/www.domain.com
    ServerName www.domain.com
    ServerAlias *.domain.com
    RewriteEngine on
    RewriteCond %{SERVER_NAME} =www.domain.com
    RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent]
</VirtualHost>

<VirtualHost *:443>
    ServerName www.domain.com
    ServerAlias *.domain.com
    DocumentRoot /var/www/html/www.domain.com
    RewriteEngine on
    RewriteCond %{SERVER_NAME} =domain.com
    RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent]

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

<VirtualHost *:443>
    ServerName domain.com
    DocumentRoot /var/www/html/www.domain.com
    Include /etc/letsencrypt/options-ssl-apache.conf
    SSLCertificateFile /etc/letsencrypt/live/domain.com-0001/fullchain.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/domain.com-0001/privkey.pem
</VirtualHost>

All your help greatly appreciated!

2 Answers

however the non-www (//domain.com) ends up in an endless redirect

It is due to your first redirect rule which should be changed to:

Options -Indexes
RewriteEngine On

# add www and https for main domain
RewriteCond %{HTTP_HOST} !^www\. [NC,OR]
RewriteCond %{HTTPS} !on
RewriteCond %{HTTP_HOST} ^(?:www\.)?([^.]+\.[^.]+)$ [NC]
RewriteRule ^ https://www.%1%{REQUEST_URI} [R=301,L,NE]

# remove www if subdomain   
RewriteCond %{HTTP_HOST} ^www\. [NC,OR]
RewriteCond %{HTTPS} !on
RewriteCond %{HTTP_HOST} ^(?:www\.)?(?!www\.)([^.]+\.[^.]+\.[^.]+)$ [NC]
RewriteRule ^ https://%1%{REQUEST_URI} [R=301,L]

Make sure to test it after clearing browser.

You don't need to setup different rules for SSL in both www and other subdomains. All you need to do is have a rule to enforce HTTPS and another to enforce www in case you're stumbling on the root domain:

RewriteEngine On
Options -Indexes

# Makes sure HTTPS is used
RewriteCond %{HTTPS} off
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

# Adds www if not subdomain
RewriteCond %{HTTP_HOST} ^example\.com$
RewriteRule ^ http://www.example.com%{REQUEST_URI} [L,R=301]

Important to specify the root domain on RewriteCond for the www prepending, or at least use a less generic rule, such as ^[a-z0-9-_]+\.[a-z0-9-_]+$.

Related