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;
[....]
}
Your configuration script is not buggy.
With your current configuration (assuming that you have a standard single subject SSL Certificate installed), this is not an option.
The reason for this is the way https connections work:
When a client (the browser), issues a https request to the server (nginx), it initiates an SSL session by way of an SSL handshake. When, and only when, the handshake succeeds and the session is established, the browser sends the actual HTTP request containing the hostname. Since SSL/TLS is not only a way to provide encryption for data connections, but also a way for the server to authenticate itself to the client. As part of the authentication process, the browser validates the identity of the server. One of the validation checks is to match the certificate subject name with the hostname that the browser intends to request content from. If this validation fails, the browser issues a warning to the user.
Since the validation process fails, the server never receives the HTTP request for www.mydomain.com on the port 443 listener, and thus cannot send a redirect response to the client/browser.
To enable redirection from https://www.mydomain.com/ to https://mydomain.com, you have a few options, but it all comes down to this: you need a certificate with a subject for each hostname.
SAN Certificate
- Obtain a UC/SAN Certificate, and have www.mydomain.com added as a SAN (Subject Alternate Name)
- The subject(s) now match requests for both
mydomain.com
and www.mydomain.com
Multiple IP addresses
- Obtain another IP address for your server.
- Obtain an SSL certificate with the subject name
www.mydomain.com
- Configure the
www.mydomain.com
https server
to listen on the new IP address (still port 443)
- Configure the
www.mydomain.com
https server
to use the new certificate
- Update the A record for www.mydomain.com to point at the new IP address in your public DNS zone
TLS SNI
- Like in the above example, obtain an SSL certificate with the subject name
www.mydomain.com
- Instead of using another IP address, take advantage the Server Name Indication TLS Extension.
Since SNI has limited browser support, I would avoid suggestion 3. Check out the nginx documentation on SNI if you like (bottom of the page)
UPDATE: Some Certificate Authorities offer single subject certificates with a free additional SAN for the www.
prefix.
Best Answer
It will be too late. Users will have already seen the error message and had to accept it by the time the redirect happens unless you get another certificate. The previous answer has that problem.
Ignoring that, you can create a named based virtual host on port 443, set up ssl on that, and then have it rewrite. Note that instead of using your existing certificate (which will generate an error) you can have a cheap, valid certificate under mysite.com on that virtual host so that you don't get an error prior to the redirect.