virtual host force https and redirect www to non-www, but no other subdomains
Asked Answered
P

2

7

This is essentially the same question as htaccess force https and redirect www to non-www, but no other subdomains (i.e., I want to configure Apache to redirect all non-HTTPS and/or "www" URLs to HTTPS non-www URLs), but I want to configure Apache via a Virtual Host rather than an .htaccess file (since I read that avoiding .htaccess has some benefits).

I was able to get the following answer to work when using an .htaccess file: https://mcmap.net/q/260286/-htaccess-force-https-and-redirect-www-to-non-www-but-no-other-subdomains But it did not work when I tried transferring that answer's configuration to my Virtual Hosts configuration; "https://www.domain.com" never redirected to "https://domain.com".

I read up on the differences between .htaccess and Virtual Host .conf files, and found this http://tltech.com/info/rewriterule-in-htaccess-vs-httpd-conf/ and this: https://www.digitalocean.com/community/questions/can-you-use-virtual-host-config-conf-to-redirect-www-domain-to-non-www?answer=15129 which seemed to hint that I could just wrap the configuration in a <Directory> block and it would work. Unfortunately, it doesn't ("https://www.domain.com" is still never redirected to "https://domain.com"), so I'm wondering if the Internet knew what I was doing wrong:

<VirtualHost *:80>
        ServerName domain.com
        ServerAlias www.domain.com

        ServerAdmin [email protected]
        DocumentRoot /var/www/domain.com/

        ErrorLog ${APACHE_LOG_DIR}/error.log
        CustomLog ${APACHE_LOG_DIR}/access.log combined

        <Directory /var/www/domain.com/>
                RewriteEngine On

                # match any URL with www and rewrite it to https without the www
                RewriteCond %{HTTP_HOST} ^(www\.)(.*) [NC]
                RewriteRule (.*) https://%2%{REQUEST_URI} [L,R=301]

                # match urls that are non https (without the www)
                RewriteCond %{HTTPS} off
                RewriteCond %{HTTP_HOST} !^(www\.)(.*) [NC]
                RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
        </Directory>
</VirtualHost>

I've also tried configuring <VirtualHost *:443> as Dusan Bajic suggested in the comments, but that has no effect either; https://www.domain.com still won't redirect to https://domain.com:

<VirtualHost *:443>
        ServerName domain.com
        ServerAlias www.domain.com

        ServerAdmin [email protected]
        DocumentRoot /var/www/domain.com/

        ErrorLog ${APACHE_LOG_DIR}/error.log
        CustomLog ${APACHE_LOG_DIR}/access.log combined

        SSLCertificateFile /etc/letsencrypt/live/domain.com/cert.pem
        SSLCertificateKeyFile /etc/letsencrypt/live/domain.com/privkey.pem
        Include /etc/letsencrypt/options-ssl-apache.conf
        SSLCertificateChainFile /etc/letsencrypt/live/domain.com/chain.pem

        <Directory /var/www/domain.com/>
                RewriteEngine On

                # match any URL with www and rewrite it to https without the www
                RewriteCond %{HTTP_HOST} ^(www\.)(.*) [NC]
                RewriteRule (.*) https://%2%{REQUEST_URI} [L,R=301]
        </Directory>
</VirtualHost>

Also per the comments, I have tried the above *:443 configuration paired with a *:80 configuration with the <Directory> block changed to only redirect HTTP to HTTPS. But when I do that, "www" never gets removed.

<Directory /var/www/paradoxmayhem.com/>
        RewriteEngine On

        RewriteCond %{SERVER_NAME} =www.paradoxmayhem.com [OR]
        RewriteCond %{SERVER_NAME} =paradoxmayhem.com
        RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,QSA,R=permanent]
</Directory>
Piapiacenza answered 3/9, 2016 at 5:57 Comment(6)
At first glance. it looks like there is nothing .htaccess specific in your rules and they should work fine if you move them out of <Directoiry>Reasoning
Oh. <VirtualHost *:80> obviously has no effect on https:// requests, you have to put the rules (in fact only the first www->non-www rule) in <VirtualHost *:443>Reasoning
Good point, I tried configuring <VirtualHost *:443> (and added my config to the post), but it still won't redirect from https://www.domain.com to https://domain.com.Piapiacenza
Don't ever use 301 while testing or you will be cached and lose track on whether its working as expected or not. Use 302 until u get it right then change to 301. Try clearing your cache and remove rules and check your browser with firebug or some developer tool to ensure its not redirecting, then add the rules 1 by 1, ensure rule 1 is working if so add next one. Confirm everything is wrong than change to 301. If you are configuring directly on the Virtualhost then yes on the 443 u just need to redirect from www to non-www,Corrales
and on the 80 you could simple redirect to https without messing with www/non-wwwCorrales
I've had my cache disabled throughout this entire endeavor. Also, I tried just redirecting 80 to https w/o rewriting www to non-www (see edit), but that resulted in www never being rewritten. It's as if the *:443 config is always ignored...Piapiacenza
P
10

Got it! Apparently, when I used letsencrypt (certbot) to configure SSL, it automatically created another virtual host file (at /etc/apache2/sites-enabled/domain.com-le-ssl.conf), which has its own definition for the domain.com *:443 Virtual Host, and seems to have taken precedence over any of the *:443 configuration I tried to set up before. I added the following code to the -le-ssl.conf file, and now my redirects finally work in all the cases I desired, using 100% Apache Virtual Host configuration:

<Directory /var/www/domain.com/>
        RewriteEngine On

        # match any URL with www and rewrite it to https without the www
        RewriteCond %{HTTP_HOST} ^(www\.)(.*) [NC]
        RewriteRule (.*) https://%2%{REQUEST_URI} [L,R=301]
</Directory>
Piapiacenza answered 3/9, 2016 at 17:57 Comment(1)
ha! I had the most bizarre issue with letsencrypt mucking with the domain.com-le-ssl.conf (it put an entry in for port 80??) which was making ONE SUBDOMAIN ROUTE (out of many sites and domains) hosted on same ip address not be redirected to https. Your issue/answer gave me a hint/nudge in the right direction. Thank you!Lactometer
S
0

Although the OP's accepted answer works, I don't understand some of the choices he made, and it seems that he doesn't understand them either, just played with the syntax until it somehow worked. Most importantly, rewrite rules should apply to requests handled by the virtual host, not the <Directory> directive.

With the proper use of regular expressions, the redirection of www to a non-www domain is quite simple:

Listen for incoming HTTP connections

<VirtualHost *:80>
    ServerName example.com
    ServerAlias www.example.com
    DocumentRoot /var/www/example.com

    RewriteEngine on

    # Redirect both www.example.com and example.com to https://example.com
    RewriteCond %{HTTP_HOST} ^(www\.)?(.*) [NC]
    RewriteRule ^ https://%2%{REQUEST_URI} [L,R=301]
</VirtualHost>

Listen for incoming HTTPS connections

<VirtualHost *:443>
    ServerName example.com
    ServerAlias www.example.com
    DocumentRoot /var/www/example.com

    RewriteEngine on

    # Redirect www.example.com to example.com
    RewriteCond %{HTTP_HOST} ^www\.(.*) [NC]
    RewriteRule ^ https://%1%{REQUEST_URI} [L,R=301]
</VirtualHost>

These virtual host directives only apply to URLs starting with domain.com and www.domain.com because incoming requests must match the ServerName or ServerAlias. This means that any subdomain such as sub.example.com cannot be a successful match.

Sere answered 13/7 at 11:56 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.