Take the 2-minute tour ×
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
1  
Please consider moving the 'accepted answer' to serverfault.com/a/171238/90758. That's the correct one. –  olafure Nov 4 '13 at 16:28
add comment

4 Answers

up vote 157 down vote accepted

Answer

See http://serverfault.com/a/171238/64624 for the correct answer.

RegEx Alternative

The code in the original question is a pitfall. While the following code works, it is another pitfall (regular expressions [regex] should be avoided when possible):

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;

       [....]
}
share|improve this answer
4  
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
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 '13 at 20:06
9  
The code you've given here is the BAD code! –  Michael Hampton Jun 4 '13 at 0:59
7  
According to wiki.nginx.org/Pitfalls#Taxing_Rewrites it should be return 301 https://$server_name$request_uri, not with a rewrite. –  Camil Staps Jun 24 '13 at 10:50
show 6 more comments

I think the best and only way should be using a HTTP 301 Moved Permanently redirect like this:

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

The HTTP 301 301 Moved Permanently redirect is also the most efficient because there is no regex to be evaluated, according to already mentioned pitfails).

If you don't want to change the hostname (and subdomain) 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.

I use listen [::]:80 on my host because i have bindv6only set to false, so it also binds to ipv4 socket. change it to listen 80 if you don't want IPv6 or want to bind elsewhere.

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
2  
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
    
I checked this works great with https and everything - @kmindi I updated my answer with reference to yours - as I think it is the right way and this keeps popping up! Nice work. –  Michael Neale Jun 4 '13 at 0:03
    
When using a domain (non-ip) request, does not work unless I change '[::]:80' to '80'. –  Joseph Lust Nov 17 '13 at 19:58
    
that could be the expected behaviour: trac.nginx.org/nginx/ticket/345. I updated the answer to describe the listen option. –  kmindi Nov 17 '13 at 20:35
add comment

NOTE: The best way to do this was provided by http://serverfault.com/a/401632/3641 - but is repeated here:

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

In the simplest case your host will be fixed to be your service you want to send them to - this will do a 301 redirect to the browser and the browser URL will update accordingly.

Below is the previous answer, which is inefficient due to regex, a simple 301 is great as shown by @kmindi

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
13  
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
2  
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
    
this is the easiest one, but the least secure - this way you allow your server to redirect a user to any page, without checking if it's even allowed to be used on your server. If your server serves mydomain.co, malicious users could still use your server to redirect users to other domains like mydomain.co, such as google.com. –  cab0lt May 30 '13 at 15:32
5  
@cab0lt there is no security issue here. Serving a redirect doesn't present a security risk. If there's access control requirements, those should be checked at the point where the browser requests the new URL. The browser won't gain access simply on the basis of the redirect, nor do they need the redirect to request the new URL. –  mc0e Oct 16 '13 at 3:38
show 4 more comments

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 '13 at 0:53
    
This one is optimal! However, I recommend for some to replace _ with the actual domain, e.g. .domain.com I had two servers, and nginx was accidentally directing one of my servers to the default server. –  Ceane Lamerez Jul 1 '13 at 21:16
add comment

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.