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.

From what I've gathered so far it's clear that running if statements in nginx should be avoided at all costs. Most of the examples I've found so far regarding specific page redirects involve multiple servers being used. But, isn't that a bit wasteful? I'm not sure, but I would think multiple servers to accomplish this would be somewhat slower then a single server when under heavy load.

My current server call is this:

server {
    listen  10.0.0.60:80;
    listen  10.0.0.60:443 default ssl;

    #other code
}

What I want to do is redirect certain http requests to https requests. For example, I want /login/ and /my-account/ to always be forced to use SSL. If you're on /help/ though, I want that served over the default http.

Is there a way to accomplish this within a single server call? Or is there no downside to using 2 server calls to get this working? nginx seems to be under pretty active development and a lot of the older guides I've followed were from times when you couldn't listen to requests for port 80 and 443 within the same server call. But now that nginx has been updated to support that (I'm running 1.2.4), I'm wondering if there's a "best practice" way of handling this today.

Any help would be greatly appreciated.

EDIT:

I did find this guide: http://redant.com.au/blog/manage-ssl-redirection-in-nginx-using-maps-and-save-the-universe/

and I updated my code as follows:

map $uri $my_preferred_proto {
        default "http";
        ~^/#/user/login "https";
}
server {
        listen  10.0.0.60:80; ## listen for ipv4; this line is default and implied
        listen  10.0.0.60:443 default ssl;

        if ($my_preferred_proto = "none") {
                set $my_preferred_proto $scheme;
        }

        if ($my_preferred_proto != $scheme) {
                return 301 $my_preferred_proto://mysite.com$request_uri;
        }

It's not working though. When I change the default to https everything is redirected to SSL so it does somewhat work. But the redirect of /#/user/login is not redirecting to HTTPS. Any ideas? Also, is this a good way to go about this?

share|improve this question
    
why not https everything? if you bother to setup https, then there is not much reason not to just serve everything over https. –  Lie Ryan Dec 12 '12 at 12:39
    
Because a number of the files from the site are served via our API (different server) for normal HTTP requests. 98% of this sites traffic will come from http requests, so serving those files over https limits the load our nginx server can handle as we scale. But we do want our users to be able to log into this site and be forced to use SSL for both logging in and account management. –  Kris Anderson Dec 12 '12 at 12:50

3 Answers 3

IFs are ok if used correctly. In your case you can try configuration block like this (not tested):

location /login {
   if ($scheme != 'https') { 
       return 301 https://$host$url;
    }
 }
share|improve this answer
    
What makes this IF statement better then others? Isn't this going to cause extra processing for every single request? I tried the statement by the way... but I had to change $url to $uri to get nginx working. That said, it's not redirecting to SSL for me. –  Kris Anderson Dec 12 '12 at 13:34
up vote 0 down vote accepted

It turns out I can't redirect this page due to the hash tag # in the URL. Because the hash tag only updates on the client browser side, the server can't see that URL. My original redirect code and Andrei's code (with my modification to the $uri) command also work correctly.

share|improve this answer

If using /login in the location block works for you, then changing the map entry to remove the hash similar to this ~/login "https"; should work as well.

Location blocks directly correlate to $uri maps like the one you used. Matching that works in a location block should work in a $uri mapping as well.

Also – as you realised – you need to match the path that the client requests from the server, not necessarily the same as what the client shows in the location bar.

p.s. – I wrote the guide you are linking to in the original question.

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.