17

I have http:// and https:// on the same host like the following:

server {

    listen   80;
    listen   443 ssl;

    ...
    ...
}

What I need to do is redirecting users who access my shop to https://. The problem is I have many languages:

  • https://example.com/en/shop
  • https://example.com/fr/shop
  • etc...

I tried this and it didn't work (nginx: configuration file /etc/nginx/nginx.conf test failed):

if ($server_port = 80) {
    location (en|fr)/shop {
        rewrite ^ https://$host$request_uri permanent;
    }
}
Stephen Ostermiller
  • 23,933
  • 14
  • 88
  • 109
Adam
  • 2,948
  • 10
  • 43
  • 74

5 Answers5

47

It would also be more of an Nginx best practice to do a 301 redirect instead of using the if statement (see Server name on http://wiki.nginx.org/Pitfalls). I created a gist with an nginx.conf configured for SSL, Rails and Unicorn

https://gist.github.com/Austio/6399964

Here would be the relevant section for yours.

server {
    listen      80;
    server_name example.com;
    return 301  https://$host$request_uri;
}
Stephen Ostermiller
  • 23,933
  • 14
  • 88
  • 109
Austio
  • 5,939
  • 20
  • 34
11

Or better yet, avoiding the hardcoded server name

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

In order to use regular expressions for matching locations, you need to prefix the expression with either ~ or ~*:

if ($server_port = 80) {
    location ~ (en|fr)/shop {
        rewrite ^ https://$host$request_uri permanent;
    }
}

From the documentation:

To use regular expressions, you must use a prefix:

  1. "~" for case sensitive matching
  2. "~*" for case insensitive matching

Since nginx does't allow location blocks to be nested inside of if blocks, try the following configuration:

if ($server_port = 80) {
    rewrite ^/(en|fr)/shop https://$host$request_uri permanent;
}
Community
  • 1
  • 1
  • I got another error with your code: Restarting nginx: nginx: [emerg] "location" directive is not allowed here in – Adam Aug 30 '13 at 00:51
  • 2
    @AdamSilver: You cannot have `location` inside of an `if` block (see location's documentation). Simply change you rewrite rule to only rewrite if the path starts with `(en|fr)/shop`. –  Aug 30 '13 at 00:54
  • But I'll get a redirect loop! – Adam Aug 30 '13 at 00:58
  • @AdamSilver: You shouldn't. You keep your `if`, but only nest a `rewrite` inside of it. –  Aug 30 '13 at 01:00
2

Ideally, avoiding if statements while preserving the trailing path:

server {
  listen 80;
  server_name example.com;
  rewrite (.*) https://example.com$1 permanent;
}

permanent takes care of the 301.

Ben at Qbox.io
  • 413
  • 3
  • 4
2

another way with error_page 497

server {
    listen 80;
    listen 443;

    ssl on;
    error_page 497  https://$host$request_uri;
    ssl_certificate     /etc/ssl/certs/ssl-cert-snakeoil.pem;
    ssl_certificate_key /etc/ssl/private/ssl-cert-snakeoil.key;
...
okocian
  • 488
  • 4
  • 11