Nginx – How to work around the fact that the nginx alias directive isn’t allowed in named location blocks

nginx

My goal is to cache assets with query strings with a certain policy and assets that don't have query strings with another. Unfortunately, nginx ignores query strings in location blocks, so I'm stuck using the if/error_page strategy helpfully suggested here:

location /static/ {
    alias /home/client/public/;
    error_page 418 = @long_lived_caching_strategy;

    if ($query_string = "example=querystring") {
      return 418;
    }
  }

  location @long_lived_caching_strategy {
    etag off;
    add_header Cache-Control "public";
    expires 1y;
  }
}

However, my error logs show me that in the above configuration, the alias directive is ignored. But when I try to move the alias directive into the @long_lived_caching_strategy, nginx tells me that alias isn't allowed there!

What are my options for a workaround?

Alternatively, is there another way to set etag and add_header directives differently depending on whether the URL has a query string?

Best Answer

I found an easier solution to my problem thanks to this thread. My goal was really to conditionally add caching-related headers based on whether or not there was a query string, and using if to set strings turned out to be the easiest way to achieve that. Here's my final configuration:

  location /static {
    alias /usr/local/etc/nginx/relative-paths/picasso/client/public;

    # If an asset has a query string, it's probably using that query string for cache busting purposes.
    set $long_lived_caching_strategy 0;
    if ($query_string) { set $long_lived_caching_strategy 1; }

    if ($long_lived_caching_strategy = 0) {
      # Cache strategy: caches can store this but must revalidate the content with the server using ETags before serving a 304 Not Modified.
      set $cache_control "no-cache";
    }

    if ($long_lived_caching_strategy = 1) {
      # Cache strategy: proxy caches can store this content, and it's valid for a long time.
      set $cache_control "public, max-age=86400, s-maxage=86400";  # 1 day in seconds
    }

    add_header Cache-Control $cache_control;

    # Some types of assets, even when requested with query params, are probably not going to change and should be cacheable by anyone for a long time.
    location ~* \.(?:jpg|jpeg|gif|png|ico|cur|gz|svg|svgz|mp4|ogg|ogv|webm|htc|ttf)$ {
      add_header Cache-Control "public max-age=86400, s-maxage=86400";
      etag off;
      access_log off;
    }
  }