Nginx match for favicon related files

Favicons have become more and more unruly. To cater for all browsers/platforms I am using this excellent service. What I get is the following files:

android-chrome-192x192.png  favicon-16x16.png  mstile-150x150.png
android-chrome-512x512.png  favicon-32x32.png  safari-pinned-tab.svg
apple-touch-icon.png        favicon.ico
browserconfig.xml           manifest.json

The recommended path for these is the web root as some browsers do not honor custom paths. I really don't want to have such a mess in my web root. So, I am looking for a location configuration to place them all in their dedicated directory while letting the clients think they are in the web root.

I have seen exact match rules like this:

location = /favicon.ico {
  root /var/www/path/to/favicons;
}

But 10 exact match locations just for these files is not a very good solution. What else can I do?


Solution 1:

Try this - it's a case insensitive regular expression match for anything containing the substring favicon, plus tests for most of the other expressions. I've put in two exact matches because there's a chance the URLs could be used in an application. If "favicon" is used in the application it will cause problems.

 # Better option below for this line
 location ~* favicon|apple-touch-icon|android-chrome-|mstile-|safari-pinned-tab.svg|browserconfig.xml {
  root /var/www/path/to/favicons;
}
location = /browserconfig.xml {
  root /var/www/path/to/favicons;
}
location = /manifest.json {
  root /var/www/path/to/favicons;
}

I've run a quick test and this seems to work.

Tero Kilkanen offers this location, which would be a better match. It matches starting at the root directory only and has a non-capturing group.

location ~* ^/(?:favicon|apple-touch-icon|android-chrome-|mstile-|safari-pinned-tab.svg|browserconfig.xml|mainfest.json)

However, I would probably just put all the location block matches into a file and include it. I assume exact matches are a touch faster, and my Nginx config files can get up to 500 lines anyway.

Solution 2:

I see many errors in my logfile, for clients try to access :

https://my.server.com/some/location/document.html/apple-touch-icon.png

so why not to give them what they want ?

here the config that works for that :

# non capturing group is ok here, but a $ at the end would be simply wrong
# this is deliberately not limited to the root directory, because 
# clients look at all places for especially for apple-touch-icon
#
# so we match here : 
#    https://my.server.com/apple-touch-icon*,
#    https://my.server.com/*...*/apple-touch-icon*
# and rewrite to /var/www/path/to/favicons/apple-touch-icon*
#
# on the rewrite we NEED a capturing group !

location ~* /(?:favicon|apple-touch-icon|android-chrome-|mstile-|safari-pinned-tab.svg) {
      rewrite ^.*/(favicon|apple-touch-icon|android-chrome-|mstile-|safari-pinned-tab.svg)(.*)$  /$1$2 break; 
      root /var/www/path/to/favicons;
    }

    # this should be only found in the root
    location = /browserconfig.xml {
      root /var/www/path/to/favicons;
    }

    # this should be only found in the root
    location = /manifest.json {
      root /var/www/path/to/favicons;
    }