When setting up multiple websites on Nginx, developers often encounter favicon.ico issues that seem simple but can be tricky. The favicon (short for "favorites icon") appears in browser tabs and bookmarks, and while modern browsers will automatically look for it at the root, there are several implementation details worth considering.
Here's a typical Nginx virtual host configuration that should serve favicon.ico automatically when placed in the document root:
server {
listen 80;
server_name example.com www.example.com;
root /var/www/example.com;
# Default files to serve
index index.html;
}
With this setup, when you place favicon.ico in /var/www/example.com/
, browsers should find it. However, there are several reasons why this might not work as expected.
1. File Permissions
As mentioned in the original post, permission issues are a frequent culprit. The web server needs read access to the favicon file:
chmod 644 /var/www/example.com/favicon.ico
chown www-data:www-data /var/www/example.com/favicon.ico
2. Cache Issues
Browsers aggressively cache favicons. If you've changed your favicon but don't see updates, try:
- Hard refresh (Ctrl+F5 or Cmd+Shift+R)
- Adding a query string like favicon.ico?v=2
- Clearing browser cache completely
3. Explicit Location Block
For more control, you can explicitly define a location block:
server {
...
location = /favicon.ico {
alias /var/www/example.com/favicon.ico;
access_log off;
log_not_found off;
expires 30d;
}
}
Multiple Favicons for Different Devices
Modern websites often use multiple icon formats. Here's how to serve them:
# Serve different favicon formats
location ~* ^/(favicon\.ico|apple-touch-icon.*\.png|android-chrome.*\.png)$ {
root /var/www/example.com/assets/icons;
access_log off;
log_not_found off;
expires max;
}
Favicon for Subdomains
If you want different favicons for subdomains:
server {
listen 80;
server_name admin.example.com;
root /var/www/admin.example.com;
location = /favicon.ico {
alias /var/www/admin.example.com/favicon-admin.ico;
}
}
When your favicon isn't showing up:
- Check Nginx error logs:
tail -f /var/log/nginx/error.log
- Verify file permissions and ownership
- Test direct access:
curl -I http://example.com/favicon.ico
- Ensure proper MIME type is being served
Remember that while favicons seem simple, they're an important part of your site's identity and user experience. Taking the time to implement them properly pays off in professional polish.
When setting up multiple websites on Nginx, each virtual host typically requires its own favicon.ico file. The browser automatically looks for this file in the root directory of each domain, but proper configuration ensures consistent delivery.
For a standard setup where favicon.ico resides in your document root:
server {
listen 80;
server_name website.com www.website.com;
root /home/webuser/sites/website;
# Default handling (optional)
location = /favicon.ico {
log_not_found off;
access_log off;
}
}
For environments with multiple sites, each with distinct favicons:
# Primary website
server {
listen 80;
server_name site1.com;
root /var/www/site1;
location = /favicon.ico {
alias /var/www/site1/assets/favicon.ico;
expires max;
access_log off;
}
}
# Secondary website
server {
listen 80;
server_name site2.com;
root /var/www/site2;
location = /favicon.ico {
alias /var/www/site2/images/custom-fav.ico;
expires 30d;
log_not_found off;
}
}
1. Permission Issues - Ensure the favicon file has proper read permissions:
chmod 644 /path/to/favicon.ico
chown www-data:www-data /path/to/favicon.ico
2. Caching Problems - Force browser cache refresh by either:
- Renaming the favicon file
- Adding query parameters (favicon.ico?v=2)
- Using expires directive in Nginx config
3. Multiple Location Blocks - Avoid conflicts by being specific:
location = /favicon.ico {
# Exact match only
}
For high-traffic sites, consider these enhancements:
location = /favicon.ico {
alias /path/to/favicon.ico;
expires 1y;
add_header Cache-Control "public";
access_log off;
log_not_found off;
etag off;
if_modified_since off;
}
For dynamic favicon generation or CDN hosting:
location = /favicon.ico {
proxy_pass http://cdn.example.com/favicons/$host.ico;
proxy_cache favicon_cache;
proxy_cache_valid 200 30d;
}
After configuration changes:
- Test Nginx configuration:
nginx -t
- Reload Nginx:
systemctl reload nginx
- Verify with curl:
curl -I http://yoursite.com/favicon.ico
Remember to check browser developer tools (Network tab) to verify proper loading and caching headers.