Score:1

Config for different headers for different paths but always end up serving the same file

cu flag

I would like to serve different headers for different locations but fallback to always serving a specific file (if no matching file can be found).

I've also got some global headers that needed to be added to all the requests, though with the caveat that I don't want them added if they've already been added at the location level.

I've got this .template.conf so far:

server {   
   listen   ${PORT};
   # Don't include any local server address info in redirects
   absolute_redirect off;

   index    index.html;

   root ${HTML_SRC};

   include  ${INCLUDE_DIR}/*.conf;
    
   # Serve any matching requested file (CSS, etc.) fallbacking to /index.html
   location / {
      # First try a matching existing file, then just show index.html
      try_files     $uri $uri/ /index.html;
   }
}

The include (in INCLUDE_DIR/headers.conf) is defined as:

# Global headers
add_header  X-FRAME-OPTIONS "DENY"  always;
add_header  Cache-Control   "no-store, must-revalidate" always;
add_header  Report-To   "<global-config>" always;
add_header  Content-Security-Policy "<global-config>" always;

# Location specific paths

# Specific known existing file in /$HTML_SRC/.well-known
location /.well-known/apple-app-site-association$ {
    default_type    application/json;
    # Redirect everything to fallback / location to serve the file
    rewrite .* / last;
}

# Assets
location ~* \.(jpg|jpeg|gif|png|svg|ttf)$ {
    # Redeclare global headers (not inherited)
    add_header  X-FRAME-OPTIONS "DENY"  always;
    add_header  Report-To   "<global-config>" always;
    add_header  Content-Security-Policy "<global-config>" always;
    # Cache assets for a bit longer
    add_header  Cache-Control   "max-age=31557600";
    # Redirect everything to fallback / location to serve any files file
    rewrite .* / last;
}

location = /login {
    # Redeclare global headers (not inherited)
    add_header  X-FRAME-OPTIONS "DENY"  always;
    add_header  Cache-Control   "no-store, must-revalidate" always;
    # Path specific CSP headers
    add_header  Report-To   "<specific-config>" always;
    add_header  Content-Security-Policy "<specific-config>" always;
    # Redirect everything to /
    rewrite .* / last;
}

# All locations with this prefix have these headers
location /some-other-path {
    # Redeclare global headers (not inherited)
    add_header  X-FRAME-OPTIONS "DENY"  always;
    add_header  Cache-Control   "no-store, must-revalidate" always;
    # Path specific CSP headers
    add_header  Report-To   "<other-specific-config>" always;
    add_header  Content-Security-Policy "<other-specific-config>" always;
    # Redirect everything to /
    rewrite .* / last;
}

I realise that any locations with add_header means any top level (in this case in the server in the template) add_headers are not inherited.

The problem with the above is that it just doesn't quite work! The location specific headers aren't always used. I think it's the rewrite that's the issue, but I've also tried try_files (matching the template one) without success. I've also tried having nothing except the extra headers in the location block without no luck. I also think what I'm doing isn't the best approach too...

Note that I've simplified the headers added, the CSP headers are included for example, there are other global headers and other location specific ones. I've also got other paths that need different headers but I think the stuff I've got above can be fixed with a generic solution I can apply to those.

Score:1
jp flag

rewrite...last will cause Nginx to search for a new location to process the request. Only the final location gets to set response headers.

You could process the entire request within the same location block that sets the response headers with rewrite...break or more simply using try_files as follows:

try_files /index.html =404;

Notice that the /index.html term is not last parameter. If it was the last parameter, it would cause Nginx to search for a new location to process the request.


Alternatively, keep all of your add_header statements together, and use a map to set specific values. See this answer.

Rich avatar
cu flag
"Only the final location gets to set response headers." -- ahh this makes things a lot clearer knowing this now, thanks!
Rich avatar
cu flag
`try_files /index.html =404;` but will this still try getting known existing files? does `try_files` implicitly try for existence of a matching file first or is `try_files $uri /index.html =404` needed for that?
Rich avatar
cu flag
"If it was the last parameter, it would cause Nginx to search for a new location to process the request." Also this tiny important gem solves a lot of things too!
Richard Smith avatar
jp flag
`try_files /index.html =404;` is intended to replace your `rewrite .* / last;` where **everything** is redirected to `index.html`. To get existing files and/or directories, you will need to add a `$uri` and/or `$uri/` file term to the `try_files` statement.
mangohost

Post an answer

Most people don’t grasp that asking a lot of questions unlocks learning and improves interpersonal bonding. In Alison’s studies, for example, though people could accurately recall how many questions had been asked in their conversations, they didn’t intuit the link between questions and liking. Across four studies, in which participants were engaged in conversations themselves or read transcripts of others’ conversations, people tended not to realize that question asking would influence—or had influenced—the level of amity between the conversationalists.