nginx add header conditional on an upstream_http_ variable

I have a reverse proxy on nginx which proxies quite a few sites. I have recently enabled HTTP Strict Transport Security for all SSL-enabled websites. I now have one site that doesn't want to have this enabled.

I thought I would just do a simple check if my upstream already sent me a Strict-Transport-Security-header, and if not, just add one. That way, my upstream could send an STS header containing max-age=0 to avoid having HSTS enabled by the proxy.

I thought I'd just change my configuration as follows:

location / {
        proxy_pass http://webservers;

        proxy_redirect off;

        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $remote_addr;
        proxy_set_header X-Forwarded-Proto "https";

        if ($upstream_http_strict_transport_security = "") {
                add_header Strict-Transport-Security "max-age=15552000";
        }
}

But, probably because if is evil, this doesn't work. I have tried a bunch of different things to make sure the variable actually exists (which is the case), but nothing seems to help.

How could I make this work?


Solution 1:

This doesn't work because the if is evaluated before the request is passed to the backend, so the $upstream_http_ variables don't have any values yet. add_header with an empty value is ignored, so you can use a map to conditionally add the header like so:

map $upstream_http_strict_transport_security $sts {
  '' max-age=15552000;
}

server {
  location / {
    add_header Strict-Transport-Security $sts;
  }
}

Solution 2:

That's because if is executed before proxy take place and at this moment there is no variable $upstream_http_strict_transport_security.

You could use header_filter_by_lua directive from Lua module. E.g.

header_filter_by_lua 'if not ngx.header["X-Test"] then ngx.header["X-Test"] = "blah" end';