5

I'm trying to get Nginx to rewrite incoming requests to a site my server prefixed with https:// to http:// (this is because a CMS used on this site forces URIs instead of relative paths -- essentially breaking the whole site by making images, scripts, and stylesheets unavailable).

I'm currently trying to retrofit an existing directive put in place by a predecessor, but I find myself limited by my knowledge of Nginx config syntax. Here's the code:

if ($ssl_protocol = "") {
    rewrite ^   https://$http_host$request_uri? permanent;
}

I've current commented this code out to prevent forcible rewrites of http:// to https://, but I can't reverse the process without breaking the site. Here's what I've tried so far:

if ($ssl_protocol = "https") {
    rewrite ^   http://$http_host$request_uri? permanent;
}

and

# also tried ($ssl_protocol != "")
if (!($ssl_protocol = "")) {
    rewrite ^   http://$http_host$request_uri? permanent;
}

The first one doesn't seem to have an effect. The HTML sent to the client still makes HTTPS requests that aren't being rewritten.

The second snippet doesn't appear to have any effect either - if I understand correctly (although I'm still somewhat surprised), Nginx doesn't support boolean negation.

What would be the best way (or a working way) to do this?

EDIT: I've tried adding the code from @NathanC's answer; however, this unconditional rewrite causes a redirect loop. Help is still appreciated.

user3620306
  • 53
  • 1
  • 1
  • 4

2 Answers2

7

The cleaner, way would be:

if ( $scheme = "https" ) {
    return 301 http://example.com$request_uri

or somewhere between that and Nathans answer, where your default ssl server block contains simply the return 301 (whichever ssl block it is, you'll have to take a close look at yours to see how its implemented and adapt) No point in doing regex for a simple redirect

return - http://nginx.org/en/docs/http/ngx_http_rewrite_module.html#return

edit: i just noticed there is a variable $https that can be used in the if statement instead. Returns " " if not https:

if ( $https = "on" ) {
    ...

Keep in mind, while testing changes, you should use a 302 temporary redirect instead of 301 permanent, to save hair-pulling when you discover you fixed it an hour earlier but the changes didn't reflect in your browser :)

pete
  • 723
  • 1
  • 7
  • 16
  • Thanks, this seems to work! I'm still hitting an issue with an `ERR_INSECURE_RESPONSE` happening when the resources are being requested using `https` but returned over `http`, but that should be a relatively simple fix. – user3620306 May 09 '14 at 14:16
  • it may require stepping back and finding the root of why there are https requests in the code when you don't want them, otherwise i believe that would continue to be an issue for embedded resources... – pete May 09 '14 at 14:18
  • It was part of the Drupal site configuration, actually. The site's set to `https://mysite.com`. – user3620306 May 09 '14 at 14:27
  • 2
    +1 for "Keep in mind" paragraph :) – Oleg Aug 18 '15 at 08:39
0

You don't even need this since you can just force all https traffic to go http like so:

server {
        listen 443;
        ssl on;
        server_name example.com;
        rewrite ^(.*) http://example.com$1 permanent;
 }

Reference: https://stackoverflow.com/questions/3470290/nginx-redirect-https-to-http

Nathan C
  • 15,059
  • 4
  • 43
  • 62
  • Put this in my `nginx.conf`, but I'm getting *unknown directive: "server" in *`/etc/nginx/nginx.conf:5`. – user3620306 May 09 '14 at 13:01
  • I got it to work - sort of. Using your code, the page enters a redirect loop. – user3620306 May 09 '14 at 13:24
  • Do you have a redirect from http to https anywhere on the site? This code's a bit of a "hammer" in that it redirects *all* https on the specified domain. – Nathan C May 09 '14 at 14:27
  • @pete's answer solved the redirect loop issue - as he explained, in his code, the redirect occurs iff the requested URL/URI starts with an `https://` scheme. – user3620306 May 09 '14 at 14:55
  • nginx: [emerg] no "ssl_certificate" is defined for the "ssl" directive in /etc/nginx/sites-enabled/FILE:32 – Case Nov 14 '17 at 21:15