Home > Software engineering >  How do I stop the rewrite to force https from affecting all the subdomains
How do I stop the rewrite to force https from affecting all the subdomains

Time:10-18

I have this rule to switch all http connections to https. Edited to show the whole file

RewriteEngine on
RewriteCond %{HTTP_HOST} ^www\.example\.kiwi$ [OR]
RewriteCond %{HTTP_HOST} ^example\.nz$ [OR]
RewriteCond %{HTTP_HOST} ^www\.example\.nz$
RewriteRule ^/?$ "https\:\/\/example\.kiwi\/$1" [R=301,L]
RewriteCond %{HTTP_HOST} ^example\.app$ [OR]
RewriteCond %{HTTP_HOST} ^www\.example\.app$
RewriteRule ^/?$ "https\:\/\/example\.kiwi\/$1" [R=301,L]
RewriteCond %{HTTP_HOST} ^example\.online$ [OR]
RewriteCond %{HTTP_HOST} ^www\.example\.online$
RewriteRule ^/?$ "https\:\/\/example\.kiwi\/$1" [R=301,L]
RewriteCond %{HTTP_HOST} ^example\.software$ [OR]
RewriteCond %{HTTP_HOST} ^www\.example\.software$
RewriteRule ^/?$ "https\:\/\/example\.kiwi\/$1" [R=301,L]

RewriteCond %{HTTPS} !=on
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301,NE]
Header always set Content-Security-Policy "upgrade-insecure-requests;"
Header always setifempty Strict-Transport-Security "max-age=31536000" env=HTTPS
Header append X-Frame-Options: "SAMEORIGIN"

Unfortunately it affects things like mail.domain.com (and others). How do I stop any/all subdomains from being upgraded ?

CodePudding user response:

Assuming you only want to redirect the www subdomain and the domain apex to HTTPS then you can check the Host header in a RewriteCond directive.

For example:

RewriteCond %{HTTP_HOST} ^(www\.)?example\.com [NC]
RewriteCond %{HTTPS} !=on 
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301,NE]

The above will only redirect www.example.com or example.com.

I've removed the capturing group in the RewriteRule pattern (ie ^(.*)$) since it's not being used here.

Test with a 302 (temporary) redirect to avoid caching issues.

You will need to clear your browser cache before testing.

Also consider canonicalising the hostname (www vs non-www) in the redirect also.

Header always set Content-Security-Policy "upgrade-insecure-requests;"

However, since not everything is now HTTPS, if you are loading resources from the subdomains over HTTP then this header should be sent conditionally, based on whether the request was over HTTPS to begin with.

For example, on Apache 2.4.10 you can use Apache expression syntax in the Header directive:

Header always set Content-Security-Policy "upgrade-insecure-requests;" "expr=%{HTTPS} == 'on'"

UPDATE:

I want different suffixes to work such as example.software and example.app, so should I replace the ".com" with ".?"

You could simply remove the TLD in the regex in the first condition. For example:

RewriteCond %{HTTP_HOST} ^(www\.)?example\. [NC]

This will now match example.com, example.software, www.example.app etc. But it will fail if you happen to have a subdomain the same name as the domain itself (eg. example.example.com) - but that should be avoided.

I have edited the post to show my whole file, in case there are side-effects. I have a number of domains that are all being redirected for the moment while the website is getting constructed.

This doesn't affect the HTTP to HTTPS redirect. These directives redirect all the other domains to https://example.kiwi - so when these directives are processed the later HTTP to HTTPS redirect is bypassed (not required) anyway.

However, there are a couple of issues with these redirects.

  • "redirected for the moment" - You imply that these redirects are temporary, but you are using a 301 (permanent) response. This results in the redirect being cached persistently, which can be impossible to undo. If this is temporary then it should be a 302 (temporary) redirect.
  • ^/?$ - You are only redirecting requests for the document root (ie. the homepage). A request for example.nz/foo will not be redirected. This further looks like an error because you are using a $1 backreference in the substitution string, which will consequently always be empty.

These redirect directives could also be greatly simplified. If you are "temporarily" redirecting all other domains to https://example.kiwi/<url> then you could do it with a single rule like this instead:

RewriteCond %{HTTP_HOST} !=example.kiwi
RewriteRule ^ https://example.kiwi%{REQUEST_URI} [R=302,L]

Where !=example.kiwi is a negated exact match string comparison (not a regex). The condition is successful then the Host header does not match example.kiwi.


Aside:

Header always setifempty Strict-Transport-Security "max-age=31536000" env=HTTPS

You shouldn't be implementing HSTS whilst still in development and changing domains. However, you don't appear to be setting an HTTPS env var in the code you have posted, so this is likely being ignored anyway. (?)

NB: env=HTTPS is not checking the server variable of the same name.

  • Related