How to Properly Configure Nginx for @font-face Cross-Origin Font Loading and MIME Types


2 views

When implementing custom fonts via @font-face in CSS, many developers encounter two major hurdles with Nginx:

  1. Correct MIME type configuration for various font formats
  2. Cross-origin resource sharing (CORS) requirements

The first step is ensuring Nginx serves fonts with proper Content-Type headers. While you've correctly added these to mime.types:

application/x-font-ttf                ttf;
font/opentype                         otf;
application/vnd.ms-fontobject         eot;
font/x-woff                           woff;

Modern best practices recommend updating these for newer formats:

font/ttf                              ttf;
font/otf                              otf;
font/woff                             woff;
font/woff2                            woff2;
application/vnd.ms-fontobject         eot;

Modern browsers require CORS headers for font loading from different domains. Your initial approach was correct in principle:

location ~* \\.(eot|ttf|woff|woff2)$ {
    add_header Access-Control-Allow-Origin *;
}

The error you're seeing indicates Nginx can't locate the font files. This typically happens when:

  • The location block overrides the root path
  • The font files are not in the expected directory
  • There's a missing root directive in your server configuration

Here's a complete working solution:

server {
    listen 80;
    server_name static.example.com;
    
    root /var/www/static;
    
    location / {
        try_files $uri $uri/ =404;
    }
    
    location ~* \\.(eot|ttf|woff|woff2)$ {
        add_header Access-Control-Allow-Origin *;
        add_header Access-Control-Allow-Methods GET;
        expires 365d;
        access_log off;
    }
}

For production environments, consider these additional optimizations:

location ~* \\.(eot|ttf|woff|woff2)$ {
    add_header Access-Control-Allow-Origin *;
    add_header Cache-Control "public";
    expires 1y;
    add_header Vary Accept-Encoding;
    gzip_static on;
    gzip_types font/woff2;
}

After making changes, always:

  1. Test configuration syntax: nginx -t
  2. Reload Nginx: nginx -s reload
  3. Verify headers: curl -I https://yourdomain.com/fonts/yourfont.woff2

When implementing custom fonts via @font-face in modern web applications, developers often encounter two critical server configuration requirements:

  1. Correct MIME types for font files
  2. Proper CORS headers for cross-origin loading

Here's a complete solution that addresses both requirements in Nginx:

# In your nginx.conf or site configuration
http {
    include mime.types;
    
    # Extended MIME types for fonts (add to existing mime.types or include separately)
    types {
        font/woff2                      woff2;
        font/woff                       woff;
        font/ttf                        ttf;
        font/otf                        otf;
        application/vnd.ms-fontobject   eot;
    }

    server {
        listen 80;
        server_name yourdomain.com;

        # Font serving location with CORS headers
        location ~* \.(eot|ttf|woff|woff2|otf)$ {
            add_header Access-Control-Allow-Origin *;
            add_header Cache-Control "public, max-age=31536000, immutable";
            try_files $uri $uri/ =404;
        }
    }
}

1. Path Resolution Errors: The error message about missing files typically indicates incorrect path configuration. Ensure your location block either:

  • Specifies an absolute path with root directive
  • Uses alias for custom font directories
location /fonts/ {
    root /path/to/your/webroot;
    # OR use alias for non-standard paths
    # alias /custom/font/path/;
}

2. MIME Type Conflicts: Some systems may have conflicting MIME type definitions. Verify with:

nginx -T | grep mime.types

For production environments, consider these enhancements:

location ~* \.(eot|ttf|woff|woff2|otf)$ {
    add_header Access-Control-Allow-Origin "*";
    add_header Access-Control-Allow-Methods "GET";
    add_header Access-Control-Max-Age "3600";
    add_header Vary "Origin";
    
    # Enable gzip compression for woff2
    gzip_static on;
    gzip_types font/woff2;
    
    # Security headers
    add_header X-Content-Type-Options "nosniff";
    add_header Content-Security-Policy "default-src 'self'";
    
    expires 1y;
    access_log off;
}

Verify your setup with these commands:

# Check MIME types
curl -I https://yourdomain.com/fonts/yourfont.woff2 | grep Content-Type

# Check CORS headers
curl -I -H "Origin: http://test.com" https://yourdomain.com/fonts/yourfont.woff2 | grep Access-Control

Remember to reload Nginx after configuration changes:

sudo nginx -t && sudo systemctl reload nginx