I am trying to figure out what the optimal configuration is for my virtual host files, but I'm having some issues with it.
Currently I have 2 domains: domain1.com and domain2.com
I have 1 server at IP 000.000.000.001 which actually hosts all the needed files. In these files you have an API (api.domain1.com) and the actual website.
domain1.com is using the nameservers of Digital Ocean and uses the following DNS records:
A @ 000.000.000.001
CNAME * domain1.com.
For SEO purposes I want to redirect all requests which are not being made to the api subdomain to forward to www.domain1.com.
However, I also ONLY want users to be able to browse my site (and API) through a SSL connection, I don't want users being able to use it through HTTP so I try to redirect all those requests to use HTTPS. The certificates are provided by LetsEncrypt!. Their automated install made changes to my virtual hosts files and currently I have 4 of them:
-
api.domain1.com.conf
<VirtualHost *:80> ServerName api.domain1.com DocumentRoot /var/www/api.domain1.com/web RewriteEngine on RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [L,QSA,R=permanent] </VirtualHost>
-
api.domain1.com-le-ssl.conf
<IfModule mod_ssl.c> <VirtualHost *:443> ServerName api.domain1.com DocumentRoot /var/www/api.domain1.com/web ExpiresActive On /* ... */ <Directory /var/www/api.domain1.com/web> AllowOverride None Order Allow,Deny Allow from All <IfModule mod_rewrite.c> Options -MultiViews RewriteEngine On RewriteCond %{REQUEST_FILENAME} !-f RewriteRule ^(.*)$ app.php [QSA,L] </IfModule> </Directory> ErrorLog ${APACHE_LOG_DIR}/error.log CustomLog ${APACHE_LOG_DIR}/access.log combined SSLCertificateFile /etc/letsencrypt/live/domain1.com/cert.pem SSLCertificateKeyFile /etc/letsencrypt/live/domain1.com/privkey.pem Include /etc/letsencrypt/options-ssl-apache.conf SSLCertificateChainFile /etc/letsencrypt/live/domain1.com/chain.pem </VirtualHost> </IfModule>
-
domain1.com.conf
<VirtualHost *:80> ServerName domain1.com Redirect 301 / https://www.domain1.com </VirtualHost>
-
domain1.com-le-ssl.conf
<IfModule mod_ssl.c> <VirtualHost *:443> ServerName www.domain1.com DocumentRoot /var/www/domain1.com ExpiresActive On /* ... */ RewriteEngine On RewriteCond %{HTTP_HOST} ^https://domain1.com RewriteRule ^/(.*)$ https://www.domain1.com/$1 [L,R=301] ErrorLog ${APACHE_LOG_DIR}/error.log CustomLog ${APACHE_LOG_DIR}/access.log combined ErrorDocument 404 /404.html SSLCertificateFile /etc/letsencrypt/live/domain1.com/cert.pem SSLCertificateKeyFile /etc/letsencrypt/live/domain1.com/privkey.pem Include /etc/letsencrypt/options-ssl-apache.conf SSLCertificateChainFile /etc/letsencrypt/live/domain1.com/chain.pem </VirtualHost> </IfModule>
When I try to visit the site, the following things happen:
http://test.domain1.com --> https://test.domain1.com FAIL
http://domain1.com --> https://www.domain1.com SUCCESS
http://www.domain1.com --> https://www.domain1.com SUCCESS
https://domain1.com --> https://domain1.com FAIL
https://www.domain1.com --> https://www.domain1.com SUCCESS
As you can see, the first and fourth entry fails. They both return a 404 Not Found to my visitors which is unacceptable to me. The first one even shows a SSL warning (I don't think that LetsEncrypt! supports wildcards so I think this warning cannot be prevented?)
What is causing my test. not redirecting to www.?
What is causing my fourth entry to end up serving a 404?
Now I also want my second domain (domain2.com) to point to this server/files. This domain is hosted at a different location (I got it from a friend) and is using different nameservers. I cannot simply change the nameservers (I think?) because this second domain has email hosting linked to it which uses the nameservers of this other provider. Momentarily, this domain also has its own web server (but this will go away in the future) hosted at 000.000.000.002. Right now, it uses a
<meta http-equiv="refresh" content="0; url=https://www.domain1.com" />
tag in its index.html file to redirect to the right server, in the future this will have to be done in the DNS records though.
How should I do this?
So to summarise:
- I thought the CNAME * is a catch-all for all subdomains?
- What did I do wrong in the virtual hosts file? Something is causing that fourth redirect to fail.
- How should I handle my second domain pointing at my first IP?
- Is there another way to only allow HTTPS connections? (This should also be forced on the API virtual host). I've heard of HSTS, should I implement this?
Some SEO tests also pointed out that I need a IP redirect to further improve my SEO results. They give this as an example:
RewriteCond %{HTTP_HOST} ^000\.000\.000\.001
RewriteRule (.*) http://www.domain1.com/$1 [R=301,L]
Should I also implement this for SEO purposes? Should I also implement this for my other IP address?
So many questions…
Of course, if you have any other suggestions, please share your opinion!
Best Answer
Lots of questions there! Let's try to work through them:
Not sure what you are asking here, and not an expert in CNAMES but would have thought you'd need '*.domain1.com' at least instead of just '*'
For both you fails you do not explicitly note your alternative server names in either ServerName nor ServerAlias. In this case it will default to the first server found in the config. Is this the api.domain.com one? If so that might explain the 404 as the SERVER_NAME will (by default) be the client supplied one so the api.domain1.com:80 settings will just redirect to the https version of what they sent (which is what appears to be happening), which will then also look at the api.domain1.com:443 config and not find the name. You would need to either add the alternative names to ServerAlias setting of your main domain1.com config, or move that config to be first so it becomes the default and the api one is only used when the api.domain1.com name is explicitly used.
As you appear to want to redirect this straight to your new site I would update the DNS to point to your new IP address, to save you paying for two servers (in terms of money and time to administer). This can be done on the existing DNS nameserver to keep the e-mail though obviously would be nicer to consolidate on one. In the meantime implement a proper 301 redirect in the server config as the meta redirect is not as strong a signal to search engines and you do seem to care about SEO.
The main way is to redirect http to https. HSTS is primarily a security feature which automatically redirects http to https before the browser makes the request. This is useful as the default is http (e.g. typing www.example.com in the browser address bar will, by default, send you to http://www.example.com rather than https://www.example.com), and this can be intercepted to prevent an upgrade to https (which is more difficult to then intercept). It has some downsides though: Not all browsers support it, you need to visit the website at least once to load the HSTS setting (though some browsers allow pre-loading of this), and the setting will expire if the site is not visited in the maxAge time (again assuming it's not preloaded). So it should not be used as a replacement to redirects but more as an enforcement of it for browsers that support HSTS. Blogged about it here if you want to read more on HSTS.
I would also say you have several different methods of redirecting (api:80 has Rewrite, domain1:80 has Redirect, domain1:443 has Rewrite - but with a very restrictive and incorrect RewriteCond). Personally I prefer to use one method as it's less confusing but that's a personal matter (Redirect is also slightly faster but Rewrite gives you more power so I prefer that one). So I tend to have config like this:
and then for the 443 I would have this:
Note that I've added different log files for each vhost so it's more obvious which vhost is being hit.
Note also that I redirect anything which is not www.domain1.com rather than your version which only redirected if people typed domain1.com (and which I'm not sure would be used as suspect api.domain1.com config came first).
This will also take care of anyone accessing your website by IP address, or any other name as it will always be redirect to your real www.domain1.com server name. This is easy for http requests, but for https requests they may indeed get a cert error if your cert does not include the servername used.
LetsEncrypt do not support wildcards, but they do allow multiple names on a cert so you can easily get a cert for domain1.com and www.domain1.com and you should as this is generally considered best practice. You could also add any other domains you think might be used. For you api.domain1.com domain you could also add to this same cert, or get a separate cert for that since you have separate config for that (your config above is not clear on which you are doing for that since it looks like same config but not sure if that's a typo or not).
For SEO purposes it is indeed best to only serve your site under one URL and use redirects to enforce that URL and above config will do this. This is to prevent Google thinking you have duplicate content if you server the same content under www.domain1.com/page1.html and https://www.domain1.com/page1.html and https://domain1.com/page1.html and http://000.000.000.001/page1.html ...etc.
A lot covered there but hopefully points you in the right direction.