<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss 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/" version="2.0">

<channel>
	<title>Random Bits</title>
	
	<link>http://blog.shadypixel.com</link>
	<description>tech, politics, etc.</description>
	<lastBuildDate>Mon, 23 Aug 2010 08:02:54 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.1.2</generator>
		<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/shadypixel" /><feedburner:info xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" uri="shadypixel" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><item>
		<title>Latest Project: a Sudoku Site</title>
		<link>http://blog.shadypixel.com/latest-project-a-sudoku-site/</link>
		<comments>http://blog.shadypixel.com/latest-project-a-sudoku-site/#comments</comments>
		<pubDate>Mon, 23 Aug 2010 08:01:18 +0000</pubDate>
		<dc:creator>btmorex</dc:creator>
				<category><![CDATA[Personal]]></category>

		<guid isPermaLink="false">http://blog.shadypixel.com/?p=355</guid>
		<description><![CDATA[In my spare time, I&#8217;ve been playing around with jQuery and databases. I decided to make a simple site to guide my learning. It&#8217;s basically functional at this point so, presenting: FillTheGrid.com &#8211; Sudoku for the Web (Yes, all the good domains are taken) Future plans including fleshing it out into a more complete site [...]]]></description>
			<content:encoded><![CDATA[<p>In my spare time, I&#8217;ve been playing around with jQuery and databases. I decided to make a simple site to guide my learning. It&#8217;s basically functional at this point so, presenting:</p>
<p><a href="http://fillthegrid.com/">FillTheGrid.com &#8211; Sudoku for the Web</a> (Yes, all the good domains are taken)</p>
<p>Future plans including fleshing it out into a more complete site (contact, about, help, maybe a blog), adding user support especially for remembering which puzzles you&#8217;ve played, and adding lots of fun statistics surrounding games won, time taken, difficulty, etc.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.shadypixel.com/latest-project-a-sudoku-site/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Integrate fail2ban with WordPress: Spam Log Plugin</title>
		<link>http://blog.shadypixel.com/spam-log-plugin/</link>
		<comments>http://blog.shadypixel.com/spam-log-plugin/#comments</comments>
		<pubDate>Mon, 20 Apr 2009 11:26:39 +0000</pubDate>
		<dc:creator>btmorex</dc:creator>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[admin]]></category>
		<category><![CDATA[development]]></category>
		<category><![CDATA[fail2ban]]></category>
		<category><![CDATA[iptables]]></category>
		<category><![CDATA[wordpress]]></category>

		<guid isPermaLink="false">http://blog.shadypixel.com/?p=300</guid>
		<description><![CDATA[Spam Log is a WordPress plugin that writes a log entry for every comment marked as spam. The log file is suitable for processing by fail2ban.]]></description>
			<content:encoded><![CDATA[<p>Recently, I&#8217;ve encountered some very aggressive WordPress spam bots. These bots post a new spam comment almost every minute for hours on end. Needless to say my spam queue is a mess. I wrote the following plugin to solve this problem.</p>
<h2>What is Spam Log?</h2>
<p>Spam Log is a simple <a href="http://wordpress.org/">WordPress</a> plugin that logs a message every time a comment is marked as spam. Each log message includes the IP address of the poster and the comment&#8217;s ID. The log can easily be processed by fail2ban. <a href="http://www.fail2ban.org/wiki/index.php/Main_Page">fail2ban</a> is a daemon that scans log files for misbehaving clients and bans them by IP address.  Here is sample output generated by Spam Log:</p>
<pre>2009-04-20 04:15:03 comment id=527 from host=83.233.30.32 marked as spam
2009-04-20 04:18:15 comment id=528 from host=83.233.30.32 marked as spam
2009-04-20 04:20:36 comment id=529 from host=83.233.30.32 marked as spam
2009-04-20 04:21:46 comment id=530 from host=83.233.30.32 marked as spam
2009-04-20 04:22:49 comment id=531 from host=83.233.30.32 marked as spam</pre>
<h3>Why use Spam Log and fail2ban if Akismet/wp-recaptcha/etc. is already catching all the spam?</h3>
<ul>
<li>Many spammers post 50+ comments a day from a single IP address. Even if every comment is correctly marked as spam, the volume alone means that you can&#8217;t easily monitor the spam queue for false positives. Spam Log and fail2ban should considerably reduce the total amount of spam.</li>
<li>Even if spam comments never appear on your blog, they still waste valuable resources on your server. Low-memory virtual servers need all available resources for serving legitimate users. Banning spammers at the firewall before they ever connect to your web server is very efficient.</li>
</ul>
<h2>Installation</h2>
<h3>Spam Log</h3>
<ol>
<li>Upload the <code class="path">spam-log</code> folder to the <code class="path">wp-content/plugins</code> directory.</li>
<li>Active the plugin through the WordPress Admin menu.</li>
<li>Set the location of the spam log through Spam Log&#8217;s Options page in the WordPress Admin menu. By default, the location is set to <code class="path">wp-content/spam.log</code>. The file or containing directory needs to be writeable by the user that the web server runs as. On Debian or Ubuntu systems, you can do the following:</li>
</ol>
<p><code>$ sudo touch /path/to/spam.log<br />
$ sudo chown www-data.www-data /path/to/spam.log</code></p>
<h3>fail2ban Configuration</h3>
<p>Create <code class="path">/etc/fail2ban/filter.d/spam-log.conf</code> with the following contents:</p>
<pre>[Definition]
failregex = ^\s*comment id=\d+ from host=&lt;HOST&gt; marked as spam$
ignoreregex =</pre>
<p>Add the following lines to <code class="path">/etc/fail2ban/jail.local</code>:</p>
<pre>[spam-log]
enabled  = true
port     = http,https
filter   = spam-log
logpath  = /path/to/spam.log
maxretry = 5
findtime = 3600
bantime  = 86400</pre>
<p>Change <code>logpath</code> to the path you set on Spam Log&#8217;s Options page. This configuration will ban an IP address for a day if it&#8217;s used to post 5 comments within an hour that are marked as spam. <strong>Warning:</strong> Some captcha plugins mark comments as spam when a user fails a captcha. Be careful decreasing <code>maxretry</code> if you&#8217;re using such a plugin as there&#8217;s a risk that you will ban legitimate users.</p>
<h2>Download</h2>
<p><a href="http://static.shadypixel.com/files/spam-log-0.1.tar.gz">spam-log-0.1.tar.gz</a><br />
<a href="http://static.shadypixel.com/files/spam-log-0.1.zip">spam-log-0.1.zip</a></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.shadypixel.com/spam-log-plugin/feed/</wfw:commentRss>
		<slash:comments>16</slash:comments>
		</item>
		<item>
		<title>Log iptables Messages to a Separate File with rsyslog</title>
		<link>http://blog.shadypixel.com/log-iptables-messages-to-a-separate-file-with-rsyslog/</link>
		<comments>http://blog.shadypixel.com/log-iptables-messages-to-a-separate-file-with-rsyslog/#comments</comments>
		<pubDate>Fri, 17 Apr 2009 17:53:21 +0000</pubDate>
		<dc:creator>btmorex</dc:creator>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[admin]]></category>
		<category><![CDATA[firehol]]></category>
		<category><![CDATA[firewall]]></category>
		<category><![CDATA[howto]]></category>
		<category><![CDATA[iptables]]></category>
		<category><![CDATA[logrotate]]></category>
		<category><![CDATA[rsyslog]]></category>

		<guid isPermaLink="false">http://blog.shadypixel.com/?p=269</guid>
		<description><![CDATA[Learn how to filter iptables log messages to a separate file. Two methods are presented: one using traditional syslog and one using rsyslog.]]></description>
			<content:encoded><![CDATA[<p>Firewall logging is very important, both to detect break-in attempts and to ensure that firewall rules are working properly. Unfortunately, it&#8217;s often difficult to predict in advance which rules and what information should be logged. Consequently, it&#8217;s common practice to err on the side of verbosity. Given the amount of traffic that any machine connected to the Internet is exposed to, it&#8217;s critical that firewall logs be separated from normal logs in order to ease monitoring. What follows are two methods to accomplish this using iptables on Linux. The first method uses traditional syslog facility/priority filtering. The second, more robust method filters based on message content with rsyslog.</p>
<h2>The Old Way: Use a Fixed Priority for iptables</h2>
<p>The traditional UNIX syslog service only has two ways to categorize, and consequently route, messages: facility and priority. Facilities include kernel, mail, daemon, etc. Priorities include emergency, alert, warning, debug, etc. The Linux <a href="http://www.netfilter.org/">iptables</a> firewall runs in the kernel and therefore always has the facility set to kern. Using traditional syslog software, the only way you can separate iptables messages from other kernel messages is to set the priority on all iptables messages to something specific that hopefully isn&#8217;t used for other kernel logging.</p>
<p>For example, you could add something like the following to <code class="path">/etc/syslog.conf</code>:</p>
<pre>kern.=debug -/var/log/iptables.log</pre>
<p>and specifically remove the kernel debugging messages from all other logs like so:</p>
<pre>kern.*;kern.!=debug -/var/log/kern.log</pre>
<p>and in each iptables logging rule use the command line option <code>--log-level debug</code>.</p>
<p>There are two distinct disadvantages to this approach. First, there&#8217;s no guarantee that other kernel components won&#8217;t use the priority you&#8217;ve set iptables to log at. There&#8217;s a real possibility that useful messages will be lost in the deluge of firewall logging. Second, this approach prevents you from actually setting meaningful priorities in your firewall logs. You might not care about random machines hammering Windows networking ports, but you definitely want to know about malformed packets reaching your server.</p>
<h2>The New Way: Filter Based on Message Content with rsyslog</h2>
<p><a href="http://www.rsyslog.com/">rsyslog</a> is mostly a drop-in replacement for a tradtional syslog daemon&#8211;on Linux, klogd and sysklogd. In fact, on Debian and Ubuntu, you can simply:</p>
<p><code>$ sudo apt-get install rsyslog</code></p>
<p>and if you haven&#8217;t customized <code class="path">/etc/syslog.conf</code>, logging should continue to work in precisely the same way. rsyslog has been the default syslog on Red Hat/Fedora based systems for a number of versions now, but if it&#8217;s not installed:</p>
<p><code>$ sudo yum install rsyslog</code></p>
<h3>Configure iptables to Use a Unique Prefix</h3>
<p>We&#8217;ll setup rsyslog to filter based on the beginning of a message from iptables. So, for each logging rule in your firewall script, add <code>--log-prefix "iptables: "</code>. Most firewall builder applications can be easily configured to add a prefix to every logging rule. For example, if you&#8217;re using <a href="http://firehol.sourceforge.net/">firehol</a> as I am, you could add:</p>
<pre>FIREHOL_LOG_PREFIX="firehol: "</pre>
<p>to <code class="path">/etc/firehol/firehol.conf</code>.</p>
<h3>Configure rsyslog to Filter Based on Prefix</h3>
<p>Create <code class="path">/etc/rsyslog.d/iptables.conf</code> with the following contents:</p>
<pre>:msg, startswith, "iptables: " -/var/log/iptables.log
&amp; ~</pre>
<p>The first line means send all messages that start with &#8220;iptables: &#8221; to <code class="path">/var/log/iptables.log</code>. The second line means discard the messages that were matched in the previous line. The second line is of course optional, but it saves the trouble of explicitly filtering out firewall logs from subsequent syslog rules.</p>
<p>When I configured this on my own machines, I did notice one issue that may be a peculiarity of firehol, but it&#8217;s probably worth mentioning anyway. It seems that firehol adds an extra single quote at the beginning of log messages that needs to be matched in the rsyslog rule. For example, here&#8217;s a log message from firehol:</p>
<pre class="wrap">Apr 17 12:41:07 tick kernel: 'firehol: 'IN-internet':'IN=eth0 OUT= MAC=fe:fd:cf:c0:47:b5:00:0e:39:6f:48:00:08:00 SRC=189.137.225.191 DST=207.192.75.74 LEN=64 TOS=0x00 PREC=0x00 TTL=32 ID=5671 DF PROTO=TCP SPT=3549 DPT=5555 WINDOW=65535 RES=0x00 SYN URGP=0</pre>
<p>Notice the extra quote after &#8220;kernel: &#8221; and before &#8220;firehol: &#8220;. So, on my machine I configured the rsyslog filter like so:</p>
<pre>:msg, startswith, "'firehol: " -/var/log/iptables.log
&amp; ~</pre>
<h3>Configure iptables Log Rotation</h3>
<p>Finally, since we&#8217;re logging to a new file, it&#8217;s useful to create a log rotation rule. Create a file /etc/logrotate.d/iptables with the following contents:</p>
<pre>/var/log/iptables.log
{
	rotate 7
	daily
	missingok
	notifempty
	delaycompress
	compress
	postrotate
		invoke-rc.d rsyslog reload &gt; /dev/null
	endscript
}</pre>
<p>The preceding script tells logrotate to rotate the firewall log daily and keep logs from the past seven days.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.shadypixel.com/log-iptables-messages-to-a-separate-file-with-rsyslog/feed/</wfw:commentRss>
		<slash:comments>11</slash:comments>
		</item>
		<item>
		<title>Using YSlow to Optimize Web Site Performance Continued</title>
		<link>http://blog.shadypixel.com/using-yslow-to-optimize-web-site-performance-continued/</link>
		<comments>http://blog.shadypixel.com/using-yslow-to-optimize-web-site-performance-continued/#comments</comments>
		<pubDate>Fri, 27 Mar 2009 21:52:16 +0000</pubDate>
		<dc:creator>btmorex</dc:creator>
				<category><![CDATA[Web]]></category>
		<category><![CDATA[admin]]></category>
		<category><![CDATA[apache]]></category>
		<category><![CDATA[css]]></category>
		<category><![CDATA[development]]></category>
		<category><![CDATA[html]]></category>
		<category><![CDATA[performance]]></category>
		<category><![CDATA[yslow]]></category>

		<guid isPermaLink="false">http://blog.shadypixel.com/?p=225</guid>
		<description><![CDATA[The second part of an article/tutorial on using the YSlow firebug extension to optimize web site performance.]]></description>
			<content:encoded><![CDATA[<p>This article is a continuation of a previous article. If you haven&#8217;t yet, read the previous article: <a href="http://blog.shadypixel.com/using-yslow-to-optimize-web-site-performance/">Using YSlow to Optimize Web Site Performance</a>.</p>
<p>In this post, I&#8217;ll  cover rules 5-13 and summarize the results of the optimizations that I made to my site.</p>
<h2>YSlow’s 13 Rules to Improve Web Site Performance (rules 5-13)</h2>
<p>A number of these rules are fairly simple, so I&#8217;ll cover some together.</p>
<h3>5. Put CSS at the top</h3>
<h3>6. Put JS at the bottom</h3>
<p>These rules are fairly easy to follow and most sites shouldn&#8217;t have to change anything. Putting CSS in the document <code>&lt;head&gt;</code> makes the page appear to load faster because of progressive rendering. It turns out that javascript blocks parallel downloads, so ideally you want to load javascript when everything else has already loaded. Also, if the javascript is hosted externally and the external server is slow, the rest of the page should load without problems.</p>
<h3>7. Avoid CSS expressions</h3>
<p>I&#8217;ll be honest here. I didn&#8217;t even know CSS had expressions until I saw this rule. YSlow recommends avoiding them because they are evaluated an absurd number of times.</p>
<h3>8. Make JS and CSS external</h3>
<p>External files can be cached indepently. If your users usually browse to more than one page on your site or you have frequent returning visitors, this should improve load times.</p>
<h3>9. Reduce DNS lookups</h3>
<p>DNS lookups can still take a fair amount of time even on a broadband connection. Basically, try to keep the number of unique host names fairly low. There is one competing performance benefit to serving page components from multiple hosts. It turns out that most browsers will only make two simultaneous connections to a given host. So, serving content from multiple hosts can speed up page load times especially if there are a lot of components.</p>
<h3>10. Minify JS and CSS</h3>
<p>Actually, in YSlow this rule says <em>Minify JS</em>, but on the explanation page, they added CSS. Minifying these files simply makes them smaller even if you&#8217;re already compressing them. The best minifier I found is the <a href="http://developer.yahoo.com/yui/compressor/">YUI Compressor</a>, which handles both CSS and javascript. Here are the results of minifying my site&#8217;s stylesheet:</p>
<table border="0">
<tbody>
<tr>
<th></th>
<th>Uncompressed</th>
<th>gzipped</th>
</tr>
<tr>
<th>Original</th>
<td>9814 bytes</td>
<td>2806 bytes</td>
</tr>
<tr>
<th>Minified</th>
<td>6164 bytes</td>
<td>1645 bytes</td>
</tr>
<tr>
<th>Savings</th>
<td>37.2%</td>
<td>41.4%</td>
</tr>
</tbody>
</table>
<p>The YUI Compressor is pretty easy to use, but using it is going to get annoying unless you automate. To solve this problem, I once again modified my publish CSS script to do the minifying automatically. If you read the first part of this article and you&#8217;re wondering how many times I&#8217;m going to modify my publish script, this is the final version:</p>
<pre>#!/bin/sh

SERIAL_FILE=serial.txt
OLD_SERIAL=`cat ${SERIAL_FILE}`
SERIAL=$((${OLD_SERIAL} + 1))
YUICOMPRESSOR_PATH=/home/avery/yuicompressor-2.4.2/build/yuicompressor-2.4.2.jar

cat	style.css.original \
	../../plugins/wp-recaptcha/recaptcha.css \
	../../plugins/deko-boko-a-recaptcha-contact-form-plugin/display/dekoboko.css \
	| java -jar ${YUICOMPRESSOR_PATH} --type css &gt; style-${SERIAL}.css

sed "s/REPLACE_WITH_SERIAL/${SERIAL}/g" &lt; header.php.original &gt; header.php

rm style-${OLD_SERIAL}.css

echo ${SERIAL} &gt; ${SERIAL_FILE}</pre>
<p>Using publish scripts for stylesheets and javascript might seem like overkill at first, but that simple script has allowed me to make significant improvements that otherwise would be too time consuming to implement.</p>
<h3>11. Avoid redirects</h3>
<h3>12. Remove duplicate scripts</h3>
<p>These two rules are fairly easy to follow. Sometimes you can&#8217;t avoid redirects such as when you move to a new domain or restructure your site. Those sort of redirects are good and they maintain the reputation your site has built with search engines. That said, a lot of redirects can be eliminated simply by adding a trailing slash to a URL. Be especially mindful if you&#8217;re working on hand-coded sites rather than CMS-based sites. Remove duplicate scripts is pretty obvious. Unfortunately, Google Adsense serves the same scripts for each ad on a page and there&#8217;s no way to fix it.</p>
<h3>13. Configure ETags</h3>
<p>I won&#8217;t say much about ETags. This YSlow rule actually means configure ETags or remove them entirely. For a site being served off a single web server, ETags offer no benefits and some drawbacks including the fact that <a href="https://issues.apache.org/bugzilla/show_bug.cgi?id=39727">Apache generates invalid ETags for gzipped content</a>. I recommend turning them off unless you&#8217;re willing to configure them per <a href="http://developer.yahoo.com/performance/rules.html#etags">Yahoo&#8217;s ETags best practices</a>. To disable ETags in Apache add the following to the virtual host configuration or the main .htaccess:</p>
<pre>FileETag None</pre>
<h2>Results</h2>
<p>Finally, here are the results that I obtained. First, my YSlow score:</p>
<div id="attachment_249" class="wp-caption aligncenter" style="width: 393px"><a href="http://static.shadypixel.com/uploads/2009/03/final-yslow-performance.png"><img class="size-full wp-image-249" title="Final YSlow Performance Tab" src="http://static.shadypixel.com/uploads/2009/03/final-yslow-performance.png" alt="Final YSlow Performance Tab" width="383" height="391" /></a><p class="wp-caption-text">Final YSlow Performance Tab</p></div>
<p>I&#8217;m somewhat disappointed that after all of that, my score barely improved, moving from an F (59) to a D (63). Unfortunately, most of the remaining areas of optimization are either unrealistic as in <em>Use a CDN</em> or are out of my control.</p>
<p>What about real performance? The following tables include the minimum, maximum, and average times out of 10 page loads. First, with a cold cache:</p>
<table border="0">
<caption>Page Load Times Before and After Optimization (cold cache)</caption>
<tbody>
<tr>
<th></th>
<th>Minimum</th>
<th>Maximum</th>
<th>Average</th>
</tr>
<tr>
<th>Before Optimization</th>
<td>1.243s</td>
<td>1.890s</td>
<td>1.422s</td>
</tr>
<tr>
<th>After Optimization</th>
<td>1.024s</td>
<td>1.410s</td>
<td>1.215s</td>
</tr>
<tr>
<th>Speed Increase</th>
<td>17.6%</td>
<td>25.4%</td>
<td>14.6%</td>
</tr>
</tbody>
</table>
<p>I&#8217;m actually fairly satisfied. Most of the optimizations I did would benefit repeat visitors rather than new visitors. A 15% performance improvement is not bad at all. Next, with a warm cache:</p>
<table border="0">
<caption>Page Load Times Before and After Optimization (warm cache)</caption>
<tbody>
<tr>
<th></th>
<th>Minimum</th>
<th>Maximum</th>
<th>Average</th>
</tr>
<tr>
<th>Before Optimization</th>
<td>0.817s</td>
<td>1.176s</td>
<td>0.968s</td>
</tr>
<tr>
<th>After Optimization</th>
<td>0.732s</td>
<td>0.920s</td>
<td>0.815s</td>
</tr>
<tr>
<th>Speed Increase</th>
<td>10.4%</td>
<td>21.8%</td>
<td>15.8%</td>
</tr>
</tbody>
</table>
<p>These results baffled me. The improvements are only slightly better than the cold cache numbers and I really thought page loads would speed up more for repeat visitors. After some investigation, it turns out that I was loading pages in the wrong way. Specifically, I was hitting the f5 key to reload the page in my warm cache tests. Reloading with f5 has a special meaning in at least Firefox. It tells the browser to check that every item in the cache is the correct version even if the item is set to expire in 10 years. Here are the numbers without using f5:</p>
<table border="0">
<caption>Non-f5 Page Load Times After Optimization (warm cache)</caption>
<tbody>
<tr>
<th>Minimum</th>
<th>Maximum</th>
<th>Average</th>
</tr>
<tr>
<td>0.397s</td>
<td>0.525s</td>
<td>0.448s</td>
</tr>
</tbody>
</table>
<p>Now, those are some fast page loads. I&#8217;m not interested enough to revert all my changes and re-test, but some statistics from YSlow suggest that I probably sped up warm cache page loads by a fair amount. Here&#8217;s the initial Stats tab, prior to any optimization:</p>
<div id="attachment_250" class="wp-caption aligncenter" style="width: 428px"><a href="http://static.shadypixel.com/uploads/2009/03/initial-yslow-stats.png"><img class="size-full wp-image-250" title="Initial YSlow Stats Tab" src="http://static.shadypixel.com/uploads/2009/03/initial-yslow-stats.png" alt="Initial YSlow Stats Tab" width="418" height="497" /></a><p class="wp-caption-text">Initial YSlow Stats Tab</p></div>
<p>And here&#8217;s the final Stats tab after all the optimizations:</p>
<div id="attachment_251" class="wp-caption aligncenter" style="width: 422px"><a href="http://static.shadypixel.com/uploads/2009/03/final-yslow-stats.png"><img class="size-full wp-image-251" title="Final YSlow Stats Tab" src="http://static.shadypixel.com/uploads/2009/03/final-yslow-stats.png" alt="Final YSlow Stats Tab" width="412" height="497" /></a><p class="wp-caption-text">Final YSlow Stats Tab</p></div>
<p>Of particular note: in the case of a primed cache, I reduced the number of HTTP requests from 25 to 15.</p>
<p>Overall, I&#8217;m satisfied with the performance improvements. Even if the improvements are not amazing, working with YSlow is not particularly hard or time consuming. In fact, writing this article took much longer than the actual changes I made to my web site. A 15% reduction in load times is worth an hour or two of writing scripts and changing server configurations.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.shadypixel.com/using-yslow-to-optimize-web-site-performance-continued/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Using YSlow to Optimize Web Site Performance</title>
		<link>http://blog.shadypixel.com/using-yslow-to-optimize-web-site-performance/</link>
		<comments>http://blog.shadypixel.com/using-yslow-to-optimize-web-site-performance/#comments</comments>
		<pubDate>Thu, 26 Mar 2009 05:11:16 +0000</pubDate>
		<dc:creator>btmorex</dc:creator>
				<category><![CDATA[Web]]></category>
		<category><![CDATA[admin]]></category>
		<category><![CDATA[apache]]></category>
		<category><![CDATA[css]]></category>
		<category><![CDATA[development]]></category>
		<category><![CDATA[html]]></category>
		<category><![CDATA[performance]]></category>
		<category><![CDATA[yslow]]></category>

		<guid isPermaLink="false">http://blog.shadypixel.com/?p=187</guid>
		<description><![CDATA[An article/tutorial on using the YSlow firebug extension to optimize web site performance.]]></description>
			<content:encoded><![CDATA[<p>I&#8217;m a big fan of <a href="http://www.youtube.com/user/googletechtalks">Google Tech Talks</a>. Recently, I caught a particularly interesting one from <a href="http://stevesouders.com/">Steve Souders</a> called <a href="http://www.youtube.com/watch?v=52gL93S3usU">Life&#8217;s Too Short &#8211; Write Fast Code</a>. Steve Souders used to work for Yahoo! as their chief web performance guru; he now does much the same at Google. The talk was a continuation of a previous lecture on a <a href="http://getfirebug.com/">firebug</a> extension that he wrote called <a href="http://developer.yahoo.com/yslow/">YSlow</a>. Suffice it to say, he knows what he&#8217;s talking about when it comes to high performance web sites. Anyway, it piqued my interest, so I decided to try to improve the performance of my own site. This article/tutorial and the next chronicle the changes I made and the results that I obtained.</p>
<h2>YSlow&#8217;s 13 Rules to Improve Web Site Performance (rules 1-4)</h2>
<p>YSlow grades web sites based on 13 different rules. Browse to your site, click on the YSlow icon in the lower right corner of Firefox, and click on the Performance tab. Here&#8217;s how one post on my site ranked before making any changes:</p>
<div id="attachment_188" class="wp-caption aligncenter" style="width: 478px"><a href="http://static.shadypixel.com/uploads/2009/03/initial-performance.png"><img class="size-full wp-image-188" title="Initial YSlow Performance Tab" src="http://static.shadypixel.com/uploads/2009/03/initial-performance.png" alt="Initial YSlow Performance Tab" width="468" height="392" /></a><p class="wp-caption-text">Initial YSlow Performance Tab</p></div>
<p>Clicking on any rule takes you to a page explaining it in more detail.</p>
<p>A quick note: the screenshot above was taken before I disabled <a href="http://www.woopra.com/">Woopra</a>, which is web analytics software similar to Google Analytics. I had tried it out a couple months ago and had simply forgotten that I had it enabled. Disabling Woopra improved my grades very slighty in a number of rules, but I don&#8217;t include that optimization in the main article because it&#8217;s technically a functional change to my site. As explained below, YSlow doesn&#8217;t make functional recommendations.</p>
<p>What follows are the changes that I made to my site, rule-by-rule.</p>
<h3>1. Make fewer HTTP requests</h3>
<p>This is one of the most important rules and it&#8217;s also one of the most difficult to implement. It&#8217;s worth mentioning at this point that YSlow&#8217;s general strategy isn&#8217;t to recommend changes that alter the actual content and functionality of a site, but instead suggest changes that will make the same content load faster. In other words, if you have a gallery with 20 images, the recommendation isn&#8217;t to cut the gallery down to 5 images. Consequently, <em>Make fewer HTTP requests</em> focuses on three components of web pages: javascript, stylesheets, and background images.</p>
<p>Expanding the rule will show counts of each component if they exceed YSlow&#8217;s thresolds:</p>
<div id="attachment_191" class="wp-caption aligncenter" style="width: 430px"><a href="http://static.shadypixel.com/uploads/2009/03/make-fewer-requests-expanded.png"><img class="size-full wp-image-191" title="Make fewer requests expanded" src="http://static.shadypixel.com/uploads/2009/03/make-fewer-requests-expanded.png" alt="Make fewer requests expanded" width="420" height="80" /></a><p class="wp-caption-text">Make fewer requests expanded</p></div>
<p>In the case of my blog, the problem comes down to external javascript and CSS. To get a list of page components, click on the Components tab. They&#8217;re sorted by type so, it&#8217;s very easy to identify the problem files.</p>
<div id="attachment_192" class="wp-caption aligncenter" style="width: 609px"><a href="http://static.shadypixel.com/uploads/2009/03/js-and-css-components.png"><img class="size-full wp-image-192" title="Javascript and CSS components" src="http://static.shadypixel.com/uploads/2009/03/js-and-css-components.png" alt="Javascript and CSS components" width="599" height="277" /></a><p class="wp-caption-text">Javascript and CSS components</p></div>
<p>I can group these into 4 basic categories: Google Adsense, Google Analytics, reCAPTCHA, and WordPress plugins. Adsense has a particularly egregious number of external javascript files. Unfortunately, there&#8217;s nothing I can do about it as modifying the code is against Adsense policies. Analytics has just one javascript file and keeping that external is probably a good idea. Almost anyone who browses more than a handful of sites will have ga.js cached as Analytics use is pervasive. Similarly, there&#8217;s a good possibility that visitors will have the main reCAPTCHA javascript cached and the other code is dynamic so you don&#8217;t want to mess with it. Finally, there are the stylesheets from WordPress plugins.</p>
<p>Combining CSS into one file&#8211;especially when it&#8217;s all hosted on the same server&#8211;is a really good idea. In this case, I&#8217;m serving my main style.css file and two other stylesheets from the <a href="http://www.blaenkdenum.com/wp-recaptcha/">wp-recaptcha plugin</a> and the <a href="http://www.toppa.com/deko-boko-wordpress-plugin/">Deko Boko plugin</a>. I wrote a simple script to combine all of the files into one, like so:</p>
<pre>#!/bin/sh

cat style.css.original \
    ../../plugins/wp-recaptcha/recaptcha.css \
    ../../plugins/deko-boko-a-recaptcha-contact-form-plugin/display/dekoboko.css \
    &gt; style.css</pre>
<p>I also modified both plugins to no longer include a link to their original stylesheets in the <code>&lt;head&gt;</code> section of the page. Search the PHP files for references to the original stylesheets and comment those lines out.</p>
<p>Before moving on, it&#8217;s worth mentioning that you should use <a href="http://www.alistapart.com/articles/sprites/">CSS sprites</a> if at all possible. Many sites use tens of icons per page. Combining those tiny icons into one sprite is a huge performance boost.</p>
<h3>2. Use a CDN</h3>
<p>One persistent criticism of YSlow is that it focuses on performance improvements to major sites. I don&#8217;t really agree with that; in fact, nearly every rule applies equally to both small and large sites. <em>Use a CDN</em> is the exception. A CDN allows you to serve content to users from geographically close servers. It&#8217;s a decent performance improvement, but it&#8217;s also incredibly expensive.</p>
<h3>3. Add an Expires header</h3>
<p>What&#8217;s the fastest HTTP request? One that never takes place. The idea behind far future Expires headers is that you should allow permanent caching of any page component that won&#8217;t change or even that is unlikely to change very often. If it does need to be modified, you simply rename it. To accomplish this using Apache, enable mod_expires and add the following to the virtual host configuration or the main .htaccess:</p>
<pre>&lt;IfModule mod_expires.c&gt;
    ExpiresActive On
    ExpiresByType image/gif "access plus 10 years"
    ExpiresByType image/jpeg "access plus 10 years"
    ExpiresByType image/png "access plus 10 years"
    ExpiresByType text/css "access plus 10 years"
&lt;/IfModule&gt;</pre>
<p><strong>Warning: </strong>The preceding configuration means that any time you change an image or stylesheet served my Apache, you must rename it. If a browser or proxy server has the component cached, it will never check to see if its version is the same as the version on your server. For images, this is probably not an annoyance; changing an image usually means uploading a new version in which case it will have a different file name anyway. For stylesheets, this can be annoying if you don&#8217;t automate the process.</p>
<p>I solved the stylesheet problem with a script. In the same directory as style.css, I created a text file like so:</p>
<p><code>$ echo 0 &gt; serial.txt</code></p>
<p>Next, I modified the script that combined the 3 original stylesheets I was using like so:</p>
<pre>#!/bin/sh

SERIAL_FILE=serial.txt
OLD_SERIAL=`cat ${SERIAL_FILE}`
SERIAL=$((${OLD_SERIAL} + 1))

cat style.css.original \
    ../../plugins/wp-recaptcha/recaptcha.css \
    ../../plugins/deko-boko-a-recaptcha-contact-form-plugin/display/dekoboko.css \
    &gt; style-${SERIAL}.css

sed "s/REPLACE_WITH_SERIAL/${SERIAL}/g" &lt; header.php.original &gt; header.php

rm -f style-${OLD_SERIAL}.css

echo ${SERIAL} &gt; ${SERIAL_FILE}</pre>
<p>The script reads a number in from serial.txt, increments it, creates a new stylesheet with the number appended, and in this case modifies WordPress&#8217; header.php to link to the new stylesheet. Every time I want a different style on my site, I modifiy style.css.original and run this script.</p>
<h3>4. Gzip components</h3>
<p>Everyone in every circumstance should enable mod_deflate. Way back in the early days of the web there were browsers that didn&#8217;t play well with gzip; they basically don&#8217;t exist anymore. In Apache, enable mod_deflate&#8211;it&#8217;s probably already enabled&#8211;and add the following to the virtual host configuration or the main .htacess:</p>
<pre>&lt;IfModule mod_deflate.c&gt;
    AddOutputFilterByType DEFLATE text/html text/plain text/xml text/css
&lt;/IfModule&gt;</pre>
<h2>Continued Soon</h2>
<p>When I started writing this post, I didn&#8217;t realize how long it was going to be. Part two, which will include the other 9 easier-to-implement and less important rules, should be up within a few days. I&#8217;ll also include some before-and-after performance statistics.</p>
<p>Part two is now finished: <a href="http://blog.shadypixel.com/using-yslow-to-optimize-web-site-performance-continued/">Using YSlow to Optimize Web Site Performance Continued</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.shadypixel.com/using-yslow-to-optimize-web-site-performance/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Firefox 3 Native Form Widgets Look Terrible</title>
		<link>http://blog.shadypixel.com/firefox-3-native-form-widgets-look-terrible/</link>
		<comments>http://blog.shadypixel.com/firefox-3-native-form-widgets-look-terrible/#comments</comments>
		<pubDate>Tue, 06 Jan 2009 19:03:38 +0000</pubDate>
		<dc:creator>btmorex</dc:creator>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[css]]></category>
		<category><![CDATA[development]]></category>
		<category><![CDATA[firefox]]></category>
		<category><![CDATA[forms]]></category>

		<guid isPermaLink="false">http://blog.shadypixel.com/?p=149</guid>
		<description><![CDATA[Firefox 3 added native form widgets on Linux. Most of the time they look great, but on some sites including mine, they look awful. Here's how I styled my forms to avoid native widgets.]]></description>
			<content:encoded><![CDATA[<p>Actually, the native widgets only look terrible if you&#8217;re on Linux with certain gtk+ themes and you&#8217;re viewing a web site with a dark background. Unfortunately, all of those conditions apply to me. See below:</p>
<div id="attachment_151" class="wp-caption alignnone" style="width: 256px"><a href="http://static.shadypixel.com/uploads/2009/01/native_widgets.png"><img class="size-full wp-image-151" title="Firefox 3 native widgets on Linux" src="http://static.shadypixel.com/uploads/2009/01/native_widgets.png" alt="Firefox 3 native widgets on Linux" width="246" height="111" /></a><p class="wp-caption-text">Firefox 3 native widgets on Linux</p></div>
<p>As you can see, there&#8217;s an ugly white box around the otherwise rounded widgets. Originally, I thought my CSS was lacking, but after hours&#8211;literally&#8211;of googling I determined that Firefox&#8217;s implementation of gtk+ widgets is just shoddy. Of course, on a site with a white background, they look great. I&#8217;m reminded of that Henry Ford quote: <em>&#8220;Any customer can have a car painted any colour that he wants as long as it is black.&#8221;</em></p>
<p>Applying any styling to the input elements will completely disable the native widgets. I ended up writing some basic CSS:</p>
<pre>input, textarea { border: 2px solid #888888; }
input:focus, textarea:focus {
	border-color: #D9D27C;
	background-color: #FFFBC4;
}</pre>
<p>They don&#8217;t look nearly as good as native widgets on a white background, but they look a whole lot better than native widgets on my site. See below:</p>
<div id="attachment_154" class="wp-caption alignnone" style="width: 255px"><a href="http://static.shadypixel.com/uploads/2009/01/styled_widgets.png"><img class="size-full wp-image-154" title="Basic styled widgets" src="http://static.shadypixel.com/uploads/2009/01/styled_widgets.png" alt="Basic styled widgets" width="245" height="103" /></a><p class="wp-caption-text">Basic styled widgets</p></div>
<p>I also added some input focus bling to the form:</p>
<div id="attachment_158" class="wp-caption alignnone" style="width: 255px"><a href="http://static.shadypixel.com/uploads/2009/01/styled_widget_with_focus.png"><img class="size-full wp-image-158" title="Text input with keyboard focus" src="http://static.shadypixel.com/uploads/2009/01/styled_widget_with_focus.png" alt="Text input with keyboard focus" width="245" height="103" /></a><p class="wp-caption-text">Text input with keyboard focus</p></div>
<p>Even though they look alright now, I&#8217;ve decided that my next major project on my blog should be a complete theme redesign. Traditional color schemes are easier to work with and I&#8217;ll also get familiar with a lot of WordPress PHP code.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.shadypixel.com/firefox-3-native-form-widgets-look-terrible/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Safely Removing External Drives in Linux</title>
		<link>http://blog.shadypixel.com/safely-removing-external-drives-in-linux/</link>
		<comments>http://blog.shadypixel.com/safely-removing-external-drives-in-linux/#comments</comments>
		<pubDate>Sun, 04 Jan 2009 22:47:20 +0000</pubDate>
		<dc:creator>btmorex</dc:creator>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[admin]]></category>
		<category><![CDATA[backup]]></category>
		<category><![CDATA[howto]]></category>

		<guid isPermaLink="false">http://blog.shadypixel.com/?p=128</guid>
		<description><![CDATA[Simply unmounting a filesystem is not the ideal way to remove an external USB/firewire/SATA drive in Linux. This tutorial explains why and gives a solution.]]></description>
			<content:encoded><![CDATA[<h3>Backstory</h3>
<p>About a year ago I bought an external SATA drive for backups. My normal usage consisted of:</p>
<ol>
<li>Power on and connect the drive</li>
<li>mount /media/backup</li>
<li>Run my backup script</li>
<li>umount /media/backup</li>
<li>Power off and unplug the drive</li>
</ol>
<p>This seemed to work pretty well&#8211;at the very least, I wasn&#8217;t losing data&#8211;except the drive made a strange sound when I powered it off. It wasn&#8217;t a normal drive spin down sound; it was louder and shorter. So, I googled for authoritative instructions on using external drives with Linux. While most sources suggest doing exactly what I did, it&#8217;s not ideal.</p>
<p>It turns out that most cheap external USB/SATA/firewire enclosures don&#8217;t properly issue a stop command to the drive when you flick the power switch. Instead, the power switch simply cuts power to the drive, which forces the drive to do an emergency head retract. If you think that sounds bad, you&#8217;re right. Emergency retracts aren&#8217;t going to brick your drive immediately, but if they occur regularly they&#8217;re putting a lot of unnecessary wear and tear on the drive. In fact, some drives monitor how often this happens with S.M.A.R.T. attribute 192. (Check <a href="http://en.wikipedia.org/wiki/S.M.A.R.T.">Wikipedia&#8217;s S.M.A.R.T. page</a> for a comprehensive list of attributes)</p>
<h3>Solution</h3>
<p>The solution is to spin down the drive via software before turning it off and unplugging it. The best way to do this is with a utility called <a href="http://llg.cubic.org/tools/">scsiadd</a>. This program can add and remove drives to Linux&#8217;s SCSI subsystem. Additionally, with fairly modern kernels, removing a device will issue a stop command, which is exactly what we&#8217;re looking for. Run:</p>
<p><code>$ sudo scsiadd -p</code></p>
<p>which should print something like:</p>
<pre>Attached devices:
Host: scsi0 Channel: 00 Id: 00 Lun: 00
  Vendor: ATA      Model: SAMSUNG HD300LJ  Rev: ZT10
  Type:   Direct-Access                    ANSI  SCSI revision: 05
Host: scsi4 Channel: 00 Id: 00 Lun: 00
  Vendor: LITE-ON  Model: DVDRW LH-20A1L   Rev: BL05
  Type:   CD-ROM                           ANSI  SCSI revision: 05
Host: scsi5 Channel: 00 Id: 00 Lun: 00
  Vendor: ATA      Model: WDC WD10EACS-00Z Rev: 01.0
  Type:   Direct-Access                    ANSI  SCSI revision: 05</pre>
<p>Identify the drive you want to remove and then issue:</p>
<p><code>$ sudo scsiadd -r <em>host</em> <em>channel</em> <em>id</em> <em>lun</em></code></p>
<p>substituting the corresponding values from the scsiadd -p output. For example, if I wanted to remove &#8220;WDC WD10EACS-00Z&#8221;, I would run:</p>
<p><code>$ sudo scsiadd -r 5 0 0 0</code></p>
<p>If everything works, scsiadd should print:</p>
<pre>Attached devices:
Host: scsi0 Channel: 00 Id: 00 Lun: 00
  Vendor: ATA      Model: SAMSUNG HD300LJ  Rev: ZT10
  Type:   Direct-Access                    ANSI  SCSI revision: 05
Host: scsi4 Channel: 00 Id: 00 Lun: 00
  Vendor: LITE-ON  Model: DVDRW LH-20A1L   Rev: BL05
  Type:   CD-ROM                           ANSI  SCSI revision: 05</pre>
<p>You can double-check the end of dmesg. You should see:</p>
<pre>[608188.235216] sd 5:0:0:0: [sdb] Synchronizing SCSI cache
[608188.235362] sd 5:0:0:0: [sdb] Stopping disk
[608188.794296] ata6.00: disabled</pre>
<p>At this point, the drive is removed from Linux&#8217;s SCSI subsystem and it should not be spinning. It&#8217;s safe to unplug and turn off.</p>
<p>Using scsiadd directly can be inconvenient because it requires looking up the host, channel, id, and lun of the drive. I wrote a short script that will take a normal Linux device file like /dev/sdb, figure out the correct arguments to scsiadd, and run scsiadd -r. I use this script in my larger backup script.</p>
<pre>#!/bin/sh

if [ $# -ne 1 ]; then
    echo "Usage: $0 &lt;device&gt;"
    exit 1
fi

if ! which lsscsi &gt;/dev/null 2&gt;&amp;1; then
    echo "Error: lsscsi not installed";
    exit 1
fi

if ! which scsiadd &gt;/dev/null 2&gt;&amp;1; then
    echo "Error: scsiadd not installed"
    exit 1
fi

device=`lsscsi | grep $1`
if [ -z "$device" ]; then
    echo "Error: could not find device: $1"
    exit 1
fi

hcil=`echo $device | awk \
    '{split(substr($0, 2, 7),a,":"); print a[1], a[2], a[3], a[4]}'`

scsiadd -r $hcil</pre>
<p>It does require the lsscsi command to be present on the system.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.shadypixel.com/safely-removing-external-drives-in-linux/feed/</wfw:commentRss>
		<slash:comments>11</slash:comments>
		</item>
		<item>
		<title>Monitoring Hard Drive Health on Linux with smartmontools</title>
		<link>http://blog.shadypixel.com/monitoring-hard-drive-health-on-linux-with-smartmontools/</link>
		<comments>http://blog.shadypixel.com/monitoring-hard-drive-health-on-linux-with-smartmontools/#comments</comments>
		<pubDate>Fri, 02 Jan 2009 11:18:09 +0000</pubDate>
		<dc:creator>btmorex</dc:creator>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[admin]]></category>
		<category><![CDATA[howto]]></category>
		<category><![CDATA[smart]]></category>

		<guid isPermaLink="false">http://blog.shadypixel.com/?p=83</guid>
		<description><![CDATA[S.M.A.R.T. is a system in modern hard drives designed to report conditions that may indicate impending failure. smartmontools is a free software package that can monitor S.M.A.R.T. attributes and run hard drive self-tests. Although smartmontools runs on a number of platforms, I will only cover installing and configuring it on Linux. Why Use S.M.A.R.T.? Basically, [...]]]></description>
			<content:encoded><![CDATA[<p><abbr title="Self-Monitoring, Analysis, and Reporting Technology">S.M.A.R.T.</abbr> is a system in modern hard drives designed to report conditions that may indicate impending failure. <a href="http://smartmontools.sourceforge.net/">smartmontools</a> is a free software package that can monitor S.M.A.R.T. attributes and run hard drive self-tests. Although smartmontools runs on a number of platforms, I will only cover installing and configuring it on Linux.</p>
<p><span id="more-83"></span></p>
<h3>Why Use S.M.A.R.T.?</h3>
<p>Basically, S.M.A.R.T. may give you enough of a warning that you can safely backup all your data before your hard drive dies. There is some amount of conflicting information on the internet about how reliable the warnings are. The best source of research that I found is a <a href="http://labs.google.com/papers/disk_failures.pdf">paper from Google</a> that describes an internal study of hard drive failure. A quick summary: certain events greatly increase the chance of hard drive failure including reallocation events and failed self-tests, but only about 60% of the drives that failed in the study had any negative S.M.A.R.T. attributes. Obviously, nothing replaces regular backups.</p>
<p>A good source for more information is the <a href="http://en.wikipedia.org/wiki/S.M.A.R.T.">S.M.A.R.T. wikipedia page</a>.</p>
<h3>Installation</h3>
<p>On Debian or Ubuntu systems:</p>
<p><code>$ sudo apt-get install smartmontools</code></p>
<p>On Fedora:</p>
<p><code>$ sudo yum install smartmontools</code></p>
<h3>Capabilities and Initial Tests</h3>
<p>smartmontools comes with two programs: smartctl which is meant for interactive use and smartd which continuously monitors S.M.A.R.T. Let&#8217;s look at smartctl first:</p>
<p><code>$ sudo smartctl -i /dev/sda</code></p>
<p>Replace /dev/sda with your hard drive&#8217;s device file in this command and all subsequent commands. If there&#8217;s only one hard drive in the system, it should be /dev/sda or /dev/hda. If this command fails, you may need to let smartctl know what type of hard drive interface you&#8217;re using:</p>
<p><code>$ sudo smartctl -d TYPE -i /dev/sda</code></p>
<p>where TYPE is usually one of ata, scsi, or sat (for serial ata). See the smartctl man page for more information. Note that if you need -d here, you will need to add it to all smartctl commands. This should print information similar to:</p>
<pre>=== START OF INFORMATION SECTION ===
Model Family:     SAMSUNG SpinPoint T133 series
Device Model:     SAMSUNG HD300LJ
Serial Number:    S0D7J1UL303628
Firmware Version: ZT100-12
User Capacity:    300,067,970,560 bytes
Device is:        In smartctl database [for details use: -P show]
ATA Version is:   7
ATA Standard is:  ATA/ATAPI-7 T13 1532D revision 4a
Local Time is:    Fri Jan  2 03:08:20 2009 EST
SMART support is: Available - device has SMART capability.
SMART support is: Enabled</pre>
<p>Now that smartctl can access the drive, let&#8217;s turn on some features. Run the following command:</p>
<p><code>$ sudo smartctl -s on -o on -S on /dev/sda</code></p>
<ul>
<li><strong>-s on</strong>: This turns on S.M.A.R.T. support or does nothing if it&#8217;s already enabled.</li>
<li><strong>-o on</strong>: This turns on offline data collection. Offline data collection periodically updates certain S.M.A.R.T. attributes. Theoretically this could have a performance impact. However, from the smartctl man page:<br />
<blockquote><p>Normally, the disk will suspend offline testing while disk accesses are taking place, and then automatically resume it when the disk would otherwise be idle, so  in  practice  it has little effect.</p></blockquote>
</li>
<li><strong>-S on</strong>: This enables &#8220;autosave of device vendor-specific Attributes&#8221;.</li>
</ul>
<p>The command should return:</p>
<pre>=== START OF ENABLE/DISABLE COMMANDS SECTION ===
SMART Enabled.
SMART Attribute Autosave Enabled.
SMART Automatic Offline Testing Enabled every four hours.</pre>
<p>Next, let&#8217;s check the overall health:</p>
<p><code>$ sudo smartctl -H /dev/sda</code></p>
<p>This command should return:</p>
<pre>=== START OF READ SMART DATA SECTION ===
SMART overall-health self-assessment test result: PASSED</pre>
<p>If it doesn&#8217;t return PASSED, you should immediately backup all your data. Your hard drive is probably failing. Next, let&#8217;s make sure that the drive supports self-tests. I have yet to see a drive that doesn&#8217;t, but the following command also gives time estimates for each test:</p>
<p><code>$ sudo smartctl -c /dev/sda</code></p>
<p>I won&#8217;t list the complete output because it&#8217;s somewhat lengthy. Make sure &#8220;Self-test supported&#8221; appears in the &#8220;Offline data collection capabilities&#8221; section. Also, look for output similar to:</p>
<pre>Short self-test routine
recommended polling time: 	 (   2) minutes.
Extended self-test routine
recommended polling time: 	 ( 127) minutes.</pre>
<p>These are rough estimates of how long the short and long self-test&#8217;s will take respectively. Let&#8217;s run the short test:</p>
<p><code>$ sudo smartctl -t short /dev/sda</code></p>
<p>On my drive, this test should take 2 minutes, but this obviously varies. You can run:</p>
<p><code>$ sudo smartctl -l selftest /dev/sda</code></p>
<p>to check results. Unfortunately, there&#8217;s no way to check progress, so just keep running that command until the results show up. A successful run will look like:</p>
<pre>=== START OF READ SMART DATA SECTION ===
SMART Self-test log structure revision number 1
Num  Test_Description    Status                  Remaining  LifeTime(hours)  LBA_of_first_error
# 1  Short offline       Completed without error       00%     21472         -</pre>
<p>Now, do the same for the long self-test:</p>
<p><code>$ sudo smartctl -t long /dev/sda</code></p>
<p>The long test can take a significant amount of time. You might want to run it overnight and check for the results in the morning. If either test fails, you should immediately backup all your data and read the last section of this guide.</p>
<h3>Configuring smartd</h3>
<p>We&#8217;ve now enabled some features and run the basic tests. Instead of repeating the previous section daily, we can setup smartd to do it all automatically. If your system has an /etc/smartd.conf file, check for a line that begins with DEVICESCAN. If you find one comment it out by adding a &#8216;#&#8217; to the beginning of the line. DEVICESCAN doesn&#8217;t work on my system and specifying a device file is easy. Add the following line to /etc/smartd.conf:</p>
<pre>/dev/sda -a -d sat -o on -S on -s (S/../.././02|L/../../6/03) -m root -M exec /usr/share/smartmontools/smartd-runner</pre>
<p>Here&#8217;s what each option does:</p>
<ul>
<li><strong>/dev/sda</strong>: Replace this with the device file you&#8217;ve been using in smartctl commands.</li>
<li><strong>-a</strong>: This enables some common options. You almost certainly want to use it.</li>
<li><strong>-d sat</strong>: On my system, smartctl correctly guesses that I have a serial ata drive. smartd on the other hand does not. If you had to add a &#8220;-d TYPE&#8221; parameter to the smartctl commands, you&#8217;ll almost certainly have to do the same here. If you didn&#8217;t, try leaving it out initially. You can add it later if smartd fails to start.</li>
<li><strong>-o on, -S on</strong>: These have the same meaning as the smartctl equivalents</li>
<li><strong>-s (S/../.././02|L/../../6/03)</strong>: This schedules the short and long self-tests. In this example, the short self-test will run daily at 2:00 A.M. The long test will run on Saturday&#8217;s at 3:00 A.M. For more information, see the smartd.conf man page.</li>
<li><strong>-m root</strong>: If any errors occur, smartd will send email to root. On my system, mail for root is forwarded to my normal email account. If you don&#8217;t have a similar setup, replace root with your normal email address. This option also requires a working email setup. Most Linux distributions automatically have working outbound email.</li>
<li><strong>-M exec /usr/share/smartmontools/smartd-runner</strong>: This last part may be specific to the Debian and Ubuntu smartmontools packages. Check if your system has /usr/share/smartmontools/smartd-runner. If it doesn&#8217;t, remove this option. Instead of sending email directly, &#8220;-M exec&#8221; makes smartd run a different command when errors occur. On Debian, smartd-runner will run each script in /etc/smartmontools/run.d/, one of which emails the user specified by the &#8220;-m&#8221; option.</li>
</ul>
<p>If you have more than one hard drive in your system, add a line for each one replacing /dev/sda with a different device file.</p>
<div class="update">
<p><strong>Update on 2009-01-06:</strong></p>
<p>Thanks to commenter robert for pointing out an omission on my part. If your system has the file /etc/default/smartmontools, uncomment the &#8220;#start_smartd=yes&#8221; line by removing the &#8220;#&#8221;.</p></div>
<p>Finally, restart smartd:</p>
<p><code>$ sudo /etc/init.d/smartmontools restart</code></p>
<p>If this command fails, the end of /var/log/daemon.log should have some diagnostic information. If smartd started fine, we should still test that email notifications are working. Add &#8220;-M test&#8221; to the end of the configuration line in /etc/smartd.conf. This will make smartd send out a test notification when it&#8217;s next started. Once again, restart smartd:</p>
<p><code>$ sudo /etc/init.d/smartmontools restart</code></p>
<p>You should receive an email similar to:</p>
<pre>This email was generated by the smartd daemon running on:

   host name: polar
  DNS domain: shadypixel.com
  NIS domain: (none)

The following warning/error was logged by the smartd daemon:

TEST EMAIL from smartd for device: /dev/sda

For details see host's SYSLOG (default: /var/log/syslog).</pre>
<p>Afterward, you can delete &#8220;-M test&#8221;.</p>
<h3>What To Do If smartd Detects Problems</h3>
<p>First, immediately backup everything. Depending on the error, your drive might be close to death or it may still have a long life ahead. Consult the <a href="http://smartmontools.sourceforge.net/faq.html">smartmontools FAQ</a>. It has some recommendations for specific errors. Otherwise, ask for help on the <a href="https://lists.sourceforge.net/lists/listinfo/smartmontools-support">smartmontools-support mailing list</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.shadypixel.com/monitoring-hard-drive-health-on-linux-with-smartmontools/feed/</wfw:commentRss>
		<slash:comments>62</slash:comments>
		</item>
		<item>
		<title>Updated awstats for Debian</title>
		<link>http://blog.shadypixel.com/updated-awstats-for-debian/</link>
		<comments>http://blog.shadypixel.com/updated-awstats-for-debian/#comments</comments>
		<pubDate>Tue, 30 Dec 2008 06:19:00 +0000</pubDate>
		<dc:creator>btmorex</dc:creator>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[awstats]]></category>
		<category><![CDATA[debian]]></category>

		<guid isPermaLink="false">http://blog.shadypixel.com/?p=67</guid>
		<description><![CDATA[The awstats package in Debian is pretty outdated. Etch has version 6.5. Sid has 6.7. Version 6.9 was released on December 28, 2008. I&#8217;m a statistics junky and the new version has better robot detection so I built an updated package on my lenny/sid machine: awstats_69-1_all.deb. This package also works perfectly on my etch server without [...]]]></description>
			<content:encoded><![CDATA[<p>The <a href="http://awstats.sourceforge.net/">awstats</a> package in Debian is pretty outdated. Etch has version 6.5. Sid has 6.7. Version 6.9 was released on December 28, 2008. I&#8217;m a statistics junky and the new version has better robot detection so I built an updated package on my lenny/sid machine: <a href="http://static.shadypixel.com/uploads/2008/12/awstats_69-1_all.deb">awstats_69-1_all.deb</a>. This package also works perfectly on my etch server without changes.</p>
<p>I did apply all the Debian patches that were still relevant so it should be the equivalent of the official Debian package.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.shadypixel.com/updated-awstats-for-debian/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>How to Shrink an LVM Volume Safely</title>
		<link>http://blog.shadypixel.com/how-to-shrink-an-lvm-volume-safely/</link>
		<comments>http://blog.shadypixel.com/how-to-shrink-an-lvm-volume-safely/#comments</comments>
		<pubDate>Sat, 30 Aug 2008 10:38:04 +0000</pubDate>
		<dc:creator>btmorex</dc:creator>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[admin]]></category>
		<category><![CDATA[howto]]></category>
		<category><![CDATA[lvm]]></category>

		<guid isPermaLink="false">http://blog.shadypixel.com/?p=63</guid>
		<description><![CDATA[Logical Volume Management is a vast improvement over standard partitioning schemes. Among many other things, it allows you to decrease the size of a volume without recreating it completely. Here&#8217;s how. First, as is always the case when you&#8217;re modifying disk volumes, partitions, or file systems, you should really have a recent backup. A typo [...]]]></description>
			<content:encoded><![CDATA[<p>Logical Volume Management is a vast improvement over standard partitioning schemes. Among many other things, it allows you to decrease the size of a volume without recreating it completely. Here&#8217;s how.</p>
<p><span id="more-63"></span></p>
<p>First, as is always the case when you&#8217;re modifying disk volumes, partitions, or file systems, you should really have a recent backup. A typo in one the following commands could easily destroy data. You have been warned!</p>
<p>All of the required steps must be performed on an unmounted volume. If want to reduce the size of a non-root volume, simply unmount it. For a root volume, you&#8217;ll have to boot from a CD. Any modern live or rescue CD should work fine. I prefer <a href="http://www.sysresccd.org/Main_Page">SystemRescueCD</a>. It includes almost any disk management programs you might need. After booting from a CD, you may have to issue:</p>
<p><code># vgchange -a y</code></p>
<p>This makes any logical volumes available to the Linux. Most boot CD&#8217;s will do it automatically some time during the boot process, but repeating the command won&#8217;t hurt. Next, force a file system check on the volume in question:</p>
<p><code># e2fsck -f /dev/polar/root</code></p>
<p>Device names for LVM volumes follow the convention: <code>/dev/&lt;volume group&gt;/&lt;logical volume&gt;</code>. In this case, my volume group is named polar and the volume I&#8217;m going to shrink is named root. This is a critical step; resizing a file system in an inconsistent state could have disastrous consequences. Next, resize the actual file system:</p>
<p><code># resize2fs /dev/polar/root 180G</code></p>
<p>Replace 180G with about 90% of the size you want the final volume to be. For example, in this case, I want the final volume to be 200 gigabytes, so I&#8217;ll reduce the file system to 180 gigabytes. Why is this necessary? When we reduce the size of the actual volume in the next step, it&#8217;s critical that the new size is greater than or equal to the size of the file system. After reading the documentation for both <code>resizefs</code> and <code>lvreduce</code>, I still haven&#8217;t been able to find out whether they&#8217;re using standard computer gigabytes (1024^3 bytes) or drive manufacturer gigabytes (1000^3 bytes). In this case, the difference is very important. To be on the safe side, we&#8217;ll just shrink the file system a bit more than necessary and expand it to use the full space available later. Next, reduce the size of the logical volume:</p>
<p><code># lvreduce -L 200G /dev/polar/root</code></p>
<p>In this case, use the actual size you want to the volume to be. Finally, grow the file system so that it uses all available space on the logical volume:</p>
<p><code># resize2fs /dev/polar/root</code></p>
<p>That&#8217;s it. Enjoy your newly acquired free space.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.shadypixel.com/how-to-shrink-an-lvm-volume-safely/feed/</wfw:commentRss>
		<slash:comments>10</slash:comments>
		</item>
	</channel>
</rss><!-- Dynamic page generated in 0.394 seconds. --><!-- Cached page generated by WP-Super-Cache on 2011-12-26 17:40:16 -->

