Correct way in new versions of nginx
Turn out my first answer to this question was correct at certain time, but it turned into another pitfall - to stay up to date please check Taxing rewrite pitfalls
I have been corrected by many SE users, so the credit goes to them, but more importantly, here is the correct code:
server {
listen 80;
server_name my.domain.com;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl;
server_name my.domain.com;
# add Strict-Transport-Security to prevent man in the middle attacks
add_header Strict-Transport-Security "max-age=31536000" always;
[....]
}
First a couple points that are probably the same for you
- I was trying to update a certificate because it has expired.
- I have multiple domains bound to the same IP. They happen to be a SAN certificate but that's probably irrelevant.
- I was trying to use the centralized certificate store. Again I think this is irrelevant to most of my answer.
- I had already attempted to update the certificate but it wasn't showing the new date.
- You're probably in a panic right now if your old certificate already expired. Take a deep breath...
First I'd recommend strongly going to https://www.digicert.com/help/
and downloading their DigiCert tool. You can also use it online.
Enter in your website https://example.com
and it will show you the expiration date and thumbprint (what MS calls the certificate hash). It does a realtime lookup so you don't have to worry whether or not your browser (or intermediate server) is caching something.
If you're using the centralized certificate store you'll want to be 100% sure the .pfx file is the latest version so go to your store directory and run this command:
C:\WEBSITES\SSL> certutil -dump www.example.com.pfx
This will show you the expiration date and hash/thumbprint. Obviously if this expiration date is wrong you probaly just exported the wrong certifcate to the filesystem so go and fix that first.
If you are using the CCS then assuming this certutil command gives you the expected expiration date (of your updated certificate) you can proceed.
Run the command:
netsh http show sslcert > c:\temp\certlog.txt
notepad c:\temp\certlog.txt
You likely have a lot of stuff in here so it's easier to open it up in a text editor.
You'll want to search this file for the WRONG hash that you got from digicert.com
(or the thumbprint you got fromChrome).
For me this yielded the following. You'll see it is bound to an IP and not my expected domain name. This is the problem. It seems that this (for whatever reason I'm not sure) takes precedence over the binding set in IIS that I just updated for example.com
.
IP:port : 10.0.0.1:443
Certificate Hash : d4a17e3b57e48c1166f18394a819edf770459ac8
Application ID : {4dc3e181-e14b-4a21-b022-59fc669b0914}
Certificate Store Name : My
Verify Client Certificate Revocation : Enabled
Verify Revocation Using Cached Client Certificate Only : Disabled
Usage Check : Enabled
Revocation Freshness Time : 0
URL Retrieval Timeout : 0
Ctl Identifier : (null)
Ctl Store Name : (null)
DS Mapper Usage : Disabled
Negotiate Client Certificate : Disabled
I don't even know where this binding came from - I don't even have any SSL bindings on my default site but this server is a few years old and I think something just got corrupted and stuck.
So you'll want to delete it.
To be on the safe side you'll want to run the following comand first to be sure you're only deleting this one item:
C:\Windows\system32>netsh http show sslcert ipport=10.0.0.1:443
SSL Certificate bindings:
-------------------------
IP:port : 10.0.0.1:443
Certificate Hash : d4a17e3b57e48c1166f18394a819edf770459ac8
Application ID : {4dc3e181-e14b-4a21-b022-59fc669b0914}
Certificate Store Name : My
Verify Client Certificate Revocation : Enabled
Verify Revocation Using Cached Client Certificate Only : Disabled
Usage Check : Enabled
Revocation Freshness Time : 0
URL Retrieval Timeout : 0
Ctl Identifier : (null)
Ctl Store Name : (null)
DS Mapper Usage : Disabled
Negotiate Client Certificate : Disabled
Now we've verified this is the 'bad' thumbprint, and expected single record we can delete it with this command:
C:\Windows\system32>netsh http delete sslcert ipport=10.0.0.1:443
SSL Certificate successfully deleted
Hopefully if you now go back to Digicert and re-run the command it will give you the expected certificate thumbprint. You should check all SAN names if you have any just to be sure.
Probably want to IISRESET here to be sure no surprises later.
Final note: If you're using the centralized certificate store and you're seeing erratic behavior trying to even determine if it is picking up your certificate from there or not don't worry - it's not your fault. It seems to sometimes pick up new files immediately, but cache old ones. Opening and resaving the SSL binding after making any kind of change seems to reset it but not 100% of the time.
Good luck :-)
Best Answer
The first thing to be aware of is that modern web browsers may not be the best tool for debugging problems such as these. The browser may even be the cause of them as the server can be configured completely correctly and the issue can be 100% client side.
Contents:
curl
and incognito/anonymous browser)curl
does, but the private browser window does not display the correct contenttesting
Try to not only test with the FQDN
http://sub.example.com
but use a more complete URL such ashttp://sub.example.com/some-page.html
. When you know that you're behind a proxy, adding additional parameters will usually by-pass cached contents i.e. add and increment a counter such ashttp://sub.example.com/some-page.html?test=3
test from a "Private/Incognito" browser window.
That reduces the odds of drawing incorrect conclusions based on cached objects.
test from a command line (on a test server) with for example
curl -vv http://sub.example.com/some-page.html
or usetelnet
and emulate a web request withtelnet sub.example.com 80
GET /some-page.html HTTP/1.1
Host: sub.example.com
Things to look for in the
curl
output:Proxy settings are definitely a danger sign and a real hinderance when debugging server issues. Proxy servers can cache (DNS records and web content), restrict your access and even replace TLS certificates.
Test from (test) system that does not rely on a proxy server if you want to properly test the configuration of an internet web server. I usually don't have test systems that will support a fully fledged browser, but I can usually manage a system that will run curl commands from a command line.
There you observe that a connection gets successfully established to the correct IP-address and port of the web server. The > marker precedes the request headers made by curl.
The server response headers are marked with a < marker and then after an empty line the response body is sent by the server:
After the first protocol header
HTTP/1.1
comes the HTTP status code the server generates. There a2xx
response means some form of success,3xx
responses are redirects (seen here),4xx
and5xx
are errors.Of the other headers the server sends the
Location:
in this example indicates the target of a redirect response.both tests display the expected content
Conclusion: The web server is configured correctly and the issue is browser related.
The most likely cause: there may have been a permanent redirect configured before the web server configuration was changed and permanent redirects (301) are cached by browsers. Fairly common are cached broken redirects or cached redirects to https and no certificate and https site for
sub.example.com
is configured yet.Resolution 1: Clear the browser cache and the site should load as expected.
Resolution 2: Get a SSL certificate for sub.example.com and enable TLS.
Cause 2: Not quite the same root cause, but effectively similar cause and effect to a cached redirect to https, a HTTP Strict Transport Security (HSTS) policy that is set by the
example.com
domain is also applicable for all (new) subdomains of example.com. Any reasonably modern browser stores and honours HSTS policies and will refuse to connect over plain http to port 80 and will silently rewrite thehttp://sub.example.com
URL tohttps://sub.example.com
and attempt to connect to port 443 with TLS.Resolution: get a SSL certificate for sub.example.com and enable TLS.
Clearing the HSTS browser cache can work temporarily but that is only effective when you also remove the include subdomains HSTS policy from example.com, which is not recommended.
curl
does, but the private browser window does not display the correct contentConclusion: The web server is configured correctly and the issue is browser or client related.
Cause 1: Not quite the same root cause, but effectively similar cause and effect to a cached HTTP Strict Transport Security (HSTS) policy is a domain on the HSTS pre-load list. But where cached HSTS policies should not be honoured in a "Private/Incognito" windows, the HSTS pre-load list should always apply, even in private/incognito windows.
See this Q&A for an overview on how to determine if either your domain or your TLD is on the HSTS pre-load list:
List of top-level domains (TLDs) that require HTTPS connections, like .dev
Resolution: get a SSL certificate for sub.example.com and enable TLS.
Cause 2: although the DNS records are configured correctly, the client resolver, the desktop where your browser runs, may point to a different IP-address. Check with for example
nslookup
anddig
what the client name server resolves and that do not forget that a hosts file entry for sub.example.com will override DNS.Resolution: remove the hosts file entry for sub.example.com, or investigate the DNS discrepancy further.
neither test displays the expected content
Conclusion: The issue is server-side, not client-side.
No response
Refer to What causes the 'Connection Refused' message? when it appears that the web server does not respond at all on port 80.
Redirect response
When the web server does respond, take closer look that response:
This is a fairly typical response for a web server that is configured to redirect plain HTTP to HTTPS.
The
302 Found
status code in the first header is indicative of a temporary redirect. For a permanent redirect that would be a301 Moved Permanently
http status header.The
Location:
header show where the client is redirect to.Cause: when not defined in the web server configuration it is very common for web applications to generate redirects to either https, or a different domain altogether.
On Apache web servers (that allow them) a
.htaccess
file can also be the source of a redirect.Resolution: adjust or remove the redirect, or ensure that the redirect becomes valid and something responds on the target of the redirect.
Frequently: get that SSL certificate and enable TLS!
Cause: often the target of the redirect is broken, check for subtle typo's there as well, I have seen missing
/
's to redirect tosub.example.comsome-page.html
and incorrectly used parameters redirecting tohttp://some-page.html
, orhttp://wwww.example.com/http://sub.example.com/some-page.html
and similar.Also test for loops by making a request to the
Location:
multiple levels of redirects usually indicate a broken configuration as well and remove the loop.Content from different site
When you see content from a different site that you host and not the content for
sub.example.com
be aware that most web servers will display the content from a default site when they can't match a hostname to a specific site.Resolution: Re-check your configuration for typo's and confirm that the web server has been restarted with the updated configuration.