Here's my abbreviated nginx vhost conf:

upstream gunicorn {
    server fail_timeout=0;

server {
    listen 80;
    listen 443 ssl;
    server_name domain.com ~^.+\.domain\.com$;

    location / {
        try_files $uri @proxy;

    location @proxy {
        proxy_pass_header Server;
        proxy_redirect off;
        proxy_set_header Host $http_host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto https;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Scheme $scheme;
        proxy_connect_timeout 10;
        proxy_read_timeout 120;
        proxy_pass http://gunicorn;

The same server needs to serve both HTTP and HTTPS, however, when the upstream issues a redirect (for instance, after a form is processed), all HTTPS requests are redirected to HTTP. The only thing I have found that will correct this issue is changing proxy_redirect to the following:

proxy_redirect http:// https://;

That works wonderfully for requests coming from HTTPS, but if a redirect is issued over HTTP it also redirects that to HTTPS, which is a problem.

Out of desperation, I tried:

if ($scheme = 'https') {
    proxy_redirect http:// https://;

But nginx complains that proxy_redirect isn't allowed here.

The only other option I can think of is to define the two servers separately and set proxy_redirect only on the SSL one, but then I would have duplicate the rest of the conf (there's a lot in the server directive that I omitted for simplicity sake). I know I could also use an include directive to factor out the redundancy, but I really want to keep just one conf file without any dependencies.

So, first, is there something I'm missing that will negate the problem entirely? Or, second, if not, is there any other way (besides including an external file) to factor out the redundant config information so that I can separate out the HTTP and HTTPS versions of the server config?

2 Answers 2


Well, I got a bit of inspiration and tried:

proxy_redirect http:// $scheme://;

Which seems to do the trick. This still seems hacky to me, though, so I still welcome any guidance on anything I might be doing wrong or less hacky ways to achieve the same result.


The other solution is to indicate to the upstream whether the request is HTTP or HTTPS and have it issue the according redirect. Adding this in the nginx config would set a header for the upstream to inspect.

proxy_set_header    X-Scheme $scheme;
  • Ah, I see now that you already have that configuration.
    – mgorven
    Mar 23, 2012 at 23:03
  • Yep. But I appreciate the attempt to help, nonetheless. Mar 26, 2012 at 15:48
  • 4
    This seems to be some triky header. I think X-Forwarded-Proto is better
    – vladkras
    Jan 25, 2018 at 14:20

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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