<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Think Vitamin &#187; Chris Lea</title>
	<atom:link href="http://thinkvitamin.com/author/chrislea/feed/" rel="self" type="application/rss+xml" />
	<link>http://thinkvitamin.com</link>
	<description>The Web Practitioner&#039;s Blog</description>
	<lastBuildDate>Thu, 09 Feb 2012 16:41:31 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	
		<item>
		<title>Bulletproof backups for MySQL</title>
		<link>http://thinkvitamin.com/code/bulletproof-backups-for-mysql/</link>
		<comments>http://thinkvitamin.com/code/bulletproof-backups-for-mysql/#comments</comments>
		<pubDate>Thu, 04 Feb 2010 13:27:08 +0000</pubDate>
		<dc:creator>Chris Lea</dc:creator>
				<category><![CDATA[Code]]></category>

		<guid isPermaLink="false">http://carsonified.com/?p=4365</guid>
		<description><![CDATA[You have all your important data backed up, right? I mean, come on folks, it&#8217;s 2010. We may not have flying cars yet like we&#8217;re supposed to, but &#8220;having backups&#8221; is a problem that&#8217;s solved. And I&#8217;m sure you&#8217;ve solved it. I&#8217;m sure you sleep well at night knowing that if a comet hit the [...]]]></description>
			<content:encoded><![CDATA[<p>You have all your important data backed up, right? I mean, come on folks, it&#8217;s 2010. We may not have flying cars yet like we&#8217;re supposed to, but &#8220;having backups&#8221; is a problem that&#8217;s solved. And I&#8217;m sure you&#8217;ve solved it. I&#8217;m sure you sleep well at night knowing that if a comet hit the data center where your website lives, and everything was completely destroyed, you could get back up and running somewhere else quickly enough.</p>
<p>Except that the chance this is actually true for you, statistically, is very small. If we look at the statistics, then what we see is that people are storing increasing amounts of things, important things even, online because disks keep getting bigger and cheaper (though sadly not much faster, but that&#8217;s a different article).</p>
<p>But despite this availability of cheap storage, people for the most part still don&#8217;t back things up. This isn&#8217;t universally true of course, there are <a title="Automattic" href="http://automattic.com" target="_blank">some folks</a> who have implemented really brilliant backup systems at their companies.</p>
<p>Of course, it helps when you have an <a title="Barry Abrahamson" href="http://barry.wordpress.com" target="_blank">amazing systems guy</a> on your team who is made out of lighting bolts and awesomeness, taking care of the nitty gritty details for you. If, however, you are one of the many many people who doesn&#8217;t have a good backup strategy in place, this article is here to help you out.</p>
<p>I&#8217;ve written a <a href="http://carsonified.com/wp-content/uploads/2010/02/db-backup.sh.txt" target="_blank">shell script</a> (<em>Ed: please remove .txt extension before use)</em> that will serve as a good starting point, and we&#8217;ll talk through it in a little bit. For now though, let&#8217;s discuss backups in a more general sense so we can decide what our end goals are.<span id="more-4365"></span></p>
<h3>Types of things to back up</h3>
<p>There are lots of different kinds of data that you may need to back up. Three of the most common are:</p>
<ol>
<li>Source Code</li>
<li>Static Files (images, PDFs, etc)</li>
<li>Data in a Database</li>
</ol>
<p>These days, there&#8217;s a good chance you have your source code files in an RCS system somewhere, such as <a title="GitHub" href="http://github.com" target="_blank">GitHub</a>. If you do (and you should), and your RCS system is on a different server or servers than your site, you already have your source code backed up. If your server catches on fire, you can just do a fresh checkout onto a new server. This is one of the <strong>many</strong> advantages of using an RCS system.</p>
<p>Static files, such as images or music or what have you, are easy to back up. A quick search will reveal dozens of different ways to ship this sort of data to some secondary place in case of emergency.</p>
<p>Database data, however, can be a little more tricky. You can&#8217;t just copy your binary data files safely while the database is running because if a write happens during the process, then your &#8220;backup&#8221; will be in an inconsistent state, which will probably render it useless.</p>
<p>Moreover, it&#8217;s not generally the best way to do a backup because restoring data from a binary copy can be tricky. What my shell script does is allow you to automate correctly backing up a standard MySQL database, or databases, with full end-to-end encryption to an offsite location.</p>
<h3>Is my data backed Up?</h3>
<p>This seems like an easy question to answer. In fact, it is a rather easy question to answer, but I&#8217;ve found that many people have never bothered to answer it, and it gets them in trouble. Are you doing backups of some sort currently? If so, does that mean you have backups? Actually, no, it doesn&#8217;t. If there is one golden rule of having backups that I hope you remember after reading this, it&#8217;s the following:</p>
<blockquote><p>If your backup procedure doesn&#8217;t include instructions for doing a restore of the data, or if your restoration procedure has not been tested, then you don&#8217;t have backups.</p></blockquote>
<p>Simply put, unless you <strong>know</strong> that you can reliably do a restoration of your data, you don&#8217;t have backups. If you haven&#8217;t tried, you don&#8217;t know. As an example, I once encountered a setup where an administrator was &#8220;backing up&#8221; several databases by using <tt>rsync</tt> to copy the binary data store to a remote machine once a day. He thought he had backups, and he was wrong.</p>
<p>As I noted before, if a write happens during the <tt>rsync</tt> process, those binary files aren&#8217;t guaranteed to be in a consistent state. If he&#8217;d ever tried to do a restore of those files (he hadn&#8217;t), he would have discovered this problem. So I say again, until you have tested a restore and it&#8217;s worked, and you&#8217;ve documented how to do that restore, you don&#8217;t have backups.</p>
<p>Another thing that I always like to stress is that you really, really want backups that are under as much personal control as possible. This typically means using a third party or offsite service distinct from your ISP to store your backups. If you ever need to restore some data, there&#8217;s a good chance it&#8217;s because something has gone wrong with your systems.</p>
<p>In that case, there&#8217;s also a fair chance that something has gone wrong at your ISP itself, so you&#8217;d rather not have your backups tied to your ISP. What you want is backups that are stored by some other company, preferably in an entirely different physical data center.</p>
<h3>Basic process for setting up database backups</h3>
<p>The steps I use to back up the databases for <a title="Virb" href="http://virb.com" target="_blank">Virb</a> are as follows:</p>
<ul>
<li>Get a dump of the database</li>
<li>Compress the data</li>
<li>Encrypt the data</li>
<li>Send the data over an encrypted connection to an offsite service</li>
<li>Automate the entire procedure with a cron job</li>
</ul>
<p>It&#8217;s nothing fancy, and it shouldn&#8217;t be. Fancy, intricate things tend to break, and this is the last thing you want to worry about breaking.</p>
<h3>Prerequisites</h3>
<p>You&#8217;ll need to have a few things in place for this to all work. I&#8217;m assuming you&#8217;re using a reasonably new Debian style Linux distribution (which includes Ubuntu). You need to be able to use the <tt>mysqldump</tt> program to get a dump of the desired database data. This comes standard with the MySQL installations on every Linux distribution I know of.</p>
<p>I&#8217;m going to assume that you have a <tt>.my.cnf</tt> file set up in your home directory with a username and password that allow you to dump out the data you want. If you&#8217;ve never used a <tt>.my.cnf</tt> file before, it&#8217;s very easy. Create a file called <tt>.my.cnf</tt> in your home directory, and put the following in it:</p>
<pre><code>[client]
user = dbusername
password = dbpassword</code></pre>
<p>of course substituting the correct username and password for your systems. Then run <tt>chmod 600 $HOME/.my.cnf</tt> on the file so other people can&#8217;t read it. You can now use all the <tt>mysql*</tt> command line utilities without having to pass the <tt>-u</tt> and <tt>-p</tt> flags all the time.</p>
<p>Another assumption I&#8217;m making here is that you can safely run <tt>mysqldump</tt> at some point during the day, and this won&#8217;t mess anything on your site up, which practically means that you don&#8217;t have <strong>that</strong> much data. When you dump the database out, a write lock is placed on all the tables in that database (assuming you&#8217;re dumping out all the tables). So while the data is getting written out, reads can still happen, but no INSERTS, UPDATEs or DELETEs can.</p>
<p>If you have say a few hundred megabytes of binary data, usually located in <tt>/var/lib/mysql</tt> on Linux systems, you are probably okay just dumping the data out from whatever machine the database is on. On reasonably modern hardware, 300M of binary data takes about 15 seconds to dump out, for example. Having a write lock for 15 seconds in the middle of the night is not a big deal for most people.</p>
<p>If you have enough data that it really does take a long time, or your requirements are such that you can&#8217;t have a write lock happen even briefly, then the next option is to set up a mysql slave server that exists just for backups. The idea is that the slave is continuously replicating from the master.</p>
<p>When you do the backup on the slave, the write lock will happen there so that the data can get dumped out, and then once it&#8217;s finished the replication will catch back up to the master if it&#8217;s missed anything.</p>
<p>Explaining how to <a title="MySQL replication documentation" href="http://dev.mysql.com/doc/refman/5.0/en/replication.html" target="_blank">set up MySQL replication</a> is beyond the scope of this article, but this &#8220;back up a slave&#8221; strategy is exactly what we do for Virb.</p>
<p>We&#8217;re going to be backing things up using the online back up service provided by <a title="IBackup" href="http://www.ibackup.com" target="_blank">IBackup</a>. There are plenty of these sorts of services available, so if you want to use a different one feel free. Not much of what I&#8217;m going to describe is specific to IBackup. I have no particular affiliation to them, other than having used them for several projects and being pleased with their products and pricing. I&#8217;m going to assume you have an Economy plan with enough storage to hold your backups.</p>
<p>The only other assumptions I&#8217;l make are that you have <tt>stunnel4</tt>, <tt>rsync</tt>, and <tt>gpg</tt> installed. These are very standard, freely available programs. On reasonably recent Debian style systems (which include Ubuntu) you can install all of them by running this command as root:</p>
<pre><code>apt-get update &amp;&amp; apt-get install stunnel4 rsync gnupg</code></pre>
<h3>Setting up encryption</h3>
<p>We are going to encrypt our database backups, and we&#8217;re going to transmit the encrypted files over a secure connection. This is technically overkill, but encryption is free and easy so we&#8217;ll do it anyway. The first thing you&#8217;ll need to do is generate GPG keys to use.</p>
<p>I&#8217;m not going to explain it here because <a href="http://www.madboa.com/geek/gpg-quickstart/" target="_blank">this tutorial</a> will take you all of five minutes to get through, and covers everything you&#8217;ll need. Just be sure to remember your passphrase, and put copies of your key files somewhere safe just in case.</p>
<p>You should now have GPG keys set up, and an account with IBackup, so create a file in your home directory called <tt>.ibackup</tt> with the following contents:</p>
<pre><code>IBACKUP_USERNAME=username
IBACKUP_PASSWORD=password
GPG_EMAIL=<a href="mailto:your@email.com" target="_blank">your@email.com</a></code></pre>
<p>The reason for this file will become apparent shortly. Just substitute the username and password for your IBackup account there, and put in the email address that was used to generate your GPG keys. Be sure to run <tt>chmod 600 $HOME/.ibackup</tt> so that nobody else can see your password.</p>
<p>Now we need to do a little configuration for <tt>stunnel4</tt>. We don&#8217;t need it to be running all the time, so shut it down and make sure it doesn&#8217;t start on boot with the following commands:</p>
<pre><code>/etc/init.d/stunnel4 stop
update-rc.d -f stunnel4 remove</code></pre>
<p>Now let&#8217;s configure <tt>stunnel4</tt> for IBackup. First get the default configuration file out of the way.</p>
<pre><code>cd /etc/stunnel
mv stunnel.conf stunnel.conf-orig</code></pre>
<p>Next, with your text editor of choice, create a file called <tt>ibackup.conf</tt> in the <tt>/etc/stunnel</tt> directory with the following contents:</p>
<pre><code>client = yes
[ibackup]
accept = 8455
connect = <a href="http://rsync4.ibackup.com:5000" target="_blank">rsync4.ibackup.com:5000</a></code></pre>
<p>These options are fairly specific to IBackup&#8217;s service, but other backup services have similar options. The <tt>accept</tt> option defines a local port for <tt>stunnel4</tt> to use, so you don&#8217;t have to pick that particular one if, for some reason, it&#8217;s already in use.</p>
<h3>Performing the backup</h3>
<p>Since we have our security issues handled, we can now perform the backup. Open up that <a href="http://carsonified.com/wp-content/uploads/2010/02/db-backup.sh.txt" target="_blank">shell script</a> (<em>Ed: please remove .txt extension before use)</em> I mentioned at the beginning in your text editor of choice, so we can go through it. The first 14 lines just get the names of databases we&#8217;re going to back up and identify the programs we&#8217;re going to use.</p>
<pre><code>#!/bin/bash

# <a href="http://ibackup.com" target="_blank">ibackup.com</a> destination
IBACKUP_DEST=$1

# database names
DB_NAMES=$2

# binaries we need
MYSQLDUMP=/usr/bin/mysqldump
GZIP=/bin/gzip
GPG=/usr/bin/gpg
RSYNC=/usr/bin/rsync
STUNNEL=/usr/bin/stunnel4</code></pre>
<p>If you&#8217;re not familiar with <tt>bash</tt> shell scripting, it&#8217;s not hard. Things like <tt>$1</tt> and <tt>$2</tt> indicate command line arguments that get passed to the script. So here, <tt>$1</tt> is something we&#8217;re going to use in the name of the eventual backup file we&#8217;ll get, and <tt>$2</tt> will hold the name(es) of the database(es) we will back up.</p>
<p>Things get more interesting from lines 23 to 39.</p>
<pre><code>DOTIBACKUP="$HOME/.ibackup"

if [ ! -r $DOTIBACKUP ]; then
    echo "Need $DOTIBACKUP file for username and password!"
    exit 1
else
    PERMS=`/bin/ls -l $DOTIBACKUP | /usr/bin/awk '{print $1}'`
fi

if [ $PERMS != "-rw-------" ]; then
    echo "Permissions on $DOTIBACKUP are wrong!"
    echo "Should be -rw-------, actually is $PERMS"
    exit 1
fi

. $DOTIBACKUP
export RSYNC_PASSWORD=$IBACKUP_PASSWORD</code></pre>
<p>These commands check that the <tt>.ibackup</tt> file exists and has the correct permissions. If so, they source the file, which is to say they absorb the things that file defines into the running shell script. Then it sets the environment variable <tt>RSYNC_PASSWORD</tt> to be the value of the <tt>IBACKUP_PASSWORD</tt> that you use to access the service.</p>
<p>Lines 41 and 42 grab the local port that <tt>stunnel4</tt> needs in order to work.</p>
<pre><code>
# local stunnel4 port
STUNNEL_PORT=`/bin/grep 'accept' /etc/stunnel/ibackup.conf | awk '{print $3}'`</code></pre>
<p>Next, between lines 44 and 49, we make make sure there&#8217;s a directory where we can dump out all of our data.</p>
<pre><code># place to dump everything
DUMPDIR="$HOME/.ibackup_data"

if [ ! -d $DUMPDIR ]; then
    mkdir $DUMPDIR
fi
</code></pre>
<p>We&#8217;re eventually going to set this up to run daily, and if we&#8217;re doing a once-per-day backup, it&#8217;s nice to keep a few days&#8217; worth around just in case. In lines 51 through 56 we use the very convenient *NIX <tt>date</tt> program to get date stamps for the current day, the previous day, and the day before that.</p>
<pre><code># today, for tagging the dumpfile
DATE=`/bin/date +%Y-%m-%d`

# yesterday, and the day before that
ONEDAYAGO=`/bin/date -d '1 day ago' +%Y-%m-%d`
TWODAYSAGO=`/bin/date -d '2 days ago' +%Y-%m-%d`</code></pre>
<p>We&#8217;re almost ready to actually dump out our data now. Lines 58 to 86 are really boring and just make sure we have a destination name and the programs we need, so I&#8217;ll gloss over those. The important part picks between lines 88 and 92, where we go into our backup directory and actually run <tt>mysqldump</tt>.</p>
<pre><code>cd $DUMPDIR

echo -n "dumping $DB_NAMES to $DUMPDIR/$IBACKUP_DEST-$DATE.mysql... "
$MYSQLDUMP --opt --databases $DB_NAMES &gt; $IBACKUP_DEST-$DATE.mysql
echo "done!"</code></pre>
<p>Let&#8217;s take a look at that dump command to make sure we understand it. The <tt>$DB_NAMES</tt> variable was set earler in the script. It&#8217;s the second command line argument passwed to the script, and it tells <tt>mysqldump</tt> which databases we care about. The <tt>$IBACKUP_DEST</tt> variable, similarly, was the first command line argument passed to the script, and it just sets the part of the name of our dump file. Finally, the <tt>$DATE</tt> variable we just saw getting set a moment ago, and we use it as a date stamp for this dump.</p>
<p>Next, between lines 94 and 105, we compress and encrypt our dump file. We also check to make sure the encryption step actually worked and we <tt>exit</tt> out if not.</p>
<pre><code>echo -n "gzipping $DUMPDIR/$IBACKUP_DEST-$DATE.mysql... "
$GZIP $DUMPDIR/$IBACKUP_DEST-$DATE.mysql
echo "done!"

echo -n "encrypting $DUMPDIR/$IBACKUP_DEST-$DATE.mysql... "
$GPG -e -r $GPG_EMAIL $DUMPDIR/$IBACKUP_DEST-$DATE.mysql.gz
echo "done!"

if [ $? -ne 0 ]; then
    echo "encryption failed!"
    exit 7
fi</code></pre>
<p>We do a little cleanup and start <tt>stunnel4</tt> in lines 107 to 112, which are pretty self explanatory.</p>
<pre><code>echo -n "removing $DUMPDIR/$IBACKUP_DEST-$DATE.mysql.gz... "
/bin/rm -fv $DUMPDIR/$IBACKUP_DEST-$DATE.mysql.gz
echo "done!"

echo "Starting stunnel for rsync..."
/etc/init.d/stunnel4 start</code></pre>
<p>And now on line 114, we finally send our freshly made backup off to the remote servers managed by IBackup for safe keeping.</p>
<pre><code>$RSYNC -r -v -z -t --delete-after --exclude $IBACKUP_DEST-$ONEDAYAGO* --exclude $IBACKUP_DEST-$TWODAYSAGO* $DUMPDIR/ $IBACKUP_USERNAME@localhost::ibackup/$IBACKUP_DEST --port $STUNNEL_PORT</code></pre>
<p>This is using several different features of <tt>rsync</tt> so let&#8217;s talk about them so we know what is going on. The command line flags <tt>-r -v -z -t</tt> are what the folks at IBackup <a href="http://www.ibackup.com/online-backup-faq/faqqrsync.htm#1" target="_blank">tell us to use</a> when syncing things over to them. The <tt>--delete-after</tt> flag tells <tt>rsync</tt> to delete anything in the target directory that&#8217;s not in the local directory being sync&#8217;d. But we also have the two <tt>--exclude</tt> options there.</p>
<p>So what we&#8217;re really saying is &#8220;Keep the file we&#8217;re sending over, and the one from yesterday, and the day before that, but then delete everything else&#8221;. That way we always have the last three days&#8217; worth of backups. The last point of interest is that because we tell <tt>rsync</tt> to use <tt>$STUNNEL_PORT</tt>, all the communication is encapsulated by <tt>stunnel4</tt> and is therefore encrypted across the wire as it gets transferred. Whew!</p>
<p>The last few lines from 116 to 121 simply stop <tt>stunnel4</tt> and clean up things by removing the directory we made to put the dump file into.</p>
<pre><code>echo "Stopping stunnel for rsync..."
/etc/init.d/stunnel4 stop

echo -n "Cleaning up... "
/bin/rm -rfv $DUMPDIR
echo "done!"</code></pre>
<p>So that <strong>should</strong> about do it. To find out, put this script somewhere and run <tt>chmod 755 db-backup.sh</tt> on it so it&#8217;s executable. Then test it to make sure it actually works. If you want the target to be called &#8216;mybackup&#8217;, and you have to back up the databases named &#8216;db1&#8242;, &#8216;db2&#8242;, and &#8216;db3&#8242;, you would invoke the script like this.</p>
<pre><code>/path/to/db-backup.sh mybackup "db1 db2 db3"
</code></pre>
<p>If that works, then you are almost done! We just need to automate the process, which we can do trivially with a <tt>cron</tt> job. In your shell where you tested the script from, type the following:</p>
<pre><code>crontab -e</code></pre>
<p>This will put you into edit mode for your crontab. Assuming you want the backup to happen starting at 12:40am each day, put the following into your crontab file:</p>
<pre><code>0 40 * * * /path/to/db-backup.sh mybackup "db1 db2 db3" &gt;/dev/null 2&gt;&amp;1</code></pre>
<p>Save the file, and then type <tt>crontab -l</tt> to list the crontab and make sure that line is in there. If it is, then there&#8217;s just one last thing to do.</p>
<h3>Testing a restore</h3>
<p>I said at the start of this article that if you haven&#8217;t done a restore, you don&#8217;t have backups. And seriously, I meant that. So if you&#8217;ve made it this far, then you must do one last step. The day after you set this up, you need to go to your IBackup account, download your dump file, decrypt it with the GPG key you made, and do a restore to a running MySQL instance.</p>
<p><strong>Make sure</strong> you do this last step, as the consequences of missing it can be dire.</p>
<h3>In conculsion</h3>
<p>I covered quite a bit in this article, but if you make it through everything, you should be able to rest easier knowing that you have good, safe backups of your database. Although we used the IBackup service in these examples, very little of what I covered is specific to them.</p>
<p>If you wanted to use a different company, or maybe just push the backup files to a different server you have, you&#8217;ll probably just need to change some of the commands that you pass to <tt>rsync</tt>. The basic strategy though should&#8217;t have to change.</p>
<p>I hope you&#8217;re found this helpful, and don&#8217;t hesitate to <a title="contact me" href="http://chrislea.com/contact/" target="_blank">get in touch</a> if you have any questions.</p>
]]></content:encoded>
			<wfw:commentRss>http://thinkvitamin.com/code/bulletproof-backups-for-mysql/feed/</wfw:commentRss>
		<slash:comments>29</slash:comments>
		</item>
		<item>
		<title>Get Started with DNS</title>
		<link>http://thinkvitamin.com/code/get-started-with-dns/</link>
		<comments>http://thinkvitamin.com/code/get-started-with-dns/#comments</comments>
		<pubDate>Wed, 08 Jul 2009 13:15:54 +0000</pubDate>
		<dc:creator>Chris Lea</dc:creator>
				<category><![CDATA[Code]]></category>

		<guid isPermaLink="false">http://carsonified.com/?p=1823</guid>
		<description><![CDATA[Editor&#8217;s note: Chris will be doing a workshop called Setting up Your Web App &#8211; Powerful Alternatives to LAMP at FOWA London in October. DNS is a big topic, and I&#8217;m certainly not going to try to cover all of it here. However, I think that by the end of this article, we should have [...]]]></description>
			<content:encoded><![CDATA[<p><em>Editor&#8217;s note: Chris will be doing a workshop called <a href="http://events.carsonified.com/fowa/2009/london/workshops#workshop_56">Setting up Your Web App &#8211; Powerful Alternatives to LAMP</a> at FOWA London in October.</em></p>
<p>DNS is a big topic, and I&#8217;m certainly not going to try to cover all of it here. However, I think that by the end of this article, we should have covered the parts that developers should be aware of and understand properly. We&#8217;ll start by talking about the sequence of servers that may get consulted whenever a DNS lookup is performed.</p>
<p><span id="more-1823"></span></p>
<h3>Nameservers</h3>
<p>The DNS system is in place to translate the representations of internet destinations from things that we humans care about (domain names) to things that computers can use (IP addresses). The system is naturally distributed as we&#8217;ll see, which keeps the servers that handle DNS requests from getting too overloaded. There are two distinct sorts of nameservers that we&#8217;ll discuss, and each is responsible for a different sort of task. They are:</p>
<ul>
<li>Authoritative nameservers</li>
<li>Resolving nameservers</li>
</ul>
<p>If you&#8217;ve ever moved a domain name between hosting providers, you&#8217;ve probably had to do something to &#8220;update the nameservers&#8221; for the domain. What you are doing there is changing the authoritative nameservers for that domain. Similarly, if you perform a <a href="http://www.internic.net/whois.html" target="_blank">whois query</a> on a domain, it will tell you what the authoritative nameservers are for it. As the name suggests, the job of an authoritative nameserver is to know all the DNS information for the domains assigned to it.</p>
<p>What&#8217;s not understood as well is that whatever computer you are using to read this article is almost certainly not talking to an authoritative nameserver. It&#8217;s talking to a resolving nameserver, often referred to as just a &#8220;resolver&#8221;. The resolvers are typically provided to you by your ISP. Their job is to answer the requests of client computers for arbitrary DNS lookups.</p>
<p>When you surf to a website, say amazon.com, your computer asks the resolver what the corresponding IP address is (assuming it&#8217;s not stored already in a local cache somewhere on your computer). If the resolver knows, it just answers immediately. If it doesn&#8217;t know, the following sequence of things happen very, very quickly:</p>
<ol>
<li>The resolver determines what nameservers are authoritative for the domain.</li>
<li>The resolver asks one of the authoritative nameservers for the needed info.</li>
<li>Upon getting the info, the resolver stores the information, and answers your computer.</li>
</ol>
<p>So in this way, DNS info gets distributed around the internet. Typically lots of people will be using any particular group of resolvers from an ISP, and once the resolvers know the answers for any given lookup, they remember the answers for future use. This is why Google&#8217;s nameservers can stay up. It&#8217;s not as if they get queried every single time anybody goes to google.com, since the relevant resolvers have that information cached close to all the people surfing there.</p>
<p>Of course, eventually, a resolving nameserver will need to check back in with an authoritative one to see if anything has changed. Otherwise, no DNS information could ever update on the Internet. I&#8217;ll explain how this works next.</p>
<h3>TTL</h3>
<p>So in the last section, we noted how a resolver will ask an authoritative nameserver for information that it doesn&#8217;t already have. It will always get back a little more than just the information it asked for though. Specifically, it will get something called a TTL value for the lookup, which stands for &#8220;Time To Live&#8221;. The TTL is measured in seconds, and it tells the resolver how long it should assume the information it got back should be considered valid. After the amount of time specified in the TTL has passed, the resolver should check back in with the authoritative server even if it still has the information for the lookup stored.</p>
<p>This concept is important enough that it&#8217;s probably worth talking through an example. Let&#8217;s say that I have the TTL for chrislea.com set at four hours, and that a resolver asks my authoritative nameservers for the IP address at exactly 12:00pm. Let&#8217;s then assume that I change the IP address in the authoritative servers at exactly 12:01pm. In this scenario, any client computer talking to the resolver that checked in at noon won&#8217;t pick up the IP address change until 4:00pm. This is why it can take some time for an IP address change to propagate across the Internet. Had I been smarter, at 8:00am that morning, I would have lowered the TTL so some low value, say 300 seconds. That way, by the time I wanted to make the change at noon, all the resolvers that cared to check would have gotten the five minute TTL value. Therefore, in this case, the IP address change would only take five minutes to propagate across the Internet. After the propagation was finished, I would have updated the TTL again and put it back to a higher value to save strain on my authoritative nameservers.</p>
<p>There&#8217;s really no standard for what TTL values are supposed to be. Typical values might correspond to 12 or 24 hours, though they certainly can be longer in some cases. One important note though relates to the &#8220;lowering the TTL&#8221; trick I just described. I recommend <strong>never</strong> using a TTL lower than 300 seconds. This is because some resolvers are set up such that if they see a TTL value that&#8217;s considered &#8220;too low&#8221;, it&#8217;s assumed to be wrong, and the resolver will just use an internal default value. Said internal default will generally be something like 12 or 24 hours, so you would effectively have induced the exact opposite behavior of what you were shooting for.</p>
<p>We&#8217;ve now covered how the relevant servers talk to each other, and how DNS distributes information around. Now, we can dive into exactly what that information is and how it&#8217;s used. When a DNS query happens, it&#8217;s for a specific type of record. There are lots of different types of DNS records, and we&#8217;re not going to talk about all of them here, but we&#8217;re going to cover the most common ones that you should know about.</p>
<h3>A Records</h3>
<p>A lookup for an A record is what people are generally talking about when they generically say &#8220;DNS Lookup&#8221;. Your computer gives the resolver a domain name, gets an IP address back in response. It&#8217;s the sort of lookup that occurs when you are surfing around in a web browser, pinging something, or telnetting to a port.</p>
<p>An important point here is that every time you add a something ending in a dot character &#8220;.&#8221; to the left of a domain, then as far as DNS is concerned, it&#8217;s a differnet domain. For example, the following two domains are distinct:</p>
<ul>
<li>chrislea.com</li>
<li>www.chrislea.com</li>
</ul>
<p>In practice, basically everybody points the www. to the same IP address as just the base domain, but you don&#8217;t have to. They could point to completely different places. Conveniently, you can create a &#8220;star&#8221; record for subdomains if you want a catchall. For example, I have *.chrislea.com set up as a catchall for my personal domain, and the catchall is pointed to the same IP address as just chrislea.com. Therefore, if you try and ping the domain vogons.chrislea.com, which doesn&#8217;t have an explicit entry, it will match the *.chrislea.com entry and ping the same IP as if you had just pinged chrislea.com. However, if you ping debian01.chrislea.com, which <strong>does</strong> have an explicit entry, you will see the IP assigned to that domain directly. If a catchall doesn&#8217;t exist, and you query a subdomain with no entry, the nameserver will respond that there is no entry, and the behavior of the program you&#8217;re using in that case is dependent on the program itself.</p>
<p>Understanding how lookups for A records happen is quite straightforward as we&#8217;ve seen. There are more complex queries though that require multi stage lookups to complete. Let&#8217;s talk about one of these next.</p>
<h3>MX Records</h3>
<p>The MX part of the name stands for &#8220;Mail Exchanger&#8221;. As it turns out, email is so special that it has its own class of DNS entries. They aren&#8217;t too complex, though it is a bigger topic than the A records we just covered. To understand it, we first have to cover just the basics of how an email gets from your computer to wherever it&#8217;s supposed to go.</p>
<p>Many people use desktop email clients such as Outlook, Thunderbird, Mail.app, or (if you&#8217;re lucky) <a href="http://en.wikipedia.org/wiki/Evolution_(software)" target="_blank">Evolution</a>. When you send an email out using one of these programs, it&#8217;s not this client software that&#8217;s actually responsible for getting that email to its final destination. What happens is that your client program forwards the mail on to a server running Mail Transport Agent (MTA) software such as <a href="http://en.wikipedia.org/wiki/Postfix_(software)" target="_blank">postfix</a>. This MTA program is what actually sends the mail for you. When it gets an email message, the MTA looks up the domain to the right of the @ symbol in the email address, and then checks DNS for the MX record(s) for that domain. The response should be one or more domain names. Again, just to be clear, it gets domain names in the form of A records in response. It then looks up the IP address for one of the A records, just as discussed in the previous section, and sends the mail to that IP address.</p>
<p>As an example, let&#8217;s assume you&#8217;re sending an email to my GMail account. When the MTA you&#8217;re using gets the email message, it will check the MX records for gmail.com. The response it gets back will (currently) include:</p>
<ul>
<li>gmail.com mail is handled by 40 alt4.gmail-smtp-in.l.google.com.</li>
<li>gmail.com mail is handled by 10 alt1.gmail-smtp-in.l.google.com.</li>
<li>gmail.com mail is handled by 20 alt2.gmail-smtp-in.l.google.com.</li>
<li>gmail.com mail is handled by 5 gmail-smtp-in.l.google.com.</li>
<li>gmail.com mail is handled by 30 alt3.gmail-smtp-in.l.google.com.</li>
</ul>
<p>Don&#8217;t worry about the syntax here. The important points to note are that</p>
<ol>
<li>There are multiple domains returned in the response.</li>
<li>These domains are A records.</li>
<li>There is a number, used for priority, attached to each domain.</li>
</ol>
<p>The priority number tells the MTA in what order to try the different domains to send the message to. It will try from lowest to highest. So in this case, the MTA will first try to deliver the message to gmail-smtp-in.l.google.com since that has a priority of 5. If it can&#8217;t deliver it to the IP that corresponds to that domain, it will try alt1.gmail-smtp-in.l.google.com next, with a priority of 10, and so on.</p>
<p>There are a variety of reasons for this infrastructure to be in place. First, it allows for some resiliency in email sending, since the receiving entity can have more than one place that mail can be delivered to. If a server goes down, then there may be another one still up that can handle getting the message. Second, it means that the place where your mail goes can be a completely different server, or group of servers, than where your website&#8217;s IP address is. And, it can do this without having to have really annoying domains to the right of the @ symbol in your email address. This is frequently done to use third party mail services for your mail, such as a hosted Exchange service or GMail.</p>
<p>Next, let&#8217;s cover another two stage lookup type of record. This one is actually a bit simpler.</p>
<h3>CNAME Records</h3>
<p>A CNAME, which stands for Canonical Name, is best thought of as an alias. The &#8220;Canonical Name&#8221; name is very poorly worded, and I recommend just always referring to it as a CNAME. The way a CNAME works is that you have a domain you control, and you assign it to be an alias of some other domain name. For example, I currently have the domain thechris.org CNAME&#8217;d to the domain virb.com. There is no A record set up for thechris.org, so if you surf there in your browser, the CNAME value is what&#8217;s returned by DNS. Much like with MX records, the domain virb.com is returned, and then a second lookup happens to determine what IP that is. Then, your browser knows to go to that IP address. However, it will still show thechris.org in the URL bar.</p>
<p>Now, I could have simply pointed the domain thechris.org to the virb.com IP address using an A record. <a href="http://virb.com" target="_blank">Virb</a> would not know any difference if I did. The problem with that approach is that if, in the future, we ever change the IP address for virb.com, I would have to go and explicitly update my A record for thechris.org to whatever the new IP address was in order for things to keep working. Using a CNAME alias like this, things just keep working automagically as we&#8217;d like them to.</p>
<p>Okay, enough with these fancy double lookup records. Let&#8217;s move on to our next topic which will bring us back to a straightforward lookup mechanism, albeit a good one to understand.</p>
<h3>TXT Records</h3>
<p>The TXT record is really boring, at least in terms of how it&#8217;s defined in the RFC. Essentially, this field is supposed to be a &#8220;comments&#8221; area, where you can put whatever you want, but it&#8217;s not supposed to contain important or machine readable information. So why am I mentioning it? Well, as it turns out, even though you&#8217;re not supposed to put imporant stuff in there, people do it all the time. The most common reason currently is to provide <a href="http://en.wikipedia.org/wiki/Sender_Policy_Framework" target="_blank">SPF</a> data. Really covering SPF is outside of the scope of this article, but in a nutshell, it&#8217;s a way to specify via DNS what IP address are allowed to send mail out for a certain domain. For example, here is the TXT record currently in place for chrislea.com:</p>
<p><code><br />
v=spf1 a mx ip4:70.32.89.79 ip4:76.87.248.247 ip4:64.207.133.104 ip4:72.10.46.46 ~all<br />
</code></p>
<p>This says that the four IPs listed there are &#8220;blessed&#8221; by me as being allowed to send email from the domain chrislea.com. The information is used to help in determining if a message is SPAM or not. For example, if I send a message to my GMail account from my chrislea.com domain, and I look at the headers in GMail by selecting &#8220;show original&#8221; from the actions, one of the things I see is this.</p>
<p><code><br />
Received-SPF: pass (google.com: domain of chl@chrislea.com designates 64.207.133.104 as permitted sender) client-ip=64.207.133.104;<br />
Authentication-Results: mx.google.com; spf=pass (google.com: domain of chl@chrislea.com designates 64.207.133.104 as permitted sender) smtp.mail=chl@chrislea.com<br />
</code></p>
<p>So Google checked that I had an SPF record set up, and that the sending IP address from my MTA was in fact permitted. This contributed to a &#8220;not spammy&#8221; score and the message made it to my Inbox.</p>
<p>It&#8217;s important to note again that this technique is really sort of a hack. The DNS specification clearly states that useful information such as this isn&#8217;t supposed to go into TXT records. It&#8217;s done though because it led to people being able to adopt SPF very quickly, since all the nameserver software has supported TXT records forever. In 2005, <a href="http://en.wikipedia.org/wiki/Internet_Assigned_Numbers_Authority" target="_blank">IANA</a> introduced a new record, specifically called an SPF record, to get around this. The syntax is identical to what people are putting into the TXT records. However, due to how recently it was introduced, not all nameserver software supports this new record type yet. Therefore most people are still putting SPF information into TXT records.</p>
<p>There is one more record type that I&#8217;m going to go over, and as it turns out, it&#8217;s also relevant to you largely because of the implications with SPAM.</p>
<h3>PTR Records</h3>
<p>A PTR record, or &#8220;pointer record&#8221;, is generally used to set up what&#8217;s called a reverse DNS lookup. Basically, the idea is that if there is a server associated with a given IP address, you should be able to ask DNS about that IP address and get some indication that there&#8217;s a server there, in the form of a domain name. This is important because many MTA programs that recieve mail are set up to flatly reject any message from an IP address that does not have reverse DNS set up. The idea here is that bad people doing spammy things aren&#8217;t going to properly set up reverse DNS, and thus any message coming from such an IP address is considered untrustworthy.</p>
<p>As an example, my personal mail server at mail.chrislea.com has the IP address 64.207.133.104 currently. If I check reverse DNS, for this, I will see that the reverse entry is for debian01.chrislea.com, as this is the name of the server that I handle my mail on. Note that it&#8217;s not critical for the domain names to match here. The forward lookup is for the &#8220;mail&#8221; subdomain and the reverse lookup returns the &#8220;debian01&#8243; subdomain. Some SPAM calssifying software might use the fact that the base domains match in part of their scoring, but it&#8217;s generally not that critical. What is critical is the fact that the reverse DNS entry exists and is a valid domain name that itself has a forward DNS entry. Because of this (and the fact I don&#8217;t send spammy looking emails), my mail typically doesn&#8217;t get rejected when I send out to other people. It is a good idea to make sure that whoever you are using to send mail through has reverse DNS set up properly for their sending servers. That said, if you haven&#8217;t experienced massive problems with your mail going into SPAM folders, they almost certainly already have.</p>
<h3>Using host to check DNS Entries</h3>
<p>There is a command line program available on every *NIX type system I know of called <tt>host</tt> which can be used to check DNS entries directly from nameservers. If you are using Microsoft Windows, you won&#8217;t have the host program. I&#8217;d recommend scrapping Windows, installing <a href="http://www.ubuntu.com/" target="_blank">Ubuntu</a> or <a href="http://fedoraproject.org/" target="_blank">Fedora</a> on your computer and using that. But since that may not be practical for you, you might want to just skip to the next section. :)</p>
<p>Using <tt>host</tt> is not hard. First you&#8217;ll need to open up a Terminal. If you are using OS X, the Terminal program is in the Applications -&gt; Utilities folder. If you are using Linux or some other *NIX, I&#8217;ll assume you already know how to open up a Terminal. :)</p>
<p>It&#8217;s easiest to learn by example, so now that you have the terminal open, type in the following:</p>
<p><code><br />
host chrislea.com<br />
</code></p>
<p>The output you get should look like this:</p>
<p><code><br />
chrislea.com has address 70.32.89.79<br />
chrislea.com mail is handled by 10 mail.chrislea.com.<br />
</code></p>
<p>You just looked up the A record for chrislea.com, and found that the IP is currently 70.32.89.79. By default, <tt>host</tt> also looks up the MX records for a domain when you do this sort of lookup. That&#8217;s what you see in the second line there. I only have one MX record for my personal email. If I had more, as discussed before, they would all show up here.</p>
<p>A very important thing to be aware of here is that with the above command, you just queried the resolving nameservers that your computer is currently using. If you want to query a different nameserver, you put that in as a final argument like so.</p>
<p><code><br />
host chrislea.com ns2.mediatemple.net<br />
</code></p>
<p>This should return essentially the same information since the <a href="http://mediatemple.net" target="_blank">(mt) Media Temple</a> nameservers are authoritative for chrislea.com. If it doesn&#8217;t, then it probably means that the authoritative nameserver has been updated with new information, like a new IP address, but that this hasn&#8217;t propagated to the resolver you are using yet.</p>
<p>If you want to look at a record that&#8217;s not an A record, you can accomplish this with the <tt>-t</tt> flag using host. Let&#8217;s say you want to check on the TXT record for my domain. The command and results on my Linux machine look like this.</p>
<p><code><br />
chl@melian:~$ host -t txt chrislea.com<br />
chrislea.com descriptive text "v=spf1 a mx ip4:70.32.89.79 ip4:76.87.248.247 ip4:64.207.133.104 ip4:72.10.46.46 ~all"<br />
</code></p>
<p>Here, you can see that it returned the same SPF information that we talked about before, becuase I have that set up in the TXT record for chrislea.com. As another example, let&#8217;s look at the MX records for carsonified.com.</p>
<p><code><br />
chl@melian:~$ host -t mx carsonified.com<br />
carsonified.com mail is handled by 0 ASPMX4.GOOGLEMAIL.com.<br />
carsonified.com mail is handled by 0 ASPMX5.GOOGLEMAIL.com.<br />
carsonified.com mail is handled by 5 ALT1.ASPMX.L.GOOGLE.com.<br />
carsonified.com mail is handled by 5 ALT2.ASPMX.L.GOOGLE.com.<br />
carsonified.com mail is handled by 10 ASPMX.L.GOOGLE.com.<br />
carsonified.com mail is handled by 0 ASPMX2.GOOGLEMAIL.com.<br />
carsonified.com mail is handled by 0 ASPMX3.GOOGLEMAIL.com.<br />
</code></p>
<p>As you can probably guess, Ryan and crew are using GMail to handle their mail needs.</p>
<p>Finally, if you want to look up a PTR record to see the reverse DNS for an IP, just feed that IP address to <tt>host</tt> like you&#8217;d expect to.</p>
<p><code><br />
chl@melian:~$ host 64.207.133.104<br />
104.133.207.64.in-addr.arpa domain name pointer debian01.chrislea.com.<br />
</code></p>
<p>You can put a different nameserver in as the final argument for any of those last examples if you want to query something other than your resolvers. And, of course, if you&#8217;d like to learn about all the other fun options the <tt>host</tt> command has, you should consult <a href="http://linux.die.net/man/1/host" target="_blank">the man page</a>.</p>
<h3>Using nslookup to check DNS Entries</h3>
<p>If you are using Microsoft Windows, I&#8217;m sorry (seriously&#8230; Ubuntu will almost certainly install painlessly on your hardware, and it&#8217;s much prettier). But, if that&#8217;s the boat you are in, the tool they provide to query nameservers directly is called <tt>nslookup</tt>. I should point out that I&#8217;ve basically never used Windows Vista, so I am assuming it works the same on there as it does in Windows XP. If I&#8217;m wrong and there&#8217;s an astute reader out there who uses Vista and can correct me, please do so.</p>
<p>You&#8217;ll first need to open up a DOS shell, which is sort of the same as opening up a Terminal on a *NIX type system. In Windows XP, this can be accomplished by clicking Start, clicking Run, typing &#8220;cmd&#8221; with no quotes into the dialog and pressing Enter. I&#8217;m told that in Vista, you simply click Start, type &#8220;cmd&#8221; with no quotes, and press Enter.</p>
<p>The <tt>nslookup</tt> command has a non-interactive mode, and a shell mode. I find the shell mode much more useful so that&#8217;s what I&#8217;m going to explain. In the DOS prompt, simply type <tt>nslookup</tt> in order to enter the shell. Once you&#8217;re in the shell, type the domain name you are interested in <strong>followed by a period</strong> to do a lookup of the A record for that domain. If you don&#8217;t remember the trailing period, you won&#8217;t get the expected results. As an example:</p>
<p><code><br />
&gt; chrislea.com.<br />
Server:  mjolnir.chrislea.com<br />
Address:  192.168.0.1</code></p>
<p>Non-authoritative answer:<br />
Name:    chrislea.com<br />
Address:  70.32.89.79</p>
<p>If you&#8217;d like to do a different type of query, you use the syntax <tt>set query=&lt;type&gt;</tt>. So, if I&#8217;d like to check on the TXT record for chrislea.com, the commands would look like this.</p>
<p><code><br />
&gt; set query=txt<br />
&gt; chrislea.com.<br />
Server:  mjolnir.chrislea.com<br />
Address:  192.168.0.1</code></p>
<p>Non-authoritative answer:<br />
chrislea.com    text =</p>
<p>&#8220;v=spf1 a mx ip4:70.32.89.79 ip4:76.87.248.247 ip4:64.207.133.104 ip4:72.10.46.46 ~all&#8221;</p>
<p>This should look familiar to you from the examples that used the <tt>host</tt> command (assuming you read those). Now, you&#8217;ll note in these results that the first lines indicate that the Server referenced is called mjolnir.chrislea.com at address 192.168.0.1. This device is my local router which happens to be running a resolver. As you might expect, by default, <tt>nslookup</tt> uses whatever resolving nameservers your Windows installation is itself using by default. If you want to change this, you use the syntax <tt>server &lt;IP address of nameserver&gt;</tt> to tell <tt>nslookup</tt> to use something different. Unfortunately, you can&#8217;t just use the hostname of the nameserver as far as I know. You can see what the IP address is for a nameserver by just pinging whatever that server&#8217;s hostname is from the DOS shell. For example:</p>
<p><code><br />
C:\Documents and Settings\Chris Lea&gt;ping ns1.mediatemple.net</code></p>
<p>Pinging ns1.mediatemple.net [64.207.129.18] with 32 bytes of data:</p>
<p>Control-C<br />
^C<br />
C:\Documents and Settings\Chris Lea&gt;nslookup<br />
Default Server:  mjolnir.chrislea.com<br />
Address:  192.168.0.1</p>
<p>&gt; server 64.207.129.18<br />
Default Server:  ns1.mediatemple.net<br />
Address:  64.207.129.18</p>
<p>&gt; chrislea.com.<br />
Server:  ns1.mediatemple.net<br />
Address:  64.207.129.18</p>
<p>Name:    chrislea.com<br />
Address:  70.32.89.79</p>
<p>Once you&#8217;ve used the <tt>server</tt> directive to change which nameserver <tt>nslookup</tt> is querying, it stays with that nameserver until you change it back or you exit the program.</p>
<p>I think this basically covers the same functionality as what I went over with the <tt>host</tt> command. You should now be able to query arbitrary nameservers for all the sorts of DNS records that we&#8217;ve talked about here.</p>
<h3>Concluding Information</h3>
<p>There are just a few last things that I feel I should mention that didn&#8217;t fit in so well elsewhere.</p>
<p>The first is that <strong>many</strong> of the routers commonly in use today run their own, local, resolving nameservers. As I pointed out in my <tt>nslookup</tt> examples above, the standard &#8220;Default Server&#8221; read mjolnir.chrislea.com with IP address 192.180.0.1. That is the name and IP address of my local Linksys router. The <a href="http://www.polarcloud.com/tomato" target="_blank">Tomato firmware</a> I&#8217;m using runs a local resolver. If the resolver on the router doesn&#8217;t know some answer that is requested, it will then ask my ISPs resolvers. If they don&#8217;t know, they find authoritative nameservers to ask. This is relevant, because sometimes it may be necessary to reboot your local router to flush DNS entries in order to get the most accurate data. I&#8217;ve found this to be particularly true with Apple&#8217;s Airport routers.</p>
<p>Another thing I&#8217;d like to mention is that authoritative nameservers are, generally, &#8220;open&#8221;. By this I mean that they will answer a DNS request from any IP address that queries it. They basically have to, since they by definition have authoritative information that other random systems may need to know. However, resolving nameservers do not share this concern. Therefore, typically, ISPs will limit connectivity to their resolving nameservers to their own IP space. For example, the resolving nameservers we run at (mt) Media Temple will only respond to queries from the (mt) IP space. This is something that is wise to keep in mind, but that practically will not cause much trouble for you in my experince.</p>
<p>Lastly, as I said at the beginning, DNS is a big topic. This should have given you a pretty solid grounding, but there is certainly a lot more to know about it if you&#8217;re trying to be comprehensive. If this applies to you, the standard first place to start reading is the book <a href="http://www.amazon.com/DNS-BIND-5th-Cricket-Liu/dp/0596100574/ref=sr_1_1?ie=UTF8&amp;s=books&amp;qid=1247025409&amp;sr=8-1" target="_blank">DNS and BIND</a> from O&#8217;Reilly press. It&#8217;s commonly just known as &#8220;the bugs book&#8221; among systems administrators due to its ubiquity. A great deal of the book focuses on administering the <a href="http://en.wikipedia.org/wiki/BIND" target="_blank">BIND</a> software package, which you will hopefully never have to deal with. That said it&#8217;s still the standard reference for learning DNS.</p>
<p>With those final notes, I will conclude. I hope you&#8217;ve found this article informative. If you have any questions or (cough) corrections, please comment below or <a href="http://chrislea.com/contact/" target="_blank">contact me</a>.</p>
<h3>Like this article?</h3>
<p>If you enjoyed, this article, feel free to re-tweet it to let others know. Thanks, we appreciate it! :) <script type="text/javascript">// <![CDATA[
tweetmeme_source = 'carsonified';
// ]]&gt;</script><br />
<script src="http://tweetmeme.com/i/scripts/button.js" type="text/javascript"></script></p>
<p>Photo credit: <a href="http://www.flickr.com/photos/seanosh">flickr.com/photos/seanosh</a></p>
]]></content:encoded>
			<wfw:commentRss>http://thinkvitamin.com/code/get-started-with-dns/feed/</wfw:commentRss>
		<slash:comments>28</slash:comments>
		</item>
	</channel>
</rss>

<!-- Dynamic page generated in 0.566 seconds. -->
<!-- Cached page generated by WP-Super-Cache on 2012-02-11 15:38:05 -->

