19

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?

23

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;
  }
}
| improve this answer | |
  • 1
    Clever use of map! – Alexey Ten May 23 '14 at 18:20
  • ok i've been trying to do something little different but i couldn't figure nginx out. Can you tell me where can i learn nginx formally. And also can you help me here: serverfault.com/questions/678521/… – Muhammad Umer Mar 26 '15 at 18:34
  • Note that this doesn't work if you have any other directives setting the same header—nginx only passes through the original header if it's not being overridden anywhere. If you encounter this, you can add default ''; to your map, e.g. map $upstream_http_strict_transport_security $sts { '' max-age=15552000; default ''; } – Matt Browne Jul 8 at 21:26
6

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';
| improve this answer | |
  • 1
    This works. On Debian 7 you can get LUA support by using Nginx from backports via apt-get -t wheezy-backports install nginx-extras. – Pieter Ennes Apr 10 '15 at 9:38

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.