5

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?

2
  • 1
    10 exact matches is good solution. Just put them in separate file and include it – Alexey Ten Oct 16 '17 at 17:38
  • @AlexeyTen I would still prefer not to resort to using this. Let's see if an alternative is proposed. – Majid Fouladpour Oct 16 '17 at 18:16
3

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.

9
  • I did a quick test and it seems to work ok. – Tim Oct 16 '17 at 18:50
  • By including, do you mean to have a separate config file linked to in sites-enabled? If not, how would one include a file in a config? – Majid Fouladpour Oct 16 '17 at 18:55
  • Using the Nginx Include directive. I have an nginx.conf that includes a separate file for each website I host. Each file has four server blocks, to account for the http/https and www/non-www domains. Those servers include other files as required, such as one that sets security headers like STS. If you only have one server that serves content just put this into that file. – Tim Oct 16 '17 at 18:59
  • 1
    location ^/(?:favicon|apple-touch-icon|android-chrome-|mstile-|safari-pinned-tab.svg|browserconfig.xml)$ would be a more refined one, with start and end anchors and then a non-capturing group with alternate matching strings. – Tero Kilkanen Oct 17 '17 at 17:02
  • 1
    I can only get @TeroKilkanen's version to work with an added ~* to indicate use a regexp rather than just prefix location ~* ^/(?:favicon|apple-touch-icon|android-chrome-|mstile-|safari-pinned-tab.svg|browserconfig.xml|mainfest.json) I also had to drop the trailing $ to allow favicon-16x16.png to work. – Mat Jan 25 '19 at 0:59
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;
    }

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.