So, here's my conundrum! I have been trying to get Cloudfront to play nicely with my nginx server for the past three days...have read countless StackOverflow posts and blog articles...scoured the interwebs and I am still stuck with issues surrounding cross-domain access policies when it comes to Cloudfront serving fonts. I am going to post my complete setup in hopes that someone with more expertise may help me figure out what is going on. In the future, I hope this post will serve many others facing similar issues. Here goes...
Nginx config:
I have a nginx webserver with the following server block configuration. (...truncated for brevity)
server {
server_name example.com www.example.com;
root /var/www/example.com/html;
index index.html index.htm;
location / {
try_files $uri $uri/ =404;
}
location /assets {
autoindex on;
}
# Media
location ~* \.(jpe?g|gif|png|ico|cur|gz|svgz?|mp4|ogg|ogv|webm|htc|webp)$ {
expires 1M;
access_log off;
add_header Cache-Control public;
}
# Fonts
location ~* \.(eot|ttf|woff|woff2|svg)$ {
expires 365d;
access_log off;
add_header Cache-Control public;
add_header Access-Control-Allow-Origin example.com;
// Have also tried setting the "Access-Control-Allow-Origin" header to "*", but I'd prefer not to do this for security reasons.
}
}
FYI: All of my website files I would like to serve and offload to CloudFront are in the /assets
directory of my virtual host. (ie. http://example.com/assets/..)
CloudFront:
I have created a new CloudFront distribution with the following settings:
Note: I am not using S3 to host my website files and assets.
General:
- Alternate Domain Names (CNAMEs): static.example.com
- Default Root Object: index.html
Origins:
- Origin Domain Name: example.com
- Origin Path: (left blank)
- Origin SSL Protocols: TLSv1.2, TLSv1.1, TLSv1
- Origin Protocol Policy: HTTP Only
- HTTP Port: 80
- HTTPS Port: 443
- Origin Custom Headers: (none)
Behaviors:
- Path Pattern: Default ()*
- Viewer Protocol Policy: HTTP and HTTPS
- Allowed HTTP Methods: GET, HEAD
- Cached HTTP Methods: GET, HEAD (Cached by default)
- Forward Headers: Whitelist
- Access-Control-Allow-Origin
- Object Caching: Use Origin Cache Headers
- Forward Query Strings: No (Improves Caching)
- Compress Objects Automatically: Yes
DNS settings:
A portion of my Zone file...
example.com. 1800 IN A 12.34.567.890 //faked IP here for privacy reasons
www.example.com. 1800 IN CNAME example.com.
static.example.com. 1800 IN CNAME kg72kgf83nhfy3.cloudfront.net. //faked CloudFront dist. domain name here for privacy reasons
What's happening? Why it no- worky?
So, CloudFront does its thing processing and deploying my distribution, and I'm assuming pulling the assets from my '/assets/..' web directory. All src
, href
, and CSS url()
references point to http://static.example.com in my current HTML and CSS documents, including all font-face
references. After the distribution is deployed, I hit my site http://example.com in a browser.
It appears that all static site assets are served correctly from CloudFront w/ appropriate caching headers as defined in my nginx config...EXCEPT...webfonts. I am getting missing fonts on the page and cross-domain access policy error messages in my browser console.
Headers—
An image, for reference (when pinging my server):
curl -I "http://example.com/assets/images/image1.png" HTTP/1.1 200 OK Server: nginx/1.6.3 Date: Sun, 15 May 2016 02:09:25 GMT Content-Type: image/png Content-Length: 194665 Last-Modified: Sun, 15 May 2016 01:52:35 GMT Connection: keep-alive ETag: "5737d663-2f869" Expires: Tue, 14 Jun 2016 02:09:25 GMT Cache-Control: max-age=2592000 Cache-Control: public Accept-Ranges: bytes
A font (when pinging my server):
curl -I "http://example.com/assets/fonts/webfont.woff" HTTP/1.1 200 OK Server: nginx/1.6.3 Date: Sun, 15 May 2016 02:10:29 GMT Content-Type: application/font-woff Content-Length: 8752 Last-Modified: Sun, 15 May 2016 01:51:55 GMT Connection: keep-alive Vary: Accept-Encoding ETag: "5737d63b-2230" Expires: Mon, 15 May 2017 02:10:29 GMT Cache-Control: max-age=31536000 Cache-Control: public Access-Control-Allow-Origin: example.com Accept-Ranges: bytes
Same image (when requesting from CloudFront):
curl -I "http://static.example.com/assets/images/image1.png" HTTP/1.1 200 OK Content-Type: image/png Content-Length: 194665 Connection: keep-alive Server: nginx/1.6.3 Date: Sun, 15 May 2016 02:39:16 GMT Last-Modified: Sun, 15 May 2016 01:52:35 GMT ETag: "5737d663-2f869" Expires: Tue, 14 Jun 2016 02:39:16 GMT Cache-Control: max-age=2592000 Cache-Control: public Accept-Ranges: bytes X-Cache: Miss from cloudfront Via: 1.1 lots_of_random_characters_i_dont_know_if_should_share_here.cloudfront.net (CloudFront) X-Amz-Cf-Id: lSM1plINYENbYycBn424LJ2wdtDhS3CpqAFiDSoxQDEctP_WM09bUQ==
Same font (when requesting from CloudFront):
curl -I "http://static.example.com/assets/fonts/webfont.woff" HTTP/1.1 200 OK Content-Type: application/font-woff Content-Length: 8752 Connection: keep-alive Server: nginx/1.6.3 Date: Sun, 15 May 2016 02:41:00 GMT Last-Modified: Sun, 15 May 2016 01:51:55 GMT ETag: "5737d63b-2230" Expires: Mon, 15 May 2017 02:41:00 GMT Cache-Control: max-age=31536000 Cache-Control: public Access-Control-Allow-Origin: example.com Accept-Ranges: bytes Vary: Accept-Encoding X-Cache: Miss from cloudfront Via: 1.1 lots_of_random_characters_i_dont_know_if_should_share_here.cloudfront.net (CloudFront) X-Amz-Cf-Id: vNfiyurS8pjosofnpLNSrnZuaGFg0V4xIs4ySCm05NKDMZ_PozhuOg==
Loading my website at http://example.com, everything seems to work (ie. images) EXCEPT the webfonts. Checking the browser console outputs the following message for every font:
Font from origin 'http://static.example.com' has been blocked from loading by Cross-Origin Resource Sharing policy: The 'Access-Control-Allow-Origin' header contains the invalid value 'example.com'. Origin 'http://example.com' is therefore not allowed access.
So, anyone have any thoughts?? I would greatly appreciate the help/input. I'm a young web developer just trying to learn.
Thank you! :)
–Kyle
Footnotes:
- One of many blog posts I've followed yet haven't been able to get things working.
- My plan is to append hashed query strings to the end of every file (ie.
//static.example.com/assets/images/image.png?622c6911
) to invalidate the CloudFront cache. This way I do not have to always re-upload new assets with changing names...I can simply control invalidation from the HTML and append a new query string to assets when I want CloudFront to request the latest version of that file from my webserver Origin. - I will eventually be purchasing a SSL certificate for my site, so I would like traffic to support both HTTP and HTTPS requests.