Stopping cookies being set from a domain (aka "cookieless domain") to increase site performance
Asked Answered
M

4

24

I was reading in Google's documentation about improving site speed. One of their recommendations is serving static content (images, css, js, etc.) from a "cookieless domain":

Static content, such as images, JS and CSS files, don't need to be accompanied by cookies, as there is no user interaction with these resources. You can decrease request latency by serving static resources from a domain that doesn't serve cookies.

Google then says that the best way to do this is to buy a new domain and set it to point to your current one:

To reserve a cookieless domain for serving static content, register a new domain name and configure your DNS database with a CNAME record that points the new domain to your existing domain A record. Configure your web server to serve static resources from the new domain, and do not allow any cookies to be set anywhere on this domain. In your web pages, reference the domain name in the URLs for the static resources.

This is pretty straight forward stuff, except for the bit where it says to "configure your web server to serve static resources from the new domain, and do not allow any cookies to be set anywhere on this domain". From what I've read, there's no setting in IIS that allows you to say "serve static resources", so how do I prevent ASP.NET from setting cookies on this new domain?

At present, even if I'm just requesting a .jpg from the new domain, it sets a cookie on my browser, even though our application's cookies are set to our old domain. For example, ASP.NET sets an ".ASPXANONYMOUS" cookie that (as far as I'm aware) we're not telling it to do.

Apologies if this is a real newb question, I'm new at this!

Thanks.

Mingrelian answered 17/6, 2010 at 10:23 Comment(0)
R
17

If you don't write cookies from domain, the domain will be cookie-less.

When the domain is set to host only resource content like scripts, images, etc., they are requested by plain HTTP-GET requests from browsers. These contents should be served as-is. This will make your domain cookieless. This cannot be done by web-server configuration. Http is completely state-less and web-servers have no idea about the cookies at all. Cookies are written or sent to clients via server-side scripts. The best you can do is disable asp.net, classic-asp or php script capabilities on the IIS application.

The way we do it is.

We have a sub-domain setup to serve cookie-less resources. So we host all our images and scripts on the sub-domain. and from the primary application we just point the resource by it's url. We make sure sub-domain remains cookie-free by not serving any dynamic script on that domain or by creating any asp.net or php sessions.

http://cf.mydomain.com/resources/images/*.images
http://cf.mydomain.com/resources/scripts/*.scripts
http://cf.mydomain.com/resources/styles/*.styles

from primary domain we just refer a resource as following.

<img src="http://cf.mydomain.com/resources/images/logo.png" />
Reddish answered 17/6, 2010 at 10:39 Comment(13)
Thanks for your answer, but as previously stated, we've done exactly the same as you and we're getting cookies set by ASP.NET, not our application. For example, "ASPXANONYMOUS".Mingrelian
Are you serving your resources from any HttpHandler or do you have global.asax file in your cookie-less domain ?Reddish
I'd suggest to clear all cookies from the browser. put only few image resources on the domain and try calling it from an html page. I'm sure it will be cookie-free.Reddish
I've cleared all my cookies (from both domains), and requested nothing but a single .jpg from the "static" domain. I still get the ASPXANONYMOUS cookie set in my browser.Mingrelian
I can't help but feel I'm doing something very obviously wrong :-/Mingrelian
Also make sure, you have create a separate domain altogether and not have a virtual-directory application under primary domain.Reddish
When you say "domain", do you mean "site"? Should I create a new site in IIS and have it pointing to the same directory as our normal site? At present I have the alternative "static" domain binded in IIS to the existing site.Mingrelian
Ok, I did what I suggested (what I thought you were suggesting) and it worked! Still got some weird bugs to iron out, I think, but definitely getting there.Mingrelian
I think the trick (in our case) was to make sure that it was set up as a new site in IIS, and not just "binded" to an existed one.Mingrelian
Exactly, it has to be a seperate domain that a browser can differentiate. The browser does not know about IIS sites and v.dirs.Reddish
The other important thing is to make sure that your App Pool for your Static domain is set to "No managed code". Otherwise you'll be served with the annoying ASPXANONYMOUS cookie.Mingrelian
I don't think so. We didn't do anything such. AppPool is a concept on server-side and Http or browsers don't have anything to do with this. How do you have cookie-less domains on non-IIS web-servers ? The only way cookie-less domains are achieved is by making sure no single cookie ever is written from the domain and that is why you keep a seperate domain that acts cookie-less because your primary domain would always have to deal with cookies in some ways.Reddish
As I say, if you don't set the AppPool for your Static domain to "No managed code" you'll be served with an ASPXANONYMOUS cookie.Mingrelian
M
25

This is how I've done in my website:

  1. Setup a website on IIS with an ASP.NET application pool
  2. Set the binding host to your.domain.com
    • Note: you cannot use domain.com or else the sub-domain will not be cookieless
  3. Create a folder on the website called Static
  4. Setup another website, point it to Static folder created earlier.
  5. Set the binding host to static.domain.com
  6. Use an application pool with unmanaged code
  7. On the settings open Session State and check Not enabled.

Now you have a static website. To setup open the web.config file under Static folder and replace with this one:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
  <system.web>
    <sessionState mode="Off" />
    <pages enableSessionState="false" validateRequest="false" />
    <roleManager>
      <providers>
        <remove name="AspNetWindowsTokenRoleProvider" />
      </providers>
    </roleManager>
  </system.web>
  <system.webServer>
    <staticContent>
      <clientCache cacheControlMode="UseMaxAge" cacheControlMaxAge="30.00:00:00" />
    </staticContent>
    <httpProtocol>
      <customHeaders>
        <remove name="X-Powered-By" />
      </customHeaders>
    </httpProtocol>
  </system.webServer>
</configuration>

This is going to cache the files for 30 days, remove a RoleManager (I don't know if it changes anything but I removed all I could find), and remove an item from Response Headers.

But here is a problem, your content will be cached even when a new version is deployed, so to avoid this I made an helper method for MVC. Basically you have to append some QueryString that will change every time you change these files.

default.css?v=1   ?v=2  ...

My MVC method gets the last write date and appends on the file url:

public static string GetContent(this UrlHelper url, string link)
{
    link = link.ToLower();

    // last write date ticks to hex
    var cacheBreaker = Convert.ToString(File.GetLastWriteTimeUtc(url.RequestContext.HttpContext.Request.MapPath(link)).Ticks, 16);

    // static folder is in the website folders, but instead of
    // www.domain.com/static/default.css I convert to
    // static.domain.com/default.css
    if (link.StartsWith("~/static", StringComparison.InvariantCultureIgnoreCase))
    {
        var host = url.RequestContext.HttpContext.Request.Url.Host;
        host = String.Format("static.{0}", host.Substring(host.IndexOf('.') + 1));

        link = String.Format("http://{0}/{1}", host, link.Substring(9));

        // returns the file URL in static domain
        return String.Format("{0}?v={1}", link, cacheBreaker);
    }

    // returns file url in normal domain
    return String.Format("{0}?v={1}", url.Content(link), cacheBreaker);
}

And to use it (MVC3 Razor):

<link href="@Url.GetContent("~/static/default.css")" rel="stylesheet" type="text/css" />

If you are using another kind of application you can do the same, make a method that to append HtmlLink on the page.

Marchall answered 30/1, 2011 at 15:41 Comment(0)
R
17

If you don't write cookies from domain, the domain will be cookie-less.

When the domain is set to host only resource content like scripts, images, etc., they are requested by plain HTTP-GET requests from browsers. These contents should be served as-is. This will make your domain cookieless. This cannot be done by web-server configuration. Http is completely state-less and web-servers have no idea about the cookies at all. Cookies are written or sent to clients via server-side scripts. The best you can do is disable asp.net, classic-asp or php script capabilities on the IIS application.

The way we do it is.

We have a sub-domain setup to serve cookie-less resources. So we host all our images and scripts on the sub-domain. and from the primary application we just point the resource by it's url. We make sure sub-domain remains cookie-free by not serving any dynamic script on that domain or by creating any asp.net or php sessions.

http://cf.mydomain.com/resources/images/*.images
http://cf.mydomain.com/resources/scripts/*.scripts
http://cf.mydomain.com/resources/styles/*.styles

from primary domain we just refer a resource as following.

<img src="http://cf.mydomain.com/resources/images/logo.png" />
Reddish answered 17/6, 2010 at 10:39 Comment(13)
Thanks for your answer, but as previously stated, we've done exactly the same as you and we're getting cookies set by ASP.NET, not our application. For example, "ASPXANONYMOUS".Mingrelian
Are you serving your resources from any HttpHandler or do you have global.asax file in your cookie-less domain ?Reddish
I'd suggest to clear all cookies from the browser. put only few image resources on the domain and try calling it from an html page. I'm sure it will be cookie-free.Reddish
I've cleared all my cookies (from both domains), and requested nothing but a single .jpg from the "static" domain. I still get the ASPXANONYMOUS cookie set in my browser.Mingrelian
I can't help but feel I'm doing something very obviously wrong :-/Mingrelian
Also make sure, you have create a separate domain altogether and not have a virtual-directory application under primary domain.Reddish
When you say "domain", do you mean "site"? Should I create a new site in IIS and have it pointing to the same directory as our normal site? At present I have the alternative "static" domain binded in IIS to the existing site.Mingrelian
Ok, I did what I suggested (what I thought you were suggesting) and it worked! Still got some weird bugs to iron out, I think, but definitely getting there.Mingrelian
I think the trick (in our case) was to make sure that it was set up as a new site in IIS, and not just "binded" to an existed one.Mingrelian
Exactly, it has to be a seperate domain that a browser can differentiate. The browser does not know about IIS sites and v.dirs.Reddish
The other important thing is to make sure that your App Pool for your Static domain is set to "No managed code". Otherwise you'll be served with the annoying ASPXANONYMOUS cookie.Mingrelian
I don't think so. We didn't do anything such. AppPool is a concept on server-side and Http or browsers don't have anything to do with this. How do you have cookie-less domains on non-IIS web-servers ? The only way cookie-less domains are achieved is by making sure no single cookie ever is written from the domain and that is why you keep a seperate domain that acts cookie-less because your primary domain would always have to deal with cookies in some ways.Reddish
As I say, if you don't set the AppPool for your Static domain to "No managed code" you'll be served with an ASPXANONYMOUS cookie.Mingrelian
S
2

Serving resources from Cookie-less domains is great technique if you have more than 5 of combined images/styleshees/javascript then its benefit is noticeable and is gain even with that extra DNS lookup. Also its very easy to implement :). There's how you can easily set it in web.config[system.web] and have completely cookieless subdomain (unless its cookie-fested by Google Analytics but thats easily curable as well) :)

<!-- anonymousIdentification configuration:
                    enabled="[true|false]"                              Feature is enabled?
                    cookieName=".ASPXANONYMOUS"                         Cookie Name
                    cookieTimeout="100000"                              Cookie Timeout in minutes
                    cookiePath="/"                                      Cookie Path
                    cookieRequireSSL="[true|false]"                     Set Secure bit in Cookie
                    cookieSlidingExpiration="[true|false]"              Reissue expiring cookies?
                    cookieProtection="[None|Validation|Encryption|All]" How to protect cookies from being read/tampered
                    domain="[domain]"                                   Enables output of the "domain" cookie attribute set to the specified value
                -->

To give you example

<anonymousIdentification enabled="true" cookieName=".ASPXANONYMOUS" cookieTimeout="100000" cookiePath="/" cookieRequireSSL="false" cookieSlidingExpiration="true" cookieProtection="None" domain="www.domain." />

This will set .ASPXANONYMOUS cookie only on www.domain.anyTLD but not myStatic.domain.anyTLD ... no need to create new pools and stuff :).

Swinge answered 22/3, 2011 at 21:37 Comment(0)
A
0

If you aren't using that cookie, in any way, you could just disable session state in IIS 6: http://support.microsoft.com/kb/244465

In IIS, go to the Home Directory tab, then click the "Configuration" button.

Next go to the Options tab and un-check "Enable session state". The cookie will go away, and you can leave your files where they are with no need for an extra domain or sub-doamin.

Plus, by using additional domains, you increase dns lookups, which partially defeats the intent of the overall optimization.

Absentminded answered 31/8, 2010 at 8:27 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.