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;
}