Tell me more ×
Server Fault is a question and answer site for professional system and network administrators. It's 100% free, no registration required.

I want to rewrite all http requests on my web server to be https requests, I started with the following:

server {
    listen      80;

    location / {
      rewrite     ^(.*)   https://mysite.com$1 permanent;
    }
...


One Problem is that this strips away any subdomain information (e.g., node1.mysite.com/folder), how could I rewrite the above to reroute everything to https and maintain the sub-domain?

share|improve this question

5 Answers

up vote 112 down vote accepted

The mothod you guys are using is actually one of the nginx pitfalls:

http://wiki.nginx.org/Pitfalls#Taxing_Rewrites

The correct code would be:

server {
       listen         80;
       server_name    my.domain.com;
       rewrite        ^ https://$server_name$request_uri? permanent;
}

server {
       listen         443;
       server_name    my.domain.com;

       ssl            on;

       [....]
}

I know it is a small change, but I thought it was useful to add.

share|improve this answer
3  
Nice one - yes this is a good answer. – Michael Neale Mar 7 '12 at 1:52
2  
This should be the correct answer. – Rune Kaagaard Apr 4 '12 at 8:55
2  
You would have to do this on a domain by domain basis however - no? What if you wanted to apply it to every domain on your server? – JM4 Aug 15 '12 at 23:57
This seems all to work very well. But then, what will happen to the POST parameters? Body/Headers? Anybody got some inputs on this? – nembleton Aug 18 '12 at 10:46
3  
@JM4: if you use $host$ in the rewrite instead of server_name and add default_server to the listen directive it will work for every domain on your server. – Klaas van Schelven Jan 5 at 20:06
show 4 more comments

I have been using nginx 0.8.39 and above, and used the following:

 server {
       listen 80;
       rewrite ^(.*) https://$host$1 permanent;
 }

Sends a permanent redirect to the client.

share|improve this answer
1  
You should also have "443" on the listen line. – gWaldo Dec 6 '11 at 20:51
12  
I think it should be 80 - as this is listening for http and then telling the client to come back as https (443). – Michael Neale Dec 8 '11 at 22:30
1  
This should be the top answer! – Nathan Aug 31 '12 at 22:52
3  
This is the most taxing answer. – Iscariot Nov 21 '12 at 7:36

I think the best way should be this (according to already mentioned pitfails http://wiki.nginx.org/Pitfalls#Taxing_Rewrites):

server {
    listen         [::]:80;
    return 301 https://$host$request_uri;
}

If you dont want to change the hostname this is the way.

This does still work if you have no dns, as I am using it locally. I am requesting for example with http://192.168.0.100/index.php and will get redirected to exactly https://192.168.0.100/index.php. Thats what I want.

The solution from Saif Bechan uses the server_name which in my case is localhost but that is not reachable over a network.

The solution from Michael Neale is good but according to the pitfails, there is a better solution with redirect 301 ;)

share|improve this answer
Nice you try to quote it, but 301 does not work on HTTPS. – Iscariot Nov 21 '12 at 7:34
what does not work? the stated server section is for non-encrypted http (without s) traffic to be permanently redirected to encrypted server (that section that listens on 443 (https) is not listed) – kmindi Nov 21 '12 at 13:05

The above didn't work for with with new subdomains being created all the time. e.g. AAA.example.com BBB.example.com for about 30 subdomains.

Finally got a config working with the following:

server {
  listen 80;
  server_name _;
  rewrite ^ https://$host$request_uri? permanent;
}
server {
  listen  443;
  server_name example.com;
  ssl on;
  ssl_certificate /etc/ssl/certs/myssl.crt;
  ssl_certificate_key /etc/ssl/private/myssl.key;
  ssl_prefer_server_ciphers       on;
# ...
# rest of config here
# ...
}
share|improve this answer
thank you! nginx would either return 301 https://*/ or cancel the request prematurely in the other answers here. server_name _; with $host was the answer that did the trick. +1 – zamnuts Mar 13 at 0:53
server {
    listen         [::]:80;
    return 301 https://$host$request_uri;
}

It only worked for me since I have a similar requirement (no change in hostname).

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.