How to force or redirect to SSL in nginx?
Solution 1:
The best way as it described in the official how-to is by using the return
directive:
server {
listen 80;
server_name signup.mysite.com;
return 301 https://$server_name$request_uri;
}
Solution 2:
According to nginx pitfalls, it's slightly better to omit the unnecessary capture, using $request_uri
instead. In that case, append a question mark to prevent nginx from doubling any query args.
server {
listen 80;
server_name signup.mysite.com;
rewrite ^ https://$server_name$request_uri? permanent;
}
Solution 3:
This is the correct and most efficient way if you want to keep it all in one server block:
server {
listen 80;
listen [::]:80;
listen 443 default_server ssl;
server_name www.example.com;
ssl_certificate /path/to/my/cert;
ssl_certificate_key /path/to/my/key;
if ($scheme = http) {
return 301 https://$server_name$request_uri;
}
}
Everything else above, using "rewrite" or "if ssl_protocol" etc is slower and worse.
Here is the same, but even more efficient, by only running the rewrite on the http protocol it avoids having to check the $scheme variable on every request. But seriously, it's such a minor thing that you don't need to separate them.
server {
listen 80;
listen [::]:80;
server_name www.example.com;
return 301 https://$server_name$request_uri;
}
server {
listen 443 default_server ssl;
server_name www.example.com;
ssl_certificate /path/to/my/cert;
ssl_certificate_key /path/to/my/key;
}
Solution 4:
If you are using the new dual HTTP and HTTPS server definition, you can use the following:
server {
listen 80;
listen [::]:80;
listen 443 default ssl;
server_name www.example.com;
ssl_certificate /path/to/my/cert;
ssl_certificate_key /path/to/my/key;
if ($ssl_protocol = "") {
rewrite ^ https://$server_name$request_uri? permanent;
}
}
This appears to work for me and doesn't cause redirect loops.
Edit:
Replaced:
rewrite ^/(.*) https://$server_name/$1 permanent;
with Pratik's rewrite line.
Solution 5:
Yet another variant, that preserves the Host: request header and follows the "GOOD" example on nginx pitfalls:
server {
listen 10.0.0.134:80 default_server;
server_name site1;
server_name site2;
server_name 10.0.0.134;
return 301 https://$host$request_uri;
}
Here are the results. Note that using $server_name
instead of $host
would always redirect to https://site1
.
# curl -Is http://site1/ | grep Location
Location: https://site1/
# curl -Is http://site2/ | grep Location
Location: https://site2/
# curl -Is http://site1/foo/bar | grep Location
Location: https://site1/foo/bar
# curl -Is http://site1/foo/bar?baz=qux | grep Location
Location: https://site1/foo/bar?baz=qux