Overridable header values (with map?)

classic Classic list List threaded Threaded
3 messages Options
Reply | Threaded
Open this post in threaded view
|

Overridable header values (with map?)

Brandon Mintern
We're using nginx for several different types of servers, but we're trying to unify the configuration to minimize shared code. One stumbling block is headers. For most requests, we want to add a set of standard headers:

# headers.conf:

add_header Cache-Control $cache_control;
add_header X-Robots-Tag $robots_tag always;
add_header X-Frame-Options $frame_options;

add_header X-XSS-Protection "1; mode=block";
add_header X-Content-Type-Options nosniff;
# several more...

Many of the headers are the same for all requests, but the first three are tweaked for specific resources or target servers.

The first approach I took was to define two files:

# header-vars.conf:

# Values for the $cache_control header. By default, we use $one_day.
set $no_cache "max-age=0, no-store, no-cache, must-revalidate";
set $one_day  "public, max-age=86400";
set $one_year "public, max-age=31536000";
set $cache_control $one_day;

# To allow robots, override this variable using `set $robots_tag all;`.
set $robots_tag "noindex, nofollow, nosnippet, noarchive";
set $frame_options "SAMEORIGIN";


...and the headers.conf above. Then, at appropriate contexts (either a server or location block), different servers would include the files as follows:

include header-vars.conf;
include headers.conf;

That would give them all of our defaults. If the specific application or context needs to tweak the caching and robots, it might do something like this:

include header-vars.conf;
set $cache_control $no_cache;
set $robots_tag all;
include headers.conf;


This was fine, but I recently came across an interesting use of map that I thought I could generalize to simplify this pattern. My idea was to do something like:

# header-vars.conf:

map $robots $robots_tag {

    # Disallowed
    default "noindex, nofollow, nosnippet, noarchive";
    off     "noindex, nofollow, nosnippet, noarchive";

    # Allowed
    on      all;
}

map $frames $frame_options {

    # Allow in frames only on from the same origin (URL).
    default "SAMEORIGIN";

    # This isn't a real value, but it will cause the header to be ignored.
    allow   "ALLOW";
}

map $cache $cache_control {

    # no caching
    off     "max-age=0, no-store, no-cache, must-revalidate";

    # one day
    default "public, max-age=86400";
    1d      "public, max-age=86400";

    # one year
    1y      "public, max-age=31536000";
}


I thought this would allow me to include both header-vars.conf and headers.conf in the http block. Then, within the server or location blocks, I wouldn't have to do anything to get the defaults. Or, to tweak robots and caching:

set $cache off;
set $robots on;

Since the variables wouldn't be evaluated till the headers were actually added, I thought this would work well and simplify things a lot. Unfortunately, I was mistaken that I would be able to use an undefined variable in the first position of a map directive (I thought it would just be empty):

unknown "robots" variable

Of course, I can't set a default value for that variable since I'm including header-vars.conf at the http level. I'd rather not need to include defaults in every server (there are many).

Does anyone have any suggestions for how I can better solve this problem?

Thanks!

_______________________________________________
nginx mailing list
[hidden email]
http://mailman.nginx.org/mailman/listinfo/nginx
Reply | Threaded
Open this post in threaded view
|

Re: Overridable header values (with map?)

Maxim Dounin
Hello!

On Thu, Nov 30, 2017 at 12:28:24AM -0500, Brandon Mintern wrote:

[...]

> This was fine, but I recently came across an interesting use of map
> <https://serverfault.com/a/598106/405305> that I thought I could generalize
> to simplify this pattern. My idea was to do something like:
>
> # header-vars.conf:
>
> map $robots $robots_tag {
>
>     # Disallowed
>     default "noindex, nofollow, nosnippet, noarchive";
>     off     "noindex, nofollow, nosnippet, noarchive";
>
>     # Allowed
>     on      all;
> }

[...]

> Unfortunately, I was mistaken that I would be able to use an undefined
> variable in the first position of a map directive (I thought it would just
> be empty):
>
> unknown "robots" variable
>
> Of course, I can't set a default value for that variable since I'm
> including header-vars.conf at the http level. I'd rather not need to
> include defaults in every server (there are many).
>
> Does anyone have any suggestions for how I can better solve this problem?

The error in question will only appear if you don't have the
variable defined at all, that is, it is not used anywhere in your
configuration.  Using it at least somewhere will resolve the
error.  That is, just add something like

    set $robots off;

anywhere in your configuration as appopriate (for example, in the
default server{} block).

Once you will be able to start nginx, you'll start getting
warnings when the variable is used uninitialized, e.g.:

... [warn] ... using uninitialized "robots" variable ...

These warnings can be switched off using the
uninitialized_variable_warn directive, see
http://nginx.org/r/uninitialized_variable_warn.

--
Maxim Dounin
http://mdounin.ru/
_______________________________________________
nginx mailing list
[hidden email]
http://mailman.nginx.org/mailman/listinfo/nginx
Reply | Threaded
Open this post in threaded view
|

Re: Overridable header values (with map?)

Brandon Mintern
On Thu, Nov 30, 2017 at 9:45 AM, Maxim Dounin <[hidden email]> wrote:
Hello!

Hi!

The error in question will only appear if you don't have the
variable defined at all, that is, it is not used anywhere in your
configuration.  Using it at least somewhere will resolve the
error.  That is, just add something like

    set $robots off;

anywhere in your configuration as appopriate (for example, in the
default server{} block).

Once you will be able to start nginx, you'll start getting
warnings when the variable is used uninitialized, e.g.:

... [warn] ... using uninitialized "robots" variable ...

These warnings can be switched off using the
uninitialized_variable_warn directive, see
http://nginx.org/r/uninitialized_variable_warn.

That worked perfectly! Thank you very much!

_______________________________________________
nginx mailing list
[hidden email]
http://mailman.nginx.org/mailman/listinfo/nginx