'Naked' domains on App Engine

One topic that comes up frequently on the App Engine groups is that of 'naked' domains in App Engine, and how to handle them. A naked domain, for the uninitiated, is one without a service-specific subdomain. For example, "google.com" is naked, while "www.google.com" is not. This post provides an overview of why naked domains are a problem, and what you can do about them.

There are two separate factors that combine to make handling of naked domains a problem in App Engine. The first is the design of DNS, the system for resolving domain names to IP addresses. There are two different types of DNS record we're concerned about here: A records, which specify the IP address for a name, and CNAME records, which acts a "see also", specifying another name for a domain. For example, an A record might say "google.com has the IP", while a CNAME record might say "google.com is also known as www.l.google.com".

The problem arises with the way CNAME records work. An A record specifies the IP address only for a single record - for example, an A record on google.com specifies the address for that domain, but not for subdomains such as "news.google.com". A CNAME record, however, actually serves as a "see also" for not just the name in question, but all its subdomains. The upshot of this is that if I have a CNAME record on "foo.bar", it's not valid to have any other record, at all, on "baz.foo.bar", or any other subdomain of foo.bar.

The second factor is that App Engine operates as a global, reliable service. This means that it has to handle things such as routing traffic to the closest datacenter to the user, and failing over between data centers when necessary, and so forth. As a result, an App Engine app doesn't have a single IP address, or even a small set of them - the IP addresses that can serve an App Engine app will change over time, and even depending on where the user is. Since it's impractical to expect owners of domains that want to host on App Engine to somehow maintain these records, Google employs a common technique: They provide a DNS name - ghs.google.com - and instruct people to CNAME their own domains to that address, allowing Google's DNS servers to take care of returning the right IP address to the user.

I'm sure you can see where this is going: In order to support a global, fault-tolerant service like App Engine, we need to use CNAMEs, but CNAMEs can't be used on naked domains, because that would make it impossible to add any records for subdomains - including 'www', or mail server records. As a result, naked domains aren't directly supported.

What you can do about it

The why is all very well, but what can you do about it? Fortunately, there's a relatively easy solution: Use a service to redirect users who visit the naked domain to the www-prefixed one. Such a service is very simple: It accepts all incoming HTTP requests, and tacks on "www." to the beginning of the URL, sending the user an HTTP redirect (known as a '301 redirect' or '302 redirect') to the new URL. Even better, many registrars, such as godaddy provide such services for free. If you are using such a service, make sure that when you enable it, you don't select 'cloaking' - instead of serving a redirect, this will serve up your site in an invisible frame, which messes up URLs.

If you don't use a registrar that provides this, don't despair. You have two other options: You can change your DNS hosting to a service that does support it, or you can do it yourself.

DNS services that support redirects for naked domains include zoneedit and dyndns. Zoneedit will host your first 5 domains at no charge, and both services charge only nominal fees. You can move your DNS hosting to one of these services while continuing to use your current registrar for the domain registration, too.

If you want to do it yourself, the exact method depends on the HTTP server you use. Here's an example configuration for Apache 2:

<VirtualHost *:80>
	Include /etc/apache2/vhosts.d/default_vhost.include

	<IfModule mpm_peruser_module>
		ServerEnvironment apache apache
        RewriteEngine on
        RewriteCond %{HTTP_HOST} !^www\. [NC]
        RewriteCond %{HTTP_HOST} !^$
        RewriteRule ^/(.*)       http://www.%{HTTP_HOST}/$1 [L,R=permanent]

Other HTTP servers should be similarly easy to configure.


blog comments powered by Disqus