Serving Static Content from a Cookieless Domain
Serving static content from a cookieless domain is a standard performance best practice, one you’ve surely encountered if you’ve used a performance analysis tool like YSlow or Page Speed. The concept is simple—don’t serve static content like images and stylesheets from a domain that sets cookies—but exactly how to achieve this might not be clear to everyone. And for beginners, both the concept and the execution can be slightly confusing. So here is a brief explanation of the idea, followed by a few options for implementing it.
The trouble with cookies
From a performance perspective, the trouble with cookies is that once the server sets a cookie for a particular domain, all subsequent HTTP requests for that domain must include the cookie. Even if the server has no use for the cookie, as is usually the case with static components, the cookie is sent over the wire anyway, bloating our request headers with useless code.
Of course, cookies are typically very small. In a lot of cases an extra 300 bytes per request may be insignificant. The negative performance effect is lessened further if you’ve implemented other performance best practices, such as using sprites and concatenated files to reduce HTTP requests, or using Expires and Cache-Control headers to limit the number of trips to the server.
But remember that this extra weight, however small, is added to every request. Even requests for cached components that rely on the Last-Modified header. If your site has a large number of page components and/or heavy cookies, optimizing your site to deliver static assets from a cookieless domain may be well worth the effort.
So how do we do it? Remember that when the server sets a cookie, that cookie is attached to all future requests to the same domain (and often all subdomains as well). To get around this we simply need to request our static assets from a different domain.
I’ve emphasized the word “request”to highlight the fact that it’s only the request that matters. The static content does not need to “live” at another location; it only needs to be accessible from a different domain.
Using a CNAME
The easiest way to set up a cookieless domain for your static content is to create a CNAME record aliasing your static domain to your main domain. Your static files remain in the same place but you can now reference them at a different domain.
You can serve your static content from a subdomain (static.example.com), or you can serve it from a separate domain (www.static-example.com). If you choose to serve it from a subdomain there are a few steps you will need to take to ensure that cookies are not set on your static subdomain (see the next section).
When you create the CNAME record you want to enter your static domain/subdomain as the “label”, “name”, or “alias” and your A record domain as the “content” or “value”. (The CNAME term, which stands for “Canonical Name”, actually refers to the domain you are mapping to, not the alias. The common practice of referring to the alias as the “CNAME” is in fact backwards.)
Once you’ve set up the alias you’ll need to modify all the references to your static files to point to the new domain.
<img src="/img/animated-unicorn.gif" alt="" /> <!-- Becomes --> <img src="http://static.example.com/img/animated-unicorn.gif" alt="" /> <!-- or --> <img src="http://www.static-example.com/img/animated-unicorn.gif" alt="" />
Now, as long as you only reference files on the static domain that do not set cookies, a cookie should never be set for your static domain and all of your future requests for static content be sent cookie-free. Woot sound.
Separate domain or subdomain?
In order to set up a cookieless subdomain you have to make sure that your server or application only sets cookies for www.example.com and not the top-level example.com. (Cookies set at the top-level domain apply to all subdomains as well.) How you go about this of course depends on your particular set-up. But two common cookie-setters are Google Analytics and WordPress.
For Google Analytics, you have to set the “_setDomainName” value to your www domain. Like this:
_gaq.push( ['_setAccount', 'UA-xxxxxxx-1'], ['_setDomainName', 'www.example.com'], ['_trackPageview'] );
For WordPress, open up wp-config.php and add this line:
Obviously, this only works in situations where you don’t need to set cookies on other subdomains. To avoid this restriction, use a separate domain name.
An interesting solution for creating a cookie-free domain without having to register a second domain is 2static.it. They set up an alias to your main domain, allowing you to request your static files from http://somename.2static.it.
As far as I know, there are no downsides to using a separate domain. And it appears to be the most popular option. The only potential drawback I can think of is the possibility that Google might disassociate your images from your domain. But this is just speculation.
Speaking of SEO, you might be wondering if there is a duplicate content penalty for mirroring your entire site. The short answer is “not really”. I recommend watching this video where Google’s Greg Grothaus explains the myth of the duplicate content penalty. If you’re still concerned, you could always 301 redirect all requests for anything other than static files to your principal domain.
Using a CDN
If you offload your static content to a CDN or a file storage service like Amazon S3, keeping the static file requests cookie-free should be easy as long as you haven’t set up a CNAME record on a subdomain that receives cookies from your top-level domain. Remember it’s all about the domain that the request is made to and making sure nothing on that domain sets any cookies. Whether the files are hosted on Amazon’s servers or yours is unimportant.
A bonus benefit to serving static content from a cookieless domain is that you can double the number of page components that browsers can download in parallel. But realize that this works best when the components are balanced across two domains. If 95% of your assets are static files and if you move all of them to static.example.com, you aren’t really taking advantage of maximizing parallel connections. You’re just incurring the extra DNS look-up. (See this previous post about some light testing I did on domain sharding.)