I have an nginx 1.6.2 server running as a backend behind a load balancer that does SSL termination. All communication to the backend servers goes over HTTP.

Diagram of what's going on:

          /--http---> frontend:80  --\
client --+                            +--http---> backend:8000
          \--https--> frontend:443 --/

                      LOAD BALANCER                BACKENDS

For testing purposes I only have one backend at the moment. The load balancer runs HAProxy 1.5, which I have some control over.

I have a pretty typical try_files directive in my server block in the backend nginx config:

server {
    server_name frontend;
    try_files $uri $uri/ =404;

Now, by default, when I access a directory without a trailing slash, e.g. https://frontend/somedir, nginx wants to send an HTTP 301 redirect to an absolute URL like http://frontend:8000/somedir/.

I can make nginx omit the 8000 port number using port_in_redirect off.

However I can't seem to correct the http:// scheme at the beginning of the redirect nginx is generating. The best I can get nginx to do is a redirect from https://frontend/somedir to http://frontend/somedir/, effectively stripping SSL!

The load balancer is sending an X-Forwarded-Proto header but I do not see any way for nginx to consult it when crafting its redirect; in fact there is a 2012 answer saying nginx outright cannot do this, and the solution is to replace the load balancer with nginx. IMHO this is too trivial a thing to warrant such a drastic stack change.

Has anything changed since 2012 here? I don't really want to rewrite these redirects at the HAProxy level: actual intentional HTTPS to HTTP redirects from the web application might get "re-HTTPSed" if I just always rewrite the scheme for the Location: response header to be the same as the scheme the request was made with.


Here is a minimized config showing nginx produces absolute Location: URLs. Note there are no rewrites.

user nobody nobody;
worker_processes auto;
worker_rlimit_nofile 4096;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;

events {
    worker_connections 1024;
    multi_accept on;

http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;

    # TODO: Tune fastcgi_buffers/other buffers

    # Configure keepalive connections
    keepalive_timeout 15;
    keepalive_requests 1000;

    # Hide server version.
    server_tokens off;

    # Do not allow any directory indexes anywhere.
    # This is the default, but it is here for extra paranoia.
    autoindex off;

    # gzip text content.
    gzip on;
    gzip_vary on;
    gzip_disable "msie6";
    gzip_comp_level 2;
    gzip_min_length 1024;
    gzip_types  text/css

    server {
        listen 8000 default_server;

        root /usr/share/nginx/html;
        index index.html index.htm;

        server_name localhost;

        location / {
            try_files $uri $uri/ =404;

And if you use curl to view the headers -- note I have created a directory testdir under /usr/share/nginx/html:

[myuser@dev nginx]$ curl -i http://localhost:8000/testdir
HTTP/1.1 301 Moved Permanently
Server: nginx
Date: Thu, 26 Mar 2015 14:35:49 GMT
Content-Type: text/html
Content-Length: 178
Location: http://localhost:8000/testdir/
Connection: keep-alive

<head><title>301 Moved Permanently</title></head>
<body bgcolor="white">
<center><h1>301 Moved Permanently</h1></center>
  • nginx wants to send an HTTP 301 redirect to an absolute URL - nginx doesn't do that unless you have an explicit rewrite rule to do so - please show your full config.
    – AD7six
    Mar 26, 2015 at 8:27
  • I added the config, trimmed down to just illustrate this issue. I don't do any explicit rewrites.
    – mutron
    Mar 26, 2015 at 14:38
  • 1
    You should configure your balancer to replace protocol in Location: header since nginx has no idea what was original protocol.
    – Alexey Ten
    Mar 30, 2015 at 6:47
  • 2
    @AlexeyTen would you like to post that as an answer so I can approve it? I have not found a way to do this in nginx either, so a change at the load balancer does indeed appears to be the only way.
    – mutron
    Apr 16, 2015 at 3:49
  • 1
    This is still a bug with the latest nginX release! Does anybody know if there is a bug report already? Could not find one. May 17, 2018 at 14:29

2 Answers 2


Fast forward to 2019 and you can:

absolute_redirect off; 
port_in_redirect off;

From docs for absolute_redirect:

If disabled, redirects issued by nginx will be relative.


You need to tell the load balancer to rewrite http to https in the requests like so:

proxy_redirect http:// $scheme://;

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .