<?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>Brandon&#039;s Blog &#187; Server Admin</title>
	<atom:link href="http://www.brandonturner.net/blog/category/server-admin/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.brandonturner.net/blog</link>
	<description>Random thoughts on web applications, software development and Linux</description>
	<lastBuildDate>Thu, 08 Apr 2010 01:47:55 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
		<item>
		<title>Convert an existing Windows installation to a Xen guest</title>
		<link>http://www.brandonturner.net/blog/2010/01/convert-windows-to-xen-guest/</link>
		<comments>http://www.brandonturner.net/blog/2010/01/convert-windows-to-xen-guest/#comments</comments>
		<pubDate>Wed, 20 Jan 2010 02:53:44 +0000</pubDate>
		<dc:creator>Brandon</dc:creator>
				<category><![CDATA[Server Admin]]></category>
		<category><![CDATA[virtualization]]></category>
		<category><![CDATA[xen]]></category>

		<guid isPermaLink="false">http://www.brandonturner.net/blog/?p=524</guid>
		<description><![CDATA[I&#8217;ve been dual booting Linux and Windows for as long as I&#8217;ve run Linux on the desktop. Recently I installed Xen on Ubuntu and subsequently decided to port my old Windows bare-metal install to a Xen domU. Running Windows as a Xen domU has several advantages, the most obvious being the ability to access Windows [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve been dual booting Linux and Windows for as long as I&#8217;ve run Linux on the desktop.  Recently I installed <a href="http://www.brandonturner.net/blog/2010/01/install-xen-ubuntu/">Xen on Ubuntu</a> and subsequently decided to port my old Windows bare-metal install to a Xen domU.</p>
<p>Running Windows as a Xen domU has several advantages, the most obvious being the ability to access Windows while running Linux.  Additionally, you can take advantage of features such as domain migration, save/restore and LVM snapshots.</p>
<p>In this article, I&#8217;ll walk through how I converted my existing Windows XP Professional bare-metal (normal) install to a Xen guest (domU).  In my setup, the Xen dom0 is running on an LVM volume on a separate physical disk from the original Windows installation.  I will show you how to move the original Windows installation to a LVM logical volume.  You will need a retail or volume Windows license.  Xen emulates different hardware that will cause you to have to reactivate Windows.  An OEM license is not allowed to move hardware.  While I&#8217;d argue the physical hardware is still the same, I&#8217;m sure there is some definition that says otherwise <img src='http://www.brandonturner.net/blog/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> .  Finally, I converted a Windows XP installation, but the same procedure should work with any NTFS-based Windows installation (Vista, 7, Server 2003, Server 2008).</p>
<p>One thing before we get started:  If you plan on following these directions please back up first!  You&#8217;ll be partitioning volumes, copying partitions, etc.  One slip of the finger and you can wipe your entire system.  So be careful and back up!</p>
<p><a name="windows-disk-layout"></a></p>
<h4>Windows Disk Layout</h4>
<p>Before we begin, let&#8217;s discuss the layout of a typical Windows hard drive.  The table below shows a hard drive with a single NTFS partition.</p>
<table>
<tr>
<th>Start Sector</th>
<th>End Sector</th>
<th>Start Cylinder</th>
<th>End Cylinder</th>
<th>Description</th>
</tr>
<tr>
<td>0</td>
<td>0</td>
<td>0</td>
<td>0</td>
<td><a href="http://en.wikipedia.org/wiki/Master_boot_record">Master Boot Record</a></tr>
<tr>
<td>63</td>
<td>x</td>
<td>1</td>
<td>Total cylinders &#8211; 1</td>
<td>NTFS Volume</td>
</tr>
</table>
<p>In order to boot Windows, three conditions concerning the NTFS partition must be met:</p>
<ol>
<li>The starting sector must be encoded in the partition&#8217;s volume boot sector at address 0x1c</li>
<li>The partition should not occupy the last disk cylinder.  This is not always true, but in some cases occupying the last cylinder can cause a BSOD.</li>
<li>The partition must be marked bootable
</ol>
<p>Keep this in mind for now.  We will see how it affects us later.</p>
<p><a name="xen-vbd"></a></p>
<h4>Set up Xen Virtual Block Device (VBD)</h4>
<p>In a paravirtualized Linux guest, Xen acts as a bootloader by assigning virtual block devices and starting the kernel.  In an HVM domain such as Windows we need a bootloader to start the domain.  I chose to use the use the default bootloader that comes Windows XP.</p>
<p>Bootloaders such as Grub and the Windows bootloader are stored in the Master Boot Record of a physical disk.  In order to emulate this in our Xen guest we will create a VBD that represents a physical disk.</p>
<p>Xen has several options for VBDs.  I&#8217;m using an LVM-backed VBD as it is slightly faster than a file-based VBD and allows me to take LVM snapshots.  Creating a logical volume is easy, but first we must determine what size to make it.</p>
<p>To meet the criteria in the <a href="#windows-disk-layout">previous section</a> for booting Windows, we need to have two disk cylinders more than are required for our NTFS partition.  To simplify this, just create a logical volume 25MB larger than your Windows&#8217; NTFS partition.</p>
<div class="prompt">
<span class="comment"># Create logical volume for our 50GB NTFS partition:</span><br />
<span class="comment"># &nbsp;&nbsp;50 * 1024 + 25 = 51225 MB</span><br />
$ <span class="cmd">sudo lvcreate -nwin_hda -L51225M vg</span>
</div>
<p><a name="partition-logical-volume"></a></p>
<h4>Partition Logical Volume</h4>
<p>Now we need to partition the logical volume we just created.  Why do we need to partition a partition?  Remember that the logical volume in dom0 represents a physical disk in domU.  We need to partition this virtual disk, add a MBR and clone our NTFS volume.  Luckily, everything in Linux behaves like a file so we will have no problems partitioning our logical volume.</p>
<div class="prompt">
<p>$ <span class="cmd">sudo fdisk /dev/vg/win_hda</span></p>
<p>Command (m for help): <span class="cmd">n</span><br />
Command action<br />
&nbsp;&nbsp;e  extended<br />
&nbsp;&nbsp;p  primary partition (1-4)<br />
<span class="cmd">p</span><br />
Partition number (1-4): <span class="cmd">1</span><br />
First cylinder (1-6530, default 1): <span class="cmd">1</span><br />
<span style="color: red;">Last cylinder should be one less than total cylinders:</span><br />
Last cylinder, +cylinders or +size{K,M,G} (1-6530, default 6530): <span class="cmd">6529</span></p>
<p>Command (m for help): <span class="cmd">a</span><br />
Partition number (1-4): <span class="cmd">1</span></p>
<p>Command (m for help): <span class="cmd">t</span><br />
Selected partition 1<br />
Hex code (type L to list codes): <span class="cmd">7</span><br />
Changed system type of partition 1 to 7 (HPFS/NTFS)</p>
<p>Command (m for help): <span class="cmd">w</span>
</div>
<p><a name="clone-ntfs-partition"></a></p>
<h4>Clone NTFS Partition</h4>
<p>Now it is time to copy our NTFS partition.  The simplest way to do this is by using <code>dd</code>.  </p>
<div class="prompt">
<span class="comment"># We offset the destination so that our NTFS partition starts at the beginning of the first cylinder</span><br />
$ <span class="cmd">sudo dd bs=512 if=/dev/sdc1 of=/dev/vg/win_hda seek=63</span>
</div>
<p>This could take a while.  Don&#8217;t worry if you don&#8217;t see anything, <code>dd</code> doesn&#8217;t display progress as it works.  If you are like me and would rather know how the clone is progressing, install <a href="http://dcfldd.sourceforge.net/">dcfldd</a> and use that instead.</p>
<p><a name="modify-ntfs-boot-sector"></a></p>
<h4>Modify NTFS Boot Sector</h4>
<p>If your original NTFS partition was the first partition on the disk, you may be able to skip this step, but it won&#8217;t hurt to check.</p>
<p>To satisfy the first condition in the <a href="#windows-disk-layout">Windows Disk Layout</a> section above, we need to make sure the starting disk sector is encoded in the NTFS boot sector of our NTFS partition.  If you have followed the previous steps, your starting sector is 63.  To verify this:</p>
<div class="prompt">
$ <span class="cmd">sudo fdisk -l -u /dev/vg/win_vma</span><br />
Disk /dev/vg/win_hda: 53.7 GB, 53716451328 bytes<br />
255 heads, 63 sectors/track, 6530 cylinders, total 104914944 sectors<br />
Units = sectors of 1 * 512 = 512 bytes<br />
Disk identifier: 0xe3f4562c</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Device Boot &nbsp;Start &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;End &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Blocks &nbsp;&nbsp;Id &nbsp;System<br />
/dev/vg1/win_hda1 &nbsp;&nbsp;* &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>63</b> &nbsp;&nbsp;104888384 &nbsp;&nbsp;&nbsp;52444161 &nbsp;&nbsp;&nbsp;7 &nbsp;HPFS/NTFS
</div>
<p>You will need to convert the starting address to hexadecimal and rearrange it:</p>
<ol>
<li>Convert 63 to hex: 0x3F</li>
<li>Left pad with 0s so you have 8 hexadecimal digits: 0x0000003F</li>
<li>Rearrange pairs so AB CD EF GH becomes GH EF CD AB: 0x3F000000</li>
</ol>
<p>Now using <code><a href="http://rigaux.org/hexedit.html">hexedit</a></code>, or the binary file editor of your choice, ensure the starting sector address is inserted into the NTFS partition&#8217;s boot sector at address 0x1C (remember the NTFS partition starts at sector 63, or byte address 0x7E00).</p>
<div class="prompt">
$ <span class="cmd">sudo hexedit /dev/vg/win_hda</span>
</div>
<p>Move to position 0x7E1C (0x7E00 + 0x001C).  In hexedit this is done by pressing <code>Enter</code>, typing <code>7E1C</code>, and pressing <code>Enter</code> again.  Now make sure the 4 bytes at 0x7E1C equal the rearranged pairs above.  If not, type the pairs.  To save and exit: <code>Ctrl+X</code>.  To exit without saving: <code>Ctrl+C</code>.</p>
<p><a name="fix-mbr"></a></p>
<h4>Fix Master Boot Record</h4>
<p>At this point you have a virtual disk (<code>/dev/vg/win_hda</code>) with a single NTFS partition containing your Windows installation.  Unfortunately it is not quite ready because there is no bootloader in in the MBR.  We can use the <a href="http://www.microsoft.com/resources/documentation/windows/xp/all/proddocs/en-us/bootcons_fixmbr.mspx?mfr=true"><code>fixmbr</code></a> command on the Windows XP CD to install a bootloader into our virtual disk&#8217;s MBR.</p>
<p>First, we need to create a configuration file for our Windows Xen guest.  Here is mine, YMMV:</p>
<pre class="brush: plain;">
kernel = &quot;/usr/lib/xen/boot/hvmloader&quot;
builder = 'hvm'

memory = 1024

name = &quot;winxp&quot;
vif = []

disk = [
    'phy:/dev/vg/win_hda,hda,w',
    'phy:/dev/cdrom,hdc:cdrom,r'
]

device_model = '/usr/lib/xen/bin/qemu-dm'
boot=&quot;dc&quot;
vnc=1
</pre>
<p>Place your Windows XP CD in your CD drive.  You will boot your Xen guest using this CD to access the <code>fixmbr</code> command.</p>
<div class="prompt">
$ <span class="cmd">sudo xm create /etc/xen/winxp.cfg</span>
</div>
<p>Boot from CD:<br />
<div id="attachment_568" class="wp-caption aligncenter" style="width: 590px"><a href="http://www.brandonturner.net/blog/wp-content/uploads/2010/01/boot-from-cd.png"><img src="http://www.brandonturner.net/blog/wp-content/uploads/2010/01/boot-from-cd.png" alt="Press any key to boot from CD" title="Boot from CD" width="580" height="322" class="size-full wp-image-568" /></a><p class="wp-caption-text">Press any key to boot from CD</p></div></p>
<p>At the Welcome to Setup screen, press <b>R</b> to enter the recovery console:<br />
<div id="attachment_571" class="wp-caption aligncenter" style="width: 590px"><a href="http://www.brandonturner.net/blog/wp-content/uploads/2010/01/enter-recovery-console.png"><img src="http://www.brandonturner.net/blog/wp-content/uploads/2010/01/enter-recovery-console.png" alt="Press R to enter the recovery console" title="Enter Recovery Console" width="580" height="319" class="size-full wp-image-571" /></a><p class="wp-caption-text">Press R to enter the recovery console</p></div></p>
<p>Log on to your Windows partition:<br />
<div id="attachment_572" class="wp-caption aligncenter" style="width: 590px"><a href="http://www.brandonturner.net/blog/wp-content/uploads/2010/01/login-windows-partition.png"><img src="http://www.brandonturner.net/blog/wp-content/uploads/2010/01/login-windows-partition.png" alt="Select your Windows partition" title="Log in to Windows Partition" width="580" height="319" class="size-full wp-image-572" /></a><p class="wp-caption-text">Log in to your Windows partition</p></div></p>
<p>Use the <code>fixmbr</code> command to add the Windows bootloader to the MBR.  Confirm the ominous warning message as you know what you are doing.<br />
<div id="attachment_580" class="wp-caption aligncenter" style="width: 590px"><a href="http://www.brandonturner.net/blog/wp-content/uploads/2010/01/fixmbr.png"><img src="http://www.brandonturner.net/blog/wp-content/uploads/2010/01/fixmbr.png" alt="Running fixmbr on the Xen virtual disk" title="fixmbr" width="580" height="238" class="size-full wp-image-580" /></a><p class="wp-caption-text">Running fixmbr on the Xen virtual disk</p></div></p>
<p><a name="boot-windows"></a></p>
<h4>Boot Windows</h4>
<p>At this point your Windows Xen guest domainU is ready to boot.  Simply reboot the domain:</p>
<div class="prompt">
$ <span class="cmd">sudo xm reboot winxp</span>
</div>
<p>Once your Windows guest boots it should recognize new hardware and want to reboot.  You will probably have to reactivate Windows at some point as well.  You should probably install the <a href="http://wiki.xensource.com/xenwiki/XenWindowsGplPv">Xen GPLPV</a> drivers as soon as possible.  It is probably also a good idea to remove drivers from your old hardware as they are no longer needed.</p>
<p>I recommend accessing your Xen guest over the Remote Desktop Protocol using <code><a href="http://www.rdesktop.org/">rdesktop</a></code> instead of over VNC.  You&#8217;ll find your Windows is much more responsive over RDP.</p>
<p>Congratulations, you&#8217;ve ported your previous Windows installation to a Xen guest.  Though it wasn&#8217;t a point-and-click migration, it&#8217;s still faster then reinstalling Windows and all of your apps from scratch.  </p>
<p>Let me know if you found any errors or found this useful.  Enjoy your new Xen setup.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.brandonturner.net/blog/2010/01/convert-windows-to-xen-guest/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Installing Xen on Ubuntu 9.10</title>
		<link>http://www.brandonturner.net/blog/2010/01/install-xen-ubuntu/</link>
		<comments>http://www.brandonturner.net/blog/2010/01/install-xen-ubuntu/#comments</comments>
		<pubDate>Sat, 16 Jan 2010 22:01:58 +0000</pubDate>
		<dc:creator>Brandon</dc:creator>
				<category><![CDATA[Server Admin]]></category>
		<category><![CDATA[ubuntu]]></category>
		<category><![CDATA[virtualization]]></category>
		<category><![CDATA[xen]]></category>

		<guid isPermaLink="false">http://www.brandonturner.net/blog/?p=493</guid>
		<description><![CDATA[Install Xen 3.4.2 on Ubuntu 9.10 Karmic Koala, converting an existing install to the Xen dom0. Karmic doesn't have Xen binaries but you can install from source.]]></description>
			<content:encoded><![CDATA[<p>Recently I switched to Ubuntu as the primary operating system on my desktop machine.  As part of the switch, I wanted to install Xen to virtualize some additional operating systems.  Xen provides very good performance when virtualizing Linux distributions due to <a href="http://en.wikipedia.org/wiki/Paravirtualization">paravirtualization</a>.  The latest versions can also virtualize certain unmodified guest operating systems on processors that support virtualization.</p>
<p>In a Xen setup, the Xen hypervisor runs directly on the hardware (bare-metal).  The first guest operating system (dom0) runs &#8220;on top&#8221; of Xen and has full access to the underlying hardware.  Additional guests (domU) also run on top of the Xen hypervisor, but with limited access to the underlying hardware.</p>
<p>Converting an existing Ubuntu install to a Xen dom0 install requires installing the Xen hypervisor.  In previous versions of Ubuntu this could easily be done <a href="https://help.ubuntu.com/community/Xen">using apt</a>.  Unfortunately no packages exist for Ubuntu 9.10 (Karmic Koala).  In this post I&#8217;ll describe the steps I took to install Xen from source on Karmic.  If you&#8217;d rather install via binary packages you&#8217;ll need to find a third-party repository.</p>
<h4>Install Xen hypervisor and tools</h4>
<div class="prompt">
<p><span class="comment"># In order to compile Xen, you must first install some build dependencies:</span><br />
<span class="cmd">$ sudo apt-get install bin86 bcc iasl uuid-dev libsdl-dev</span></p>
<p>$ <span class="cmd">cd /usr/src</span></p>
<p><span class="comment"># See <a href="http://www.xen.org/products/xen_source.html">http://www.xen.org/products/xen_source.html</a> for latest downloads</span><br />
$ <span class="cmd">wget <a href="http://bits.xensource.com/oss-xen/release/3.4.2/xen-3.4.2.tar.gz">http://bits.xensource.com/oss-xen/release/3.4.2/xen-3.4.2.tar.gz</a></span><br />
$ <span class="cmd">tar -xzf xen-3.4.2.tar.gz</span></p>
<p><span class="comment"># I created this small patch to adapt Xen to Ubuntu&#8217;s layout</span><br />
$ <span class="cmd">wget <a href="http://www.bltweb.net/patches/xen-3.4.2-ubuntu.patch">http://www.bltweb.net/patches/xen-3.4.2-ubuntu.patch</a></span><br />
<span class="comment"># or if you are using Xen 4.0:</span><br />
$ <span class="cmd">wget <a href="http://www.bltweb.net/patches/xen-4.0.0-ubuntu.patch">http://www.bltweb.net/patches/xen-4.0.0-ubuntu.patch</a></span></p>
<p>$ <span class="cmd">cd xen-3.4.2</span><br />
$ <span class="cmd">patch -p1 < ../xen-3.4.2-ubuntu.patch</span><br />
$ <span class="cmd">make dist-xen dist-tools dist-stubdom</span><br />
$ <span class="cmd">sudo make install-xen install-tools install-stubdom</span></p>
</div>
<h4>Install Xen Kernel Sources</h4>
<p>The stock Karmic kernel will not work when running as dom0 in Xen.  You must install a new kernel.  I chose to compile my own kernel.  Compiling a kernel is not for the faint of heart, but isn&#8217;t as hard as you might think.</p>
<p>You have two main choices when it comes to a dom0 kernel.  The Xen kernel or a dom0 <a href="http://wiki.xensource.com/xenwiki/XenParavirtOps">pv-ops kernel</a>.  Normally I would recommend using a pv-ops kernel.  The same pv-ops kernel can run on bare-metal or under the Xen hypervisor.  The pv-ops kernel is going to be the default in future versions of Xen and will most likely be included in the mainline Linux kernel soon.</p>
<p>Unfortunately, the pv-ops kernel will not work with binary graphics drivers provided by Nvidia.  Since I have an Nvidia graphics card (and want to use the binary drivers) I need to use the standard Xen kernel.  The standard Xen kernel is still version 2.6.18, however luckily Andrew Lyon maintains <a href="http://code.google.com/p/gentoo-xen-kernel/downloads/list">forward ported patches</a> for Gentoo that we can use on our Ubuntu install.</p>
<p>First things first, let&#8217;s get the kernel sources downloaded and patched:</p>
<div class="prompt">
<p>$ <span class="cmd">cd /usr/src</span></p>
<p><span class="comment"># Download the vanilla kernel sources from <a href="http://www.kernel.org/">http://www.kernel.org/</a></span><br />
$ <span class="cmd">wget <a href="http://www.kernel.org/pub/linux/kernel/v2.6/linux-2.6.31.8.tar.bz2">http://www.kernel.org/pub/linux/kernel/v2.6/linux-2.6.31.8.tar.bz2</a></span><br />
$ <span class="cmd">tar -xjf linux-2.6.31.8.tar.bz2</span><br />
$ <span class="cmd">mv linux-2.6.31.8 linux-2.6.31.8-xen0-amd64</span></p>
<p><span class="comment"># Download the forward ported xen patches from <a href="http://code.google.com/p/gentoo-xen-kernel/downloads/list">http://code.google.com/p/gentoo-xen-kernel/downloads/list</a></span><br />
$ <span class="cmd">wget <a href="http://gentoo-xen-kernel.googlecode.com/files/xen-patches-2.6.31-10.tar.bz2">http://gentoo-xen-kernel.googlecode.com/files/xen-patches-2.6.31-10.tar.bz2</a></span><br />
$ <span class="cmd">mkdir xenpatches-v10_2.6.31.8</span><br />
$ <span class="cmd">cd xenpatches-v10_2.6.31.8</span><br />
$ <span class="cmd">tar -xjf ../xen-patches-2.6.31-10.tar.bz2</span><br />
$ <span class="cmd">cd ../</span></p>
<p><span class="comment"># Apply the xen patches</span><br />
$ <span class="cmd">cd linux-2.6.31.8-xen0-amd64</span><br />
$ <span class="cmd">for i in `ls ../xenpatches-v10_2.6.31.8/`; do patch -p1 < ../xenpatches-v10_2.6.31.8/"$i"; done</span></p>
</div>
<p>At this point I like to modify the kernel&#8217;s &#8220;extra version&#8221; to clearly identify that this is a dom0 kernel.  To do this, modify the Makefile using your favorite text editor and change the EXTRAVERSION line to look like:</p>
<pre class="brush: bash; highlight: [4];">
VERSION = 2
PATCHLEVEL = 6
SUBLEVEL = 31
EXTRAVERSION = .8-xen0-amd64
NAME = Man-Eating Seals of Antiquity
...
</pre>
<h4>Compile Xen Kernel</h4>
<p>Configuring your kernel is <i>left as an exercise for the reader</i>.  There is a ton of existing documentation on how to do this.  The easiest way to get started is to copy the configuration from the stock Ubuntu kernel and run make menuconfig.</p>
<div class="prompt">
$ <span class="cmd">cp /boot/config-2.6-31-17-generic .config</span><br />
$ <span class="cmd">make menuconfig</span>
</div>
<p>There are some options that you want to be sure you enable:</p>
<pre class="prompt">
Processor type and features --->
  [*] Enable Xen compatible kernel
Networking support --->
  Networking options --->
    &lt;*> 802.1d Ethernet Bridging
Device Drivers --->
  XEN --->
    [*] Privileged Guest (domain 0)
    &lt;M> Backend driver support
    &lt;M>   Block-device backend driver
    &lt;M>   Block-device tap backend driver
    &lt;M>   Block-device tap backend driver 2
    &lt;M>   Network-device backend driver
    &lt;M>   PCI-device backend driver
    &lt;M>   SCSI backend driver
    &lt;M>   USB backend driver
    &lt;*> Block-device frontend driver
    &lt;*> Network-device frontend driver
    &lt;M> SCSI frontend driver
    &lt;M> USB frontend driver
    &lt;*> Framebuffer-device frontend driver
    &lt;*>   Keyboard-device frontend driver
    [*] Disable serial port drivers
    &lt;*> Export Xen attributes in sysfs
        Xen version compatibility (3.3.0 and later) --->
           3.3.0 and later
</pre>
<p>Now compile and install your kernel:</p>
<div class="prompt">
<span class="comment"># To speed up the compile, set CONCURRENCY_LEVEL to one higher than the number of processor cores in your machine</span><br />
$ <span class="cmd">export CONCURRENCY_LEVEL=5</span><br />
$ <span class="cmd">make</span><br />
$ <span class="cmd">sudo make install</span><br />
$ <span class="cmd">sudo make modules_install</span></p>
<p><span class="comment"># Make an initramfs</span><br />
$ <span class="cmd">sudo mkinitramfs -o /boot/initrd.img-2.6.31.8-xen0-amd64 2.6.31.8-xen0-amd64</span>
</div>
<p>If you compiled the Xen net, block and usb backend drivers as modules, you will probably want to load them by default by adding them to your <code>/etc/modules</code> file:</p>
<pre class="brush: plain;">
# /etc/modules
...
# These modules are required for Xen DomUs to work
netbk
blkbk
usbbk
</pre>
<h4>Update Grub</h4>
<p>Most existing Xen documentation on the web refers to the first version of Grub.  Ubuntu 9.10 ships with Grub 2.  Grub 2 works great with Xen, unless you use fakeraid.  If you use fakeraid, I would suggest downgrading to Grub 1.</p>
<p>Ubuntu&#8217;s <code>update-grub</code> command won&#8217;t recognize your new Xen kernel, but you can easily modify the <code>/etc/grub.d/40_custom</code> script to manually insert it into your Grub configuration.  Here&#8217;s what my <code>40_custom</code> file looks like:</p>
<pre class="brush: bash;">
#!/bin/sh
exec tail -n +3 $0
# This file provides an easy way to add custom menu entries.  Simply type the
# menu entries you want to add after this comment.  Be careful not to change
# the 'exec tail' line above.

menuentry &quot;Ubuntu, Xen 3.4.2 dom0 2.6.31.8-xen0-amd64&quot; {
   set quiet=1
   insmod raid
   insmod mdraid
   insmod ext2
   set root=(md1)
   search --no-floppy --fs-uuid --set 31d4873b-fed1-49d9-b37d-89d9f7a46566
   multiboot (md1)/xen-3.4.2.gz vga=gfx-1440x900x32 quiet
   module (md1)/vmlinuz-2.6.31.8-xen0-amd64 root=/dev/mapper/vg0-root root=/dev/mapper/vg0-root ro quiet splash
   module (md1)/initrd.img-2.6.31.8-xen0-amd64
}
</pre>
<p>You will need to adjust this for your system.  You can use the <code>blkid</code> command to get the UUID for your disk partitions.  You might notice that I passed the <code>root=</code> parameter twice on the <code>module</code> line.  This may be a bug somewhere in Xen or Grub but I could not get anything to work when only including this parameter once.</p>
<p>You also need to update your default operating system.  You may want to wait until after you&#8217;ve verified everything works, but eventually you should edit <code>/etc/default/grub</code>.  Mine looks like:</p>
<pre class="brush: bash; highlight: [4];">
# If you change this file, run 'update-grub' afterwards to update
# /boot/grub/grub.cfg.

GRUB_DEFAULT=&quot;Ubuntu, Xen 3.4.2 dom0 2.6.31.8-xen0-amd64&quot;
#GRUB_DEFAULT=&quot;0&quot;
#GRUB_HIDDEN_TIMEOUT=1
GRUB_HIDDEN_TIMEOUT_QUIET=true
GRUB_TIMEOUT=&quot;3&quot;
GRUB_DISTRIBUTOR=`lsb_release -i -s 2&gt; /dev/null || echo Debian`
GRUB_CMDLINE_LINUX_DEFAULT=&quot;quiet splash&quot;
GRUB_CMDLINE_LINUX=&quot;&quot;

# The resolution used on graphical terminal
GRUB_GFXMODE=1440x900x32

# Uncomment if you don't want GRUB to pass &quot;root=UUID=xxx&quot; parameter to Linux
#GRUB_DISABLE_LINUX_UUID=true

# Uncomment to disable generation of recovery mode menu entrys
#GRUB_DISABLE_LINUX_RECOVERY=&quot;true&quot;

GRUB_DISABLE_OS_PROBER=true
</pre>
<p>Now run <code>update-grub</code>:</p>
<div class="prompt">
$ <span class="cmd">sudo update-grub</span>
</div>
<h4>Reboot</h4>
<p>Cross your fingers, it&#8217;s time to reboot into the Xen hypervisor and your new Xen kernel.  If you are lucky everything will work and you&#8217;ll soon be back to your desktop.  You may run into driver issues, in which case you&#8217;ll need to boot your original kernel and try your hand at reconfiguring and recompiling your kernel. </p>
<p>If you use Nvidia or ATI binary drivers they won&#8217;t work with the Xen kernel (yet).  Enabling these is a subject for another day, but it can be done.  For now, let&#8217;s stay focused on getting Xen fully installed and running.</p>
<p>After rebooting, you can check a couple of things:</p>
<div class="prompt">
$ <span class="cmd">uname -r</span><br />
<b>2.6.31.8-xen0-amd64</b><br />
$ <span class="cmd">sudo cat /proc/xen/capabilities</span><br />
<b>control_d</b>
</div>
<h4>Start Xen tools</h4>
<p>Once you are running the Xen hypervisor and a Xen compatible dom0 kernel, you need to start the Xen daemon.  This is done with:</p>
<div class="prompt">
$ <span class="cmd">sudo /etc/init.d/xend start</span>
</div>
<p>You can start this automatically by establishing sysvinit links with:</p>
<div class="prompt">
$ <span class="cmd">sudo update-rc.d xend start 20 2 3 4 5 . stop 80 0 1 6 .
</div>
<p>If you want Xen domUs in <code>/etc/xen/auto</code> to start automatically on boot, set the <code>xendomains</code> init script to run on boot:</p>
<div class="prompt">
$ <span class="cmd">sudo update-rc.d xendomains start 21 2 3 4 5 . stop 79 0 1 6 .
</div>
<h4>Compile a domU kernel</h4>
<p>This step is optional.  You may want to compile a kernel for use by your Linux domUs.  Many distributions can run as a domU with their stock kernel however if that doesn&#8217;t work you can configure them to use a Xen domU kernel.</p>
<p>Configuring a Xen domU kernel is similar to configuring a Xen dom0 kernel:</p>
<div class="prompt">
<p>$ <span class="cmd">cd /usr/src</span></p>
<p>$ <span class="cmd">tar -xjf linux-2.6.31.8.tar.bz2</span><br />
$ <span class="cmd">mv linux-2.6.31.8 linux-2.6.31.8-xenU-amd64</span></p>
<p><span class="comment"># Modify Makefile so EXTRAVERSION = .8-xenU-amd64</span></p>
<p>$ <span class="cmd">cp /boot/config-2.6-31-17-generic .config</span><br />
$ <span class="cmd">make menuconfig</span><br />
$ <span class="cmd">sudo make install</span><br />
$ <span class="cmd">sudo make modules_install</span>
</div>
<p>When configuring the domU kernel, you&#8217;ll want to make sure you enable:</p>
<pre class="prompt">
Processor type and features --->
  [*] Paravirtualized guest support --->
    [*] Xen guest support
Device drivers --->
  [*] Xen /dev/xen/evtchn device
  &lt;*> Xen filesystem
  [*] Create xen entries under /sys/hypervisor
</pre>
<h4>Ready for domUs</h4>
<p>Congratulations, your Ubuntu 9.10 Karmic Koala installation is now running as a domain 0 on top of the latest Xen hypervisor.  You are ready to start installing domUs.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.brandonturner.net/blog/2010/01/install-xen-ubuntu/feed/</wfw:commentRss>
		<slash:comments>90</slash:comments>
		</item>
		<item>
		<title>IPv6 support for qmail-jms1</title>
		<link>http://www.brandonturner.net/blog/2009/08/qmail-ipv6-jms1/</link>
		<comments>http://www.brandonturner.net/blog/2009/08/qmail-ipv6-jms1/#comments</comments>
		<pubDate>Fri, 07 Aug 2009 21:13:34 +0000</pubDate>
		<dc:creator>Brandon</dc:creator>
				<category><![CDATA[Server Admin]]></category>
		<category><![CDATA[ipv6]]></category>
		<category><![CDATA[qmail]]></category>

		<guid isPermaLink="false">http://www.brandonturner.net/blog/?p=462</guid>
		<description><![CDATA[This post is part of a series of posts dedicated to IPv6 support for qmail: Qmail IPv6 support tcpserver and rblsmtpd sslserver jgreylist jms1 combined patch IPv6 support in qmail Supporting IPv6 in qmail largely revolves around DNS lookups. Patches for tcpserver and sslserver allow incoming connections over IPv6. In order to support IPv6 in [...]]]></description>
			<content:encoded><![CDATA[<p>This post is part of a series of posts dedicated to IPv6 support for qmail:</p>
<ul class="noseparation">
<li><a href="/blog/2009/08/qmail-ipv6/">Qmail IPv6 support</a>
<ul class="noseparation">
<li><a href="/blog/2009/08/qmail-ipv6-tcpserver/">tcpserver and rblsmtpd</a></li>
<li><a href="/blog/2009/08/qmail-ipv6-sslserver/">sslserver</a></li>
<li><a href="/blog/2009/08/qmail-ipv6-jgreylist/">jgreylist</a></li>
<li><strong>jms1 combined patch</strong></li>
</ul>
</li>
</ul>
<h4>IPv6 support in qmail</h4>
<p>Supporting IPv6 in qmail largely revolves around DNS lookups.  Patches for <a href="/blog/2009/08/qmail-ipv6-tcpserver">tcpserver</a> and <a href="/blog/2009/08/qmail-ipv6-sslserver">sslserver</a> allow incoming connections over IPv6.  In order to support IPv6 in qmail:</p>
<ul class="noseparation">
<li>DNS lookups should prefer AAAA records, falling back to A records only if AAAA records are not available</li>
<li>All code referencing IP addresses should support IPv4 and IPv6 addresses</li>
<li>SPF queries should support IPv6 addresses</li>
</ul>
<h4>The fujiwara patch</h4>
<p>A <a href="http://member.wide.ad.jp/~fujiwara/files/qmail-1.03-v6-20021006.diff">qmail IPv6 patch</a> has existed since 2002 that covers the first two issues above.  It is written to apply cleanly on the base qmail-1.03 distributed on <a href="http://cr.yp.to/qmail.html">Daniel Bernstein&#8217;s site</a>.  It does not include support for SPF queries as SPF is not included in the original version of qmail.</p>
<h4>John Simpson&#8217;s combined patch</h4>
<p>I use John Simpson&#8217;s <a href="http://qmail.jms1.net/patches/combined.shtml">combined patch</a> for my qmail installs.  This patch adds support for <a href="http://www.openspf.org/">SPF</a> as well as many other things.  I have modified the fujiwara patch to apply on top of John&#8217;s combined patch as well as support SPF queries.</p>
<p>You can download my modified patch: <a href="http://www.bltweb.net/qmail/qmail-1.03-jms1.7.08-ipv6.patch">qmail-1.03-jms1.7.08-ipv6.patch</a>.  Installing it is simple:</p>
<div class="prompt">
$ <span class="cmd">wget <a href="http://cr.yp.to/software/qmail-1.03.tar.gz">http://cr.yp.to/software/qmail-1.03.tar.gz</a></span><br />
$ <span class="cmd">wget <a href="http://qmail.jms1.net/patches/qmail-1.03-jms1.7.08.patch">http://qmail.jms1.net/patches/qmail-1.03-jms1.7.08.patch</a></span><br />
$ <span class="cmd">wget <a href="http://www.bltweb.net/qmail/qmail-1.03-jms1.7.08-ipv6.patch">http://www.bltweb.net/qmail/qmail-1.03-jms1.7.08-ipv6.patch</a></span><br />
$ <span class="cmd">tar -xzf qmail-1.03.tar.gz</span><br />
$ <span class="cmd">mv qmail-1.03 qmail-1.03-jms1.7.08</span><br />
$ <span class="cmd">cd qmail-1.03-jms1.7.08</span><br />
$ <span class="cmd">patch &lt; ../qmail-1.03-jms1.7.08.patch</span><br />
$ <span class="cmd">patch -p1 &lt; ../qmail-1.03-jms1.7.08-ipv6.patch</span><br />
$ <span class="cmd">sed -ie 	&#8217;1s/$/ -DINET6/&#8217; conf-cc</span><br />
$ <span class="cmd">make</span><br />
$ <span class="cmd">make man</span><br />
$ <span class="cmd">sudo make setup check</span>
</div>
<h4>Configuration and running</h4>
<p>No special configuration is needed for this patch.</p>
<p>When applied, connections will prefer IPv6, transparently falling back to IPv4 if no IPv6 addresses are available.  This patch allows sending outbound messages over IPv6.  For inbound messages, you must apply the <a href="/blog/2009/08/qmail-ipv6-tcpserver/">tcpserver</a> or <a href="/blog/2009/08/qmail-ipv6-sslserver/">sslserver</a> patches.</p>
<p>Email addresses on my <code>bltweb.net</code> domain are IPv6 enabled thanks to a <a href="http://tunnelbroker.net">free IPv6 tunnel</a> provided by Hurricane Electric.  Feel free to send me an email once you are IPv6 enabled!</p>
<h4>Summary</h4>
<p>Feel free to leave any comments, corrections or questions below.  Remember Gentoo users can apply all of my qmail patches automatically by using the ebuilds in my <a href="/blog/gentoo-overlay/">gentoo-overlay</a>.</p>
<p>Once you have compiled qmail with IPv6 support, you should re-visit my main <a href="/blog/2009/08/qmail-ipv6/">qmail IPv6</a> post for information about testing and using your new IPv6 qmail install.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.brandonturner.net/blog/2009/08/qmail-ipv6-jms1/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>IPv6 support for jgreylist</title>
		<link>http://www.brandonturner.net/blog/2009/08/qmail-ipv6-jgreylist/</link>
		<comments>http://www.brandonturner.net/blog/2009/08/qmail-ipv6-jgreylist/#comments</comments>
		<pubDate>Fri, 07 Aug 2009 21:13:23 +0000</pubDate>
		<dc:creator>Brandon</dc:creator>
				<category><![CDATA[Server Admin]]></category>
		<category><![CDATA[ipv6]]></category>
		<category><![CDATA[qmail]]></category>

		<guid isPermaLink="false">http://www.brandonturner.net/blog/?p=456</guid>
		<description><![CDATA[In this post I describe how to modify jgreylist to support IPv6 connections.  This is one step to supporting IPv6 in qmail.]]></description>
			<content:encoded><![CDATA[<p>This post is part of a series of posts dedicated to IPv6 support for qmail:</p>
<ul class="noseparation">
<li><a href="/blog/2009/08/qmail-ipv6/">Qmail IPv6 support</a>
<ul class="noseparation">
<li><a href="/blog/2009/08/qmail-ipv6-tcpserver/">tcpserver and rblsmtpd</a></li>
<li><a href="/blog/2009/08/qmail-ipv6-sslserver/">sslserver</a></li>
<li><strong>jgreylist</strong></li>
<li><a href="/blog/2009/08/qmail-ipv6-jms1/">jms1 combined patch</a></li>
</ul>
</li>
</ul>
<h4>jgreylist Changes</h4>
<p><a href="http://qmail.jms1.net/scripts/jgreylist.shtml">jgreylist</a> is a program provided by John Simpson to allow <a href="http://en.wikipedia.org/wiki/Greylisting">greylisting</a> in qmail.  John provides two versions, one written in Perl, and one written in C.  I chose to only patch the C version.</p>
<p>jgreylist works by using the unix timestamps of empty files to track when individual IP address or class C blocks last visited your qmail server.  John does a great job of explaining how this works on his <a href="http://qmail.jms1.net/scripts/jgreylist.shtml">jgreylist</a> page.  You should understand how his program, especially the C version, works and is configured before continuing.</p>
<p>Normally, the IP addresses are stored in a directory such as <code>/var/qmail/jgreylist</code>.  Each byte of the IP address is stored in a directory so that the IP address 127.0.0.1 would be stored in <code>/var/qmail/jgreylist/127/000/000/001</code>.  To reduce the number of files needed, by default <code>jgreylist</code> actually only stores the first 3 bytes, so 127.0.0.1 would actually be stored in <code>/var/qmail/jgreylist/127/000/000</code>.  Which behavior <code>jgreylist</code> uses depends on the value of the <code>JGREYLIST_BY_IP</code> environment variable.</p>
<p>My patch changes the directory structure slightly.  All IPv4 addresses are stored inside an <code>ip4</code> directory.  IPv6 addresses are stored in an <code>ip6</code> directory.</p>
<p>IPv6 addresses are stored in directories for each byte in the address.  Unlike IPv4 addresses, each byte is represented in hex rather than decimal.  When <code>JGREYLIST_BY_IP</code> is a non-zero value, the entire address is stored.  Otherwise only the first 64 bits of the address is stored.  For example, the IPv6 <code>2001:470:1f0f:350::1</code> address would be stored in: <code>/var/qmail/jgreylist/ip6/20/01/04/70/1f/0f/03/50</code>.</p>
<h4>Download jgreylist with IPv6 support</h4>
<p>John distributes his <code>jgreylist</code> program using a single C file that you compile on your system.  I needed to pull in some additional files for the IPv6 stuff so I&#8217;ve repackaged John&#8217;s file with a Makefile and other dependencies.  This modified <code>jgreylist</code> must be run using an IPv6 patched <a href="/blog/2009/08/qmail-ipv6-tcpserver/">tcpserver</a> or <a href="/blog/2009/08/qmail-ipv6-sslserver">sslserver</a>.</p>
<p>You can download the package here: <a href="http://www.bltweb.net/qmail/jgreylist-0.8-ipv6.tar.gz">jgreylist-0.8-ipv6.tar.gz</a>.</p>
<p>Compiling and installing is easy:</p>
<div class="prompt">
$ <span class="cmd">wget <a href="http://www.bltweb.net/qmail/jgreylist-0.8-ipv6.tar.gz">http://www.bltweb.net/qmail/jgreylist-0.8-ipv6.tar.gz</a></span><br />
$ <span class="cmd">tar -xzf jgreylist-0.8-ipv6.tar.gz</span><br />
$ <span class="cmd">cd jgreylist-0.8-ipv6</span><br />
$ <span class="cmd">make</span><br />
$ <span class="cmd">sudo make install</span>
</div>
<p>After installing, you should follow John&#8217;s <a href="http://qmail.jms1.net/scripts/jgreylist.shtml">instructions</a> on configuring and running.</p>
<p>The <code>jgreylist-clean</code> perl script is included in the tar file above.  It required no changes.</p>
<h4>Summary</h4>
<p>If you have any comments, corrections or questions, feel free to post them below.  Remember Gentoo users can apply all of my qmail patches automatically by using the ebuilds in my <a href="/blog/gentoo-overlay/">gentoo-overlay</a>.  <code>jgreylist</code> is built in to the <code>qmail-jms1</code> ebuild, just use the <code>jgreylist<code> USE flag.</p>
<p>Once you've patched <code>jgreylist</code> you should move on to <a href="/blog/2009/08/qmail-ipv6-jms1/">patching qmail-jms1 or IPv6 support</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.brandonturner.net/blog/2009/08/qmail-ipv6-jgreylist/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>IPv6 support for sslserver</title>
		<link>http://www.brandonturner.net/blog/2009/08/qmail-ipv6-sslserver/</link>
		<comments>http://www.brandonturner.net/blog/2009/08/qmail-ipv6-sslserver/#comments</comments>
		<pubDate>Fri, 07 Aug 2009 21:13:14 +0000</pubDate>
		<dc:creator>Brandon</dc:creator>
				<category><![CDATA[Server Admin]]></category>
		<category><![CDATA[ipv6]]></category>
		<category><![CDATA[qmail]]></category>

		<guid isPermaLink="false">http://www.brandonturner.net/blog/?p=446</guid>
		<description><![CDATA[In this post I describe how to add IPv6 support to sslserver via a custom patch.  This is one step in enabling IPv6 support for qmail.]]></description>
			<content:encoded><![CDATA[<p>This post is part of a series of posts dedicated to IPv6 support for qmail:</p>
<ul class="noseparation">
<li><a href="/blog/2009/08/qmail-ipv6/">Qmail IPv6 support</a>
<ul class="noseparation">
<li><a href="/blog/2009/08/qmail-ipv6-tcpserver/">tcpserver and rblsmtpd</a></li>
<li><strong>sslserver</strong></li>
<li><a href="/blog/2009/08/qmail-ipv6-jgreylist/">jgreylist</a></li>
<li><a href="/blog/2009/08/qmail-ipv6-jms1/">jms1 combined patch</a></li>
</ul>
</li>
</ul>
<h4>ucspi-ssl</h4>
<p>The <a href="http://www.superscript.com/ucspi-ssl/index.html">ucspi-ssl</a> package provides the <code>sslserver</code> program.  <code>sslserver</code> accepts incoming SSL connections and passes them to another program such as <code>qmail-smtpd</code>.  <code>sslserver</code> is almost identical to tcpserver except that it deals with encrypted SSL traffic rather than clear text.</p>
<p>I could not find an IPv6 patch for <code>sslserver</code>, however I was able to port the <a href="/blog/2009/08/qmail-ipv6-tcpserver/">tcpserver patch</a> to <code>sslserver</code>.  You can easily apply my <a href="http://www.bltweb.net/qmail/ucspi-ssl-0.70-ipv6.patch">ucspi-ssl-0.70-ipv6.patch</a>:</p>
<div class="prompt">
$ <span class="cmd">wget <a href="http://www.superscript.com/ucspi-ssl/ucspi-ssl-0.70.tar.gz">http://www.superscript.com/ucspi-ssl/ucspi-ssl-0.70.tar.gz</a></span><br />
$ <span class="cmd">wget <a href="http://www.bltweb.net/qmail/ucspi-ssl-0.70-ipv6.patch">http://www.bltweb.net/qmail/ucspi-ssl-0.70-ipv6.patch</a></span><br />
$ <span class="cmd">tar -xzf ucspi-ssl-0.70.tar.gz</span><br />
$ <span class="cmd">cd host/superscript.com/net/ucspi-ssl-0.70</span><br />
$ <span class="cmd">patch -p1 < ../../../../ucspi-ssl-0.70-ipv6.patch</span><br />
$ <span class="cmd">package/compile</span><br />
$ <span class="cmd">sudo package/install</span>
</div>
<h4>sslserver</h4>
<p>To understand what the <code>sslserver</code> portion of the IPv6 patch does, you should be familiar with the <a href="http://www.superscript.com/ucspi-ssl/sslserver.html">sslserver man page</a> and read about how <code>tcpserver</code> handles IPv6 on <a href="http://www.fefe.de/ucspi/">Fefe&#8217;s ucspi-tcp</a> page.  Essentially, if a client connects via IPv4, <code>sslserver</code> exhibits it&#8217;s normal behavior.  If a client connects with IPv6, the <code>PROTO</code> environment variable will be set to &#8220;<code>SSL6</code>&#8221; instead of &#8220;<code>SSL</code>&#8220;.</p>
<p>The patch also supports using IPv6 addresses in your tcprules files.  A new rule may look like this:</p>
<div class="file">
# Don&#8217;t delay the greeting for my home server<br />
2001:470:1f0f:350::1:allow,GREETDELAY=&#8221;0&#8243;
</div>
<p>After applying this patch, you may notice that your logs are filled with addresses similar to: <code>::ffff:192.168.1.1</code>.  This is because internally <code>sslserver</code> treats every IP as an IPv6 address.  IPv4 addresses are represented using their <a href="http://en.wikipedia.org/wiki/IPv6#IPv4_mapped_addresses">IPv4 mapped address</a>.</p>
<h4>Summary</h4>
<p>If you have any comments, corrections, or questions, please feel free to leave a comment below.  Remember Gentoo users can apply all of my qmail patches automatically by using the ebuilds in my <a href="/blog/gentoo-overlay/">gentoo-overlay</a>.</p>
<p>Once you&#8217;ve patched <code>sslserver</code>, you should move on to <a href="/blog/2009/08/qmail-ipv6-jgreylist/">patching jgreylist for IPv6</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.brandonturner.net/blog/2009/08/qmail-ipv6-sslserver/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>IPv6 support for tcpserver and rblsmtpd</title>
		<link>http://www.brandonturner.net/blog/2009/08/qmail-ipv6-tcpserver/</link>
		<comments>http://www.brandonturner.net/blog/2009/08/qmail-ipv6-tcpserver/#comments</comments>
		<pubDate>Fri, 07 Aug 2009 21:13:07 +0000</pubDate>
		<dc:creator>Brandon</dc:creator>
				<category><![CDATA[Server Admin]]></category>
		<category><![CDATA[ipv6]]></category>
		<category><![CDATA[qmail]]></category>

		<guid isPermaLink="false">http://www.brandonturner.net/blog/?p=427</guid>
		<description><![CDATA[In this post I describe how to add IPv6 support to tcpserver and rblsmtpd via a custom patch.  This is one step in enabling IPv6 support for qmail.]]></description>
			<content:encoded><![CDATA[<p>This post is part of a series of posts dedicated to IPv6 support for qmail:</p>
<ul class="noseparation">
<li><a href="/blog/2009/08/qmail-ipv6/">Qmail IPv6 support</a>
<ul class="noseparation">
<li><strong>tcpserver and rblsmtpd</strong></li>
<li><a href="/blog/2009/08/qmail-ipv6-sslserver/">sslserver</a></li>
<li><a href="/blog/2009/08/qmail-ipv6-jgreylist/">jgreylist</a></li>
<li><a href="/blog/2009/08/qmail-ipv6-jms1/">jms1 combined patch</a></li>
</ul>
</li>
</ul>
<h4>ucspi-tcp</h4>
<p>The <a href="http://cr.yp.to/ucspi-tcp.html">ucspi-tcp</a> package provides the <code>tcpserver</code> and <code>rblsmtpd</code> programs.  <code>tcpserver</code> accepts incoming TCP connections and passes them to another program such as <code>qmail-smtpd</code>.  <code>rblsmtpd</code> blocks connections from RBL listed IPs.</p>
<p>Thanks to Fefe, a <a href="http://www.fefe.de/ucspi/">patch</a> has been around for a while that adds IPv6 support to <code>tcpserver</code>.  Fefe&#8217;s patch does not touch <code>rblsmtpd</code>, however.</p>
<p>I&#8217;ve modified Fefe&#8217;s patch to patch rblsmtpd as well.  You can easily apply my <a href="http://www.bltweb.net/qmail/ucspi-tcp-0.88-ipv6.patch">ucspi-tcp-0.88-ipv6.patch</a>:</p>
<div class="prompt">
$ <span class="cmd">wget <a href="http://cr.yp.to/ucspi-tcp/ucspi-tcp-0.88.tar.gz">http://cr.yp.to/ucspi-tcp/ucspi-tcp-0.88.tar.gz</a></span><br />
$ <span class="cmd">wget <a href="http://www.bltweb.net/qmail/ucspi-tcp-0.88-ipv6.patch">http://www.bltweb.net/qmail/ucspi-tcp-0.88-ipv6.patch</a></span><br />
$ <span class="cmd">tar -xzf ucspi-tcp-0.88.tar.gz</span><br />
$ <span class="cmd">cd ucspi-tcp-0.88</span><br />
$ <span class="cmd">patch -p1 < ../ucspi-tcp-0.88-ipv6.patch</span><br />
$ <span class="cmd">make</span><br />
$ <span class="cmd">sudo make install</span>
</div>
<h4>tcpserver</h4>
<p>To understand what the <code>tcpserver</code> portion of the IPv6 patch does, you should read <a href="http://www.fefe.de/ucspi/">Fefe&#8217;s ucspi-tcp</a> page.  Essentially, if a client connects via IPv4, <code>tcpserver</code> exhibits it&#8217;s normal behavior.  If a client connects with IPv6, the <code>PROTO</code> environment variable will be set to &#8220;<code>TCP6</code>&#8220;.</p>
<p>The patch also supports using IPv6 addresses in your tcprules files.  A new rule may look like this:</p>
<div class="file">
# Ignore RBL lookups for home server<br />
2001:470:1f0f:350::1:allow:RBLSMTPD=&#8221;"
</div>
<p>After applying this patch, you may notice that your logs are filled with addresses similar to: <code>::ffff:192.168.1.1</code>.  This is because internally <code>tcpserver</code> treats every IP as an IPv6 address.  IPv4 addresses are represented using their <a href="http://en.wikipedia.org/wiki/IPv6#IPv4_mapped_addresses">IPv4 mapped address</a>.</p>
<h4>rblsmtpd</h4>
<p>When patching <code>rblsmtpd</code> for IPv6 support, I had to decide how to lookup IPv6 addresses.  As far as I know, there aren&#8217;t any IPv6 blacklists yet.  There isn&#8217;t a spec on how these addresses should be queried.  My patch will use a new namespace, <code>ipv6</code>, when querying RBLs as described <a href="http://mail-archives.apache.org/mod_mbox/spamassassin-dev/200508.mbox/%3C136001c5a72c$39cf6560$7d25a8c0@watson1%3E">here</a>.  This means if you connect via <code>2001:470:1f0f:350::1</code>, a <code>TXT</code> DNS lookup will be made to:</p>
<div style="padding-left: 8px;" class="prompt">
1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.5.3.0.f.0.f.1.0.7.4.0.1.0.0.2.ipv6.rbl.example.org
</div>
<p>If anyone knows of a working RBL that differs, please let me know.</p>
<h4>Summary</h4>
<p>If you have any comments, corrections, or questions, please feel free to leave a comment below.  Remember Gentoo users can apply all of my qmail patches automatically by using the ebuilds in my <a href="/blog/gentoo-overlay/">gentoo-overlay</a>.</p>
<p>Once you&#8217;ve patched <code>tcpserver</code>, you should move on to <a href="/blog/2009/08/qmail-ipv6-sslserver/">patching ucspi-ssl (sslserver) for IPv6</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.brandonturner.net/blog/2009/08/qmail-ipv6-tcpserver/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Qmail IPv6</title>
		<link>http://www.brandonturner.net/blog/2009/08/qmail-ipv6/</link>
		<comments>http://www.brandonturner.net/blog/2009/08/qmail-ipv6/#comments</comments>
		<pubDate>Fri, 07 Aug 2009 21:12:56 +0000</pubDate>
		<dc:creator>Brandon</dc:creator>
				<category><![CDATA[Server Admin]]></category>
		<category><![CDATA[email]]></category>
		<category><![CDATA[ipv6]]></category>
		<category><![CDATA[qmail]]></category>

		<guid isPermaLink="false">http://www.brandonturner.net/blog/?p=423</guid>
		<description><![CDATA[In this series of posts I describe how to enable IPv6 support in qmail, including tcpserver, sslserver, rblsmtpd, qmail-smtpd, qmail-remote and jgreylist.]]></description>
			<content:encoded><![CDATA[<p>Adding IPv6 support to qmail can be a daunting task.  A <em>modern</em> qmail system includes several different components, with various patches and configuration options for each.  There are a few patches on the internet that claim to add IPv6 support for a specific component, but I had trouble finding patches for every piece of my qmail install.</p>
<p>I&#8217;m not trying to defend IPv6. I realize there are many people with strong feelings towards the subject, including <a href="http://cr.yp.to/djbdns/ipv6mess.html">qmail&#8217;s author</a>.  Switching to IPv6 is a monumental task.  It may never happen, but something needs to &#8211; we can&#8217;t keep NATing forever.</p>
<p>Many software projects have already added support for IPv6.  My Gentoo box has been on an IPv6 network, via Hurricane Electric&#8217;s free <a href="http://tunnelbroker.net">tunnel broker</a> service for a while now.  Mac OS X has support for IPv6, as do the latest versions of Windows.  Even Windows XP can support IPv6 if enabled.  <a href="http://www.postfix.org/IPV6_README.html">Postfix</a>, <a href="http://www.exim.org/exim-html-3.20/doc/html/spec_4.html#SEC24">Exim</a>, and <a href="http://www.sendmail.org/~ca/email/sm-810.html">Sendmail</a> all support IPv6.</p>
<p>In this series of posts, I will outline the steps I took to add IPv6 support to qmail.  I use John Simpson&#8217;s <a href="http://qmail.jms1.net/patches/combined-details.shtml">combined patch</a> for qmail as well as many other tools and methodologies described on his <a href="http://qmail.jms1.net/">site</a>, however many of the patches and instructions in these posts will work for other <em>versions</em> of qmail as well.</p>
<p><a name="components"></a></p>
<h4>Components</h4>
<p>John Simpson has an excellent illustration of a typical qmail system, <a href="http://qmail.jms1.net/qmail-system.pdf">Anatomy of a typical qmail system</a> [PDF], on his website.  The following articles describe the steps I took to enable IPv6 for each of the necessary components:</p>
<ul class="noseparation">
<li><a href="/blog/2009/08/qmail-ipv6-tcpserver/">tcpserver and rblsmtpd</a></li>
<li><a href="/blog/2009/08/qmail-ipv6-sslserver/">sslserver</a></li>
<li><a href="/blog/2009/08/qmail-ipv6-jgreylist/">jgreylist</a></li>
<li><a href="/blog/2009/08/qmail-ipv6-jms1/">jms1 combined patch</a></li>
</ul>
<p>For Gentoo users, the patches described in each of the above posts can be installed automatically using the ebuilds in my <a href="/blog/gentoo-overlay/">gentoo-overlay</a>.  For others, I&#8217;ve listed all the IPv6 patches on my <a href="http://www.bltweb.net/qmail/">qmail patches</a> page.</p>
<h4>Testing</h4>
<p>Testing your IPv6 enabled qmail setup can be a little confusing.  There aren&#8217;t that many IPv6 enabled mail servers out there.  Even worse, most people don&#8217;t have IPv6 connections.</p>
<p>Hurricane Electric provides a free <a href="http://tunnelbroker.net/">IPv6 tunnel broker</a> service that will allocate a /64 block of addresses that you can use.  I host my personal mail server on a <a href="http://www.linode.com/">Linode</a> which, despite being an excellent VPS, doesn&#8217;t have native IPv6.  To get around this I set up a tunnel broker and enabled AAAA entries in DNS.</p>
<p>To test my setup, I had to install two separate qmail installs on different servers.  Email addresses on my bltweb.net domain are now IPv6 enabled.  If you&#8217;d like to use them to test, feel free to shoot me an email.  Perhaps one day I&#8217;ll set up some type of reflector to automatically test.</p>
<h4>IPv6 email experience</h4>
<p>I&#8217;ve been running IPv6 mail servers at home and work for a few months now.  I haven&#8217;t been keeping detailed statistics, but for the most part the only connections I&#8217;ve seen over IPv6 thus far have been spam <img src='http://www.brandonturner.net/blog/wp-includes/images/smilies/icon_sad.gif' alt=':(' class='wp-smiley' /> </p>
<p>Still, enabling IPv6 in qmail wasn&#8217;t as hard as I thought it was going to be, thanks to the pre-existing patches on the internet.  Hopefully more and more companies will start to enable IPv6 on their networks, such as <a href="http://www.personal.psu.edu/dvm105/blogs/ipv6/2009/06/netflix-streaming-over-ipv6.html">Netflix</a>.  While email may still be even further out it never hurts to be ready.</p>
<p>Hopefully these posts have helped you add IPv6 support to your qmail install.  Feel free to leave comments or questions below and I&#8217;ll do my best to address them.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.brandonturner.net/blog/2009/08/qmail-ipv6/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>FastCGI with a PHP opcode cache benchmarks</title>
		<link>http://www.brandonturner.net/blog/2009/07/fastcgi_php_opcode_cache_benchmarks/</link>
		<comments>http://www.brandonturner.net/blog/2009/07/fastcgi_php_opcode_cache_benchmarks/#comments</comments>
		<pubDate>Wed, 29 Jul 2009 05:32:17 +0000</pubDate>
		<dc:creator>Brandon</dc:creator>
				<category><![CDATA[Server Admin]]></category>
		<category><![CDATA[apache]]></category>
		<category><![CDATA[apc]]></category>
		<category><![CDATA[benchmark]]></category>
		<category><![CDATA[fastcgi]]></category>
		<category><![CDATA[performance]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[suEXEC]]></category>

		<guid isPermaLink="false">http://www.brandonturner.net/blog/?p=377</guid>
		<description><![CDATA[mod_php and FastCGI performance is very comparable when an opcode cache is utilized.  These benchmarks cover performance and memory usage of mod_php vs FastCGI.]]></description>
			<content:encoded><![CDATA[<p>In my previous post, I described how to implement <a href="/blog/2009/07/fastcgi_with_php_opcode_cache/">FastCGI with a PHP opcode cache</a> on an Apache webserver.  My primary motivation for moving to FastCGI was to take advantage of the extra security provided by FastCGI with suEXEC over mod_php.  In this post, I&#8217;ll compare the two environments and provide a few benchmark results.</p>
<h4>Benchmark Setup</h4>
<p>To compare mod_php to FastCGI with a PHP opcode cache, I used the <a href="http://httpd.apache.org/docs/2.2/programs/ab.html">ab tool</a> on my desktop running PHP 5.3.0, mod_fastcgi 2.4.6 and Apache 2.2.11 on Gentoo linux.  Apache had a limited number of modules enabled (actions alias authz_host dav deflate dir expires filter headers log_config mime rewrite setenvif status vhost_alias).  The hardware consisted of a Intel Core2 Quad Q6600 (2 x 4MB L2 cache) with 2GB of RAM.</p>
<p>I chose to benchmark against the main page of a stock WordPress 2.8.2 install with no plugins enabled.  I chose WordPress because it&#8217;s extremely easy to set up and many people are familiar with it.  I&#8217;ve read that WordPress is very liberal with queries to the database (especially when plugins are involved).  Without database queries, I would expect to see a bigger difference between results with an opcode cache and results without one.  That being said, most PHP applications today make database queries as part of a typical request and thus I think these results are realistic of what you might experience on your server.</p>
<p>I executed the following command:</p>
<div class="prompt">
$ <span class="cmd">ab -n 1000 -c 30 http://localhost/</span>
</div>
<p>in four different environments:</p>
<ul>
<li>mod_php with a 30MB APC opcode cache (Apache MPM prefork)</li>
<li>mod_php without an opcode cache (Apache MPM prefork)</li>
<li>mod_fastcgi, suEXEC with a 30MB APC opcode cache (Apache MPM worker)</li>
<li>mod_fastcgi, suEXEC without an opcode cache (Apache MPM worker)</li>
</ul>
<p>Between each benchmark, I reconfigured and restarted the server.  I then loaded the main page in a web browser to prime the APC cache.</p>
<h4>Benchmark Results</h4>
<h5>Requests</h5>
<div id="attachment_385" class="wp-caption aligncenter" style="width: 590px"><a href="http://www.brandonturner.net/blog/wp-content/uploads/2009/07/requests_per_second.png"><img src="http://www.brandonturner.net/blog/wp-content/uploads/2009/07/requests_per_second.png" alt="Graph displaying requests per second of each benchmark scenario" title="Requests per second" width="580" height="300" class="size-full wp-image-385" /></a><p class="wp-caption-text">Requests per second</p></div>
<p>The graph above shows that mod_php and FastCGI behaved very similar in terms of requests per second.  Using an opcode cache increased the request rate by almost 3 times in both scenarios.  As I mentioned earlier, I&#8217;d expect to see an even bigger increase with fewer database queries.</p>
<p>I saw similar results when increasing the number of requests to 10,000, or changing the concurrency level.  I never saw any failed requests.  I was happy to see there wasn&#8217;t a significant performance difference moving from mod_php to FastCGI.</p>
<h5>Memory Usage</h5>
<div id="attachment_384" class="wp-caption aligncenter" style="width: 590px"><a href="http://www.brandonturner.net/blog/wp-content/uploads/2009/07/ram.png"><img src="http://www.brandonturner.net/blog/wp-content/uploads/2009/07/ram.png" alt="Graph displaying memory usage of each benchmark scenario" title="Memory usage" width="580" height="400" class="size-full wp-image-384" /></a><p class="wp-caption-text">Memory usage</p></div>
<p>The graph above shows the approximate memory usage for each of the 4 benchmarking scenarios.  This data was gathered by running the <a href="http://www.pixelbeat.org/scripts/ps_mem.py">ps_mem.py</a> script immediately after the ab tool completed.  This script outputs the private and shared memory usage for each program running on the system.  Because I ran my benchmarks in isolation, with nothing else accessing the host, these results should be pretty accurate.</p>
<p>The results surprised me.  From the graph you can see that disabling the opcode cache resulted in <em>more</em> memory usage.  I think this is misleading.  Typically, Linux keeps memory resident until it is needed by another process.  I believe the increased memory usage for the non-opcode cache scenarios is actually discarded memory that the Linux kernel hasn&#8217;t reclaimed.  Since each process is having to recompile the PHP script on each request, you see a lot more built up memory reported as private but most likely free to be reused.  I suspect running this on a low memory server would yield slightly different results.</p>
<p>You can clearly see the difference in memory usage for the Apache processes (green in the graph) between FastCGI and mod_php.  The FastCGI Apache processes are much leaner.  Since Apache doesn&#8217;t need the PHP bloat, it can serve static content much more effectively and quickly.</p>
<p>The scenarios with an opcode cache each used a similar amount of RAM.  There is a catch to these results however: I only benchmarked a single user.  In a shared environment, each user gets their own PHP instance and opcode cache.  With mod_php, all users share the same.  Thus I would expect every user to roughly double the RAM used in a FastCGI scenario, while mod_php memory usage would stay relatively constant.  This increased memory usage is the main trade-off when going with FastCGI.</p>
<h4>Raw Results</h4>
<p>For those who want even more detail, below are the raw results from my benchmark tests:</p>
<p>mod_php without an opcode cache:</p>
<pre class="brush: plain;">
This is ApacheBench, Version 2.3 &lt;$Revision: 655654 $&gt;
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking localhost (be patient)

Server Software:        Apache
Server Hostname:        localhost
Server Port:            80

Document Path:          /
Document Length:        5474 bytes

Concurrency Level:      30
Time taken for tests:   28.507 seconds
Complete requests:      1000
Failed requests:        0
Write errors:           0
Total transferred:      5717000 bytes
HTML transferred:       5474000 bytes
Requests per second:    35.08 [#/sec] (mean)
Time per request:       855.200 [ms] (mean)
Time per request:       28.507 [ms] (mean, across all concurrent requests)
Transfer rate:          195.85 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   0.2      0       2
Processing:   138  849 214.5    842    1608
Waiting:      138  848 214.3    842    1601
Total:        139  849 214.4    843    1608

Percentage of the requests served within a certain time (ms)
  50%    843
  66%    911
  75%    975
  80%   1004
  90%   1112
  95%   1230
  98%   1355
  99%   1426
 100%   1608 (longest request)
</pre>
<p>mod_php with opcode cache:</p>
<pre class="brush: plain;">
This is ApacheBench, Version 2.3 &lt;$Revision: 655654 $&gt;
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking localhost (be patient)

Server Software:        Apache
Server Hostname:        localhost
Server Port:            80

Document Path:          /
Document Length:        5474 bytes

Concurrency Level:      30
Time taken for tests:   10.784 seconds
Complete requests:      1000
Failed requests:        0
Write errors:           0
Total transferred:      5717000 bytes
HTML transferred:       5474000 bytes
Requests per second:    92.73 [#/sec] (mean)
Time per request:       323.530 [ms] (mean)
Time per request:       10.784 [ms] (mean, across all concurrent requests)
Transfer rate:          517.70 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   0.2      0       2
Processing:    66  319  62.9    316     580
Waiting:       66  318  62.9    316     580
Total:         67  319  62.8    316     580

Percentage of the requests served within a certain time (ms)
  50%    316
  66%    339
  75%    354
  80%    364
  90%    395
  95%    424
  98%    464
  99%    482
 100%    580 (longest request)
</pre>
<p>FastCGI without an opcode cache:</p>
<pre class="brush: plain;">
This is ApacheBench, Version 2.3 &lt;$Revision: 655654 $&gt;
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking localhost (be patient)

Server Software:        Apache
Server Hostname:        localhost
Server Port:            80

Document Path:          /
Document Length:        5474 bytes

Concurrency Level:      30
Time taken for tests:   28.170 seconds
Complete requests:      1000
Failed requests:        0
Write errors:           0
Total transferred:      5695000 bytes
HTML transferred:       5474000 bytes
Requests per second:    35.50 [#/sec] (mean)
Time per request:       845.104 [ms] (mean)
Time per request:       28.170 [ms] (mean, across all concurrent requests)
Transfer rate:          197.43 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   0.2      0       2
Processing:   105  832  82.9    832    1004
Waiting:      105  832  82.9    832    1004
Total:        107  832  82.8    832    1004

Percentage of the requests served within a certain time (ms)
  50%    832
  66%    856
  75%    873
  80%    882
  90%    908
  95%    927
  98%    954
  99%    971
 100%   1004 (longest request)
</pre>
<p>FastCGI with opcode cache:</p>
<pre class="brush: plain;">
This is ApacheBench, Version 2.3 &lt;$Revision: 655654 $&gt;
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking localhost (be patient)

Server Software:        Apache
Server Hostname:        localhost
Server Port:            80

Document Path:          /
Document Length:        5474 bytes

Concurrency Level:      30
Time taken for tests:   10.917 seconds
Complete requests:      1000
Failed requests:        0
Write errors:           0
Total transferred:      5695000 bytes
HTML transferred:       5474000 bytes
Requests per second:    91.60 [#/sec] (mean)
Time per request:       327.509 [ms] (mean)
Time per request:       10.917 [ms] (mean, across all concurrent requests)
Transfer rate:          509.44 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   0.2      0       2
Processing:    46  323  36.6    325     426
Waiting:       46  323  36.6    325     426
Total:         47  323  36.5    325     426

Percentage of the requests served within a certain time (ms)
  50%    325
  66%    335
  75%    342
  80%    346
  90%    359
  95%    368
  98%    383
  99%    389
 100%    426 (longest request)
</pre>
<p>Memory Usage (in MB):</p>
<table>
<tr>
<th rowspan="2">Benchmark</th>
<th colspan="3" style="text-align: center;">Apache</th>
<th colspan="3" style="text-align: center;">PHP</th>
<th rowspan="2">Total</th>
</tr>
<tr>
<th>private</th>
<th>shared</th>
<th>total</th>
<th>private</th>
<th>shared</th>
<th>total</th>
</tr>
<tr>
<th>mod_php, no cache</th>
<td>202.3</td>
<td>7.7</td>
<td>210</td>
<td></td>
<td></td>
<td></td>
<td><b>210</b></td>
</tr>
<tr>
<th>mod_php, with cache</th>
<td>45.3</td>
<td>15.5</td>
<td>60.8</td>
<td></td>
<td></td>
<td></td>
<td><b>60.8</b></td>
</tr>
<tr>
<th>FastCGI, no cache</th>
<td>9.2</td>
<td>3.3</td>
<td>12.5</td>
<td>68.3</td>
<td>5.0</td>
<td>73.3</td>
<td><b>85.8</b></td>
</tr>
<tr>
<th>FastCGI, with cache</th>
<td>9.2</td>
<td>3.6</td>
<td>12.8</td>
<td>23.4</td>
<td>13.8</td>
<td>37.2</td>
<td><b>50</b></td>
</tr>
</table>
<h4>Conclusion</h4>
<p>I run my blog on a <a href="http://www.linode.com/">Linode VPS</a> with a very limited amount of RAM.  I also host other applications and a few friends&#8217; sites on this same server.  Thus, I am very concerned about memory usage.  Still, the security advantages provided by FastCGI far outweigh the increased RAM usage.</p>
<p>I hope you have seen that the performance of FastCGI with an opcode cache is just as good as with mod_php.  It&#8217;s also evident how important an opcode cache is to running PHP scripts.</p>
<p>If you have any thoughts about these benchmarks, or the performance of FastCGI vs mod_php, feel free to leave a comment or question below!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.brandonturner.net/blog/2009/07/fastcgi_php_opcode_cache_benchmarks/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>FastCGI with a PHP APC Opcode Cache</title>
		<link>http://www.brandonturner.net/blog/2009/07/fastcgi_with_php_opcode_cache/</link>
		<comments>http://www.brandonturner.net/blog/2009/07/fastcgi_with_php_opcode_cache/#comments</comments>
		<pubDate>Tue, 07 Jul 2009 05:07:48 +0000</pubDate>
		<dc:creator>Brandon</dc:creator>
				<category><![CDATA[Server Admin]]></category>
		<category><![CDATA[apache]]></category>
		<category><![CDATA[apc]]></category>
		<category><![CDATA[fastcgi]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[suEXEC]]></category>

		<guid isPermaLink="false">http://www.brandonturner.net/blog/?p=320</guid>
		<description><![CDATA[Hosting PHP web applications in a shared environment usually involves a choice between two exclusive options: host a fast application by using a persistent opcode cache, or host an application that your shared neighbors can&#8217;t snoop around or destroy. In this post I discuss a way to get the best of both worlds, by combining [...]]]></description>
			<content:encoded><![CDATA[<p>Hosting PHP web applications in a shared environment usually involves a choice between two exclusive options: host a fast application by using a persistent opcode cache, or host an application that your shared neighbors can&#8217;t snoop around or destroy.  In this post I discuss a way to get the best of both worlds, by combining FastCGI with a single opcode cache per user.</p>
<p>This is a long post, ready to jump right in?  <a href="#implementation">Skip the history!</a></p>
<p><a name="mod_php"></a></p>
<h4>The evolution of mod_php to FastCGI</h4>
<p>In the early days of all-you-can eat shared hosting, administrators served PHP via mod_php.  mod_php loads the PHP interpreter into every web server process during server startup, thus alleviating the expense of starting an interpreter each time a script executes.  This allowed executing PHP scripts relatively fast.</p>
<p>mod_php came with a few drawbacks:</p>
<ul>
<li>Every server process, even those serving static files such as images and CSS scripts, contained the PHP interpreter.  This caused a lot of bloat in the web server&#8217;s memory footprint.  It also eliminated the ability to use mutil-threaded web servers as many PHP extensions are not thread safe.</li>
<li>Every PHP script ran as the same user as the web server.  While web servers typically run as a non-privileged user such as <em>nobody</em>, multiple mutually untrusting shared accounts could easily access, disrupt or destroy each other by executing a PHP script.</li>
</ul>
<p>FastCGI loads the PHP interpreter into a separate process.  This process is still persistent across connections, but, using a mechanism such as suEXEC, can run as a different user.  Static files can be served by a lightweight multi-threaded web server process while PHP scripts are served by a single-threaded FastCGI process.  What&#8217;s more, if PHP crashes, it doesn&#8217;t bring down the entire web server.</p>
<p>In the shared hosting context, each user&#8217;s PHP scripts are executed with the user&#8217;s credentials.  This leads to a more secure environment for both the host and the shared user.<br />
<a name="opcode"></a></p>
<h4>The opcode cache</h4>
<p>One of the easiest and most effective things you can do to speed up your PHP scripts is to enable an opcode cache such as <a href="http://www.php.net/apc/">APC</a>, <a href="http://xcache.lighttpd.net/">XCache</a> or <a href="http://eaccelerator.net/">eAccelerator</a>.  An opcode cache caches the compiled state of PHP scripts in shared memory.  Thus each time a PHP script is run, the server doesn&#8217;t have to waste time compiling the source code.  Opcode caches can speed up execution of scripts by up to 5 times and decrease server load.</p>
<p>In my opinion running PHP on a webserver without an opcode cache is like restarting your car&#8217;s engine at every stop sign.  You can still get where you&#8217;re going but it&#8217;s going to take longer and put a lot more wear and tear on your engine.  An opcode cache is so important that APC is going to be included in the core of PHP 6.</p>
<p>An opcode cache requires that the PHP interpreter process persist between connections.  Both mod_php and FastCGI satisfy this requirement.  An opcode cache requires RAM, a precious commodity on a shared hosting server.  By default, each cache allocates 30MB of shared memory.  This can be easily configured up or down depending on the scripts you are running.<br />
<a name="combine"></a></p>
<h4>Combining FastCGI with an opcode cache</h4>
<p>So if we agree that FastCGI and opcode caches are good (a must IMHO), why do most shared hosting providers only enable one?  The answer is two-fold:</p>
<ol>
<li>RAM.  Each opcode cache is typically 30MB.  Each PHP process gets its own opcode cache.  Each user must run its own PHP process for security.  Thus each user requires <em>at least</em> 30MB of RAM on top of the RAM required for the PHP interpreter (a lot).  All you can eat shared hosting companies typically oversell their servers.  Overselling usually works when it comes to bandwidth, I/O and CPU time, however overselling RAM is harder.  Remember the PHP processes stay in memory between connections.  So a small site only getting a 100 hits a day still hogs the same amount of RAM as a busy site.  This breaks the overselling model.</li>
<li>FastCGI.  In a typical configuration, FastCGI spawns many separate PHP processes per user.  Each PHP process needs its own opcode cache.  Instead of maintaining one opcode cache (per user), the server maintains multiple caches.  This reduces the effectiveness of the cache and increases the strain on server resources.</li>
</ol>
<p>Solving problem #1 is hard.  Some have suggested a single cache that can be shared across multiple processes and users and still provide assurance that different users cannot mess with each other.  This blog post is not about #1.  There are many reasons to use <em>unlimited</em> shared hosting providers.  Opcode caches are not one.</p>
<p>This blog post is about how to solve problem #2.  The goal is to have a reasonable system that utilizes suEXEC, FastCGI and the APC opcode cache.  Each user should have one and only one opcode cache.  The administrator should be able to adjust the size of the cache for each individual user based on their needs (and monthly fee).  Finally, the solution should decrease script load time and increase server performance while maintaining security and privacy between accounts.</p>
<p><a name="mod_fastcgi"></a></p>
<h4>mod_fastcgi vs mod_fcgid</h4>
<p>I run Apache on my server.  Many people suggest running a more lightweight server such as <a href="http://www.lighttpd.net/">lighttpd</a>.  One day I may switch, but for now I&#8217;ve tuned my Apache server to be as fast as I need.</p>
<p>There are two modules to implement FastCGI on Apache &#8211; <a href="http://www.fastcgi.com/mod_fastcgi/docs/mod_fastcgi.html">mod_fastcgi</a> and the newer <a href="http://fastcgi.coremail.cn/">mod_fcgid</a>.  Both are binary compatible with each other and do basically the same thing.  mod_fcgid sports better control over spawning processes and error detection.  mod_fastcgi has been around longer.  Both support suEXEC, and both separate PHP from Apache, thus allowing Apache to run threaded workers if desired.</p>
<p>As I mentioned in the <a href="#combine">combining FastCGI with an opcode cache</a> section, the typical behavior of FastCGI is to spawn multiple PHP interpreters.  The FastCGI process monitors each child process, kicking out processes with errors, restarting failed processes and sending incoming requests to the least busy child.  This is usually the preferred behavior, and mod_fcgid implements it particularly well.</p>
<p>Opcode caches throw a wrench in this however, because of their inability to share the cache across FastCGI processes.  Hopefully one day this will be <a href="http://pecl.php.net/bugs/bug.php?id=11988">remedied</a>.  Luckily, in the meantime, PHP is capable of playing &#8220;process manager&#8221; and a single PHP process can spawn several children to handle requests.  This way the parent PHP process can instantiate the opcode cache and its children can share it.  You&#8217;ll see this later when we set the PHP_FCGI_CHILDREN environment variable.</p>
<p>Both mod_fcgid and mod_fastcgi can be told to limit the number of PHP processes to 1 per user.  The PHP process can then be told how many children to spawn.  Unfortunately mod_fcgid will only send <strong>one request per child process</strong>.  The fact that PHP spawns its own children is ignored by mod_fcgid.  If we use mod_fcgid with our setup, we can only handle one concurrent PHP request.  This is not good.  A long running request could easily block multiple smaller requests.</p>
<p>mod_fastcgi <em>will</em> send multiple simultaneous requests to a single PHP process if the PHP process has children that can handle it.  This is the reason we <strong>must use mod_fastcgi</strong> to achieve our goal of one cache per user.</p>
<p><a name="implementation"></a></p>
<h4>Implementation</h4>
<p>This section describes the steps I took to enable suEXEC FastCGI with a single APC opcode cache per user on Apache 2.2.  These instructions may vary by Linux distribution and are not intended to be a cut-and-paste howto.  I use Gentoo, so most steps will be geared towards a Gentoo install but the general idea should work on any distribution.</p>
<p><a name="step_install_php_cgi"></a></p>
<h5>1.  Install php-cgi and disable mod_php</h5>
<p>The PHP interpreter can run in three different modes: as an Apache module, as a CGI binary or as a command line command.  Typically, separate binaries are built for the CGI and CLI modes, <code>php-cgi</code> and <code>php</code> respectively.  On Gentoo, each mode is associated with a USE flag: <code>apache2</code> for mod_php, <code>cgi</code> for a CGI binary, and <code>cli</code> for command-line PHP.  The <code>cgi</code> USE flag must be enabled.  If it isn&#8217;t, add it to <code>/etc/make.conf</code> or <code>/etc/portage/package.use</code> and recompile PHP.  On other distributions, search for a php-cgi binary.</p>
<p>You will want to disable mod_php (if it was enabled) before implementing FastCGI.  This can be done by commenting out the appropriate LoadModule line in your Apache configuration file:</p>
<div class="file">
# LoadModule php5_module modules/libphp5.so
</div>
<p>On Gentoo, this can be easily done by removing <code>PHP5</code> from the <code>APACHE2_OPTS</code> variable in <code>/etc/conf.d/apache2</code>.</p>
<p><a name="step_install_mod_fastcgi"></a></p>
<h5>2. Install and enable mod_fastcgi Apache module</h5>
<p>We already discussed why we <a href="#mod_fastcgi">must use mod_fastcgi instead of mod_fcgid</a>.  On Gentoo, installing mod_fastcgi can easily be done by running:</p>
<div class="prompt">
$ <span class="cmd">sudo emerge mod_fastcgi</span>
</div>
<p>For other distributions, try installing a mod_fastcgi package or see the <a href="http://www.fastcgi.com/mod_fastcgi/INSTALL.AP2">FastCGI Installation Notes</a>.</p>
<p>Make sure your Apache conf file contains the line:</p>
<div class="file">
LoadModule fastcgi_module modules/mod_fastcgi.so
</div>
<p>On Gentoo, this line is found in <code>/etc/apache/modules.d/20_mod_fastcgi.conf</code>.  mod_fastcgi is enabled by adding FASTCGI to the <code>APACHE2_OPTS</code> variable in <code>/etc/conf.d/apache2</code>.</p>
<p><a name="step_install_apc"></a></p>
<h5>3. Install and configure the APC Opcode Cache</h5>
<p>To install APC on Gentoo, simply run:</p>
<div class="prompt">
$ <span class="cmd">sudo emerge pecl-apc</span>
</div>
<p>For other distributions, see the <a href="http://www.php.net/manual/en/apc.installation.php">Alternative PHP Cache installation instructions</a>.</p>
<p>Once installed, look for the <code>apc.ini</code> file in your php extension configuration directory (e.g.  <code>/etc/php/cgi-php5/ext-active</code>).  The default apc.ini works with one exception.  You need to comment out <code>apc.shm_size="30"</code> (line 5 below).  Commenting this line will enable us to set it per user later.</p>
<p>My <code>apc.ini</code> file looks like:</p>
<pre class="brush: plain; highlight: [5];">
extension=apc.so
apc.enabled=&quot;1&quot;
apc.shm_segments=&quot;1&quot;
;commenting this out allows you to set it in each fastcgi process
;apc.shm_size=&quot;30&quot;
apc.num_files_hint=&quot;1024&quot;
apc.ttl=&quot;7200&quot;
apc.user_ttl=&quot;7200&quot;
apc.gc_ttl=&quot;3600&quot;
apc.cache_by_default=&quot;1&quot;
;apc.filters=&quot;&quot;
apc.mmap_file_mask=&quot;/tmp/apcphp5.XXXXXX&quot;
apc.slam_defense=&quot;0&quot;
apc.file_update_protection=&quot;2&quot;
apc.enable_cli=&quot;0&quot;
apc.max_file_size=&quot;1M&quot;
apc.stat=&quot;1&quot;
apc.write_lock=&quot;1&quot;
apc.report_autofilter=&quot;0&quot;
apc.include_once_override=&quot;0&quot;
apc.rfc1867=&quot;0&quot;
apc.rfc1867_prefix=&quot;upload_&quot;
apc.rfc1867_name=&quot;APC_UPLOAD_PROGRESS&quot;
apc.rfc1867_freq=&quot;0&quot;
apc.localcache=&quot;0&quot;
apc.localcache.size=&quot;512&quot;
apc.coredump_unmap=&quot;0&quot;
</pre>
<p><a name="step_enable_suexec"></a></p>
<h5>4. Install/enable Apache suEXEC</h5>
<p>Apache 2.2 contains built-in support for executing CGI programs as a different user id and group id than the webserver.  This support must be compiled into Apache.  On Gentoo, use the <code>suexec</code> USE flag and recompile apache.  On other distributions, see <a href="http://httpd.apache.org/docs/2.2/suexec.html#install">Configuring &#038; Installing suEXEC</a>.</p>
<p><a name="step_create_wrappers"></a></p>
<h5>5. Create wrapper scripts</h5>
<p>The <a href="http://httpd.apache.org/docs/2.2/suexec.html#model">Apache suEXEC security model</a> requires that the CGI binary meet some pretty stringent requirements concerning file ownership and permissions.  Rather than copying the php-cgi binary for each user, we create multiple wrapper scripts around the php-cgi binary.  These wrapper scripts allow us to set options on a per-user basis.</p>
<p>I keep my wrapper scripts in <code>/var/www/bin</code>, though you may keep yours wherever you want.  Each user has a directory in <code>/var/www/bin</code>, for example:</p>
<div class="prompt">
$ <span class="cmd">ls -l /var/www/bin</span><br />
dr-xr-xr-x 2 bob bob 104 Jun 24 13:56 bob/<br />
dr-xr-xr-x 2 sue     sue     104 Jun 24 13:56 sue/<br />
dr-xr-xr-x 2 joe      joe      104 Jun 24 13:53 joe/
</div>
<p>Inside each user&#8217;s bin directory is a single wrapper script, <code>php-fastcgi</code>:</p>
<div class="prompt">
$ <span class="cmd">ls -l /var/www/bin/bob/</span><br />
-r-xr-x&#8208;&#8208;&#8208; 1 bob bob 145 Jun 24 13:56 php-fastcgi
</div>
<p>I&#8217;ve shown the <code>ls -l</code> output to show the file and directory ownership and permissions.  These are important, and Apache suEXEC will not work correctly if the owner and permissions are not correct.</p>
<p>The contents of the <code>php-fastcgi</code> file in each user&#8217;s bin directory (see below for an explanation):</p>
<pre class="brush: bash;">
#!/bin/sh

PHP_FCGI_CHILDREN=5
export PHP_FCGI_CHILDREN
PHP_FCGI_MAX_REQUESTS=500
export PHP_FCGI_MAX_REQUESTS

umask 0022
exec /usr/bin/php-cgi -d apc.shm_size=25
</pre>
<p><b>PHP_FCGI_CHILDREN</b><br />
This variable tells PHP how many child processes it should spawn.  As we discussed earlier, our PHP process will act as &#8220;process manager&#8221; and pass incoming requests to its children.  The parent will maintain a single opcode cache which each child will share.  The PHP_FCGI_CHILDREN variable tells PHP how many children to spawn.  Another way to think of this is the number of concurrent PHP requests that can be handled per user.</p>
<p><b>PHP_FCGI_MAX_REQUESTS</b><br />
PHP is known for memory leaks in long running processes.  This variable causes each child process to be restarted once it has served a given number of requests (e.g. 500).  Only the child process is restarted, the parent process remains.  Since the parent process maintains the opcode cache, the opcode cache persists.</p>
<p><b>umask 0022</b><br />
This sets the umask the PHP binary will run under.  Some people may prefer a stricter umask such as 0077, however I&#8217;ve found 0022 works best as it allows the Apache server running as <em>nobody</em> to read static files written earlier by a suEXEC&#8217;d PHP process.  Some PHP applications (WordPress plugins) do not do a good job with permissions, and a strict umask can cause applications to fail.</p>
<p><b>exec /usr/bin/php-cgi -d apc.shm_size=25</b><br />
This line calls the php-cgi binary and modifies the APC cache size.  It is possible to configure this to use a separate <code>php.ini</code> file instead of setting configuration parameters on the command line, however I like the ability to share a single php.ini file.</p>
<p><a name="step_global_apache_settings"></a></p>
<h5>6. Edit global Apache settings</h5>
<p>There are two sets of settings you must configure in Apache: those that affect all users and those that affect a specific user.  This section describes global settings that affect all users.</p>
<p>I like to keep my global settings in my <code>/etc/apache/modules.d/20_mod_fastcgi.conf</code> file, but these can go in any part of your <code>http.conf</code> file.  Most of the time you do not want this in a <code>VirtualHost</code> section.  My global mod_fastcgi settings look like this (see below for an explanation):</p>
<pre class="brush: xml;">
&lt;IfDefine FASTCGI&gt;
LoadModule fastcgi_module modules/mod_fastcgi.so

FastCgiConfig -idle-timeout 20 -maxClassProcesses 1
FastCgiWrapper On

AddHandler php5-fcgi .php
Action php5-fcgi /cgi-bin/php-fastcgi

&lt;Location &quot;/cgi-bin/php-fastcgi&quot;&gt;
   Order Deny,Allow
   Deny from All
   Allow from env=REDIRECT_STATUS
   Options ExecCGI
   SetHandler fastcgi-script
&lt;/Location&gt;

&lt;/IfDefine&gt;
</pre>
<p><b>FastCgiConfig</b><br />
The <a href="http://www.fastcgi.com/drupal/node/25#FastCgiConfig">FastCgiConfig</a> configuration directive sets parameters for all dynamic FastCGI processes.  The idle-timeout causes FastCGI to abort a request if there is no activity for more than 20 seconds.  The maxClassProcesses option is very important: it tells FastCGI to only spawn one php-cgi process regardless of how many requests are pending.  Remember that our PHP process will spawn its own children, so FastCGI only needs to spawn one.  Until <a href="http://pecl.php.net/bugs/bug.php?id=11988">this APC bug</a> is fixed, this is necessary to allow sharing the APC cache among children.</p>
<p><b>FastCgiWrapper</b><br />
The <a href="http://www.fastcgi.com/drupal/node/25#FastCgiWrapper">FastCgiWrapper</a> configuration directive is needed to allow suEXEC to work.</p>
<p><b>AddHandler / Action</b><br />
The <a href="http://httpd.apache.org/docs/2.2/mod/mod_mime.html#addhandler">AddHandler</a> and <a href="http://httpd.apache.org/docs/2.2/mod/mod_actions.html#action">Action</a> configuration directives tell Apache to handle all files ending in <code>.php</code> with the <code>php-fastcgi</code> script in <code>cgi-bin</code>.  In the <a href="#step_user_apache_settings">next step</a>, you&#8217;ll see how we alias this cgi-bin directory for each individual user.</p>
<p><b>Location</b><br />
The <a href="http://httpd.apache.org/docs/2.2/mod/core.html#location">Location</a> directive tells Apache how to handle requests to <code>/cgi-bin/php-fastcgi</code>.  The <code>Allow from env=REDIRECT_STATUS</code> on line 13 prevents users from executing this script directly.  With this line, the only way to execute <code>php-fastcgi</code> is by requesting a file ending in <code>.php</code>.</p>
<p><a name="step_user_apache_settings"></a></p>
<h5>7. Edit per-user Apache settings</h5>
<p>On my host, every virtual host is associated with one user.  And every user has exactly one opcode cache.  A single user can have multiple virtual hosts, but these virtual hosts share the same opcode cache.</p>
<p>For each virtual host, I add the following lines, customized for the user associated with that virtual host:</p>
<pre class="brush: xml; highlight: [4,5,6,7];">
&lt;VirtualHost *:80&gt;
ServerName www.sue.bltweb.net
...
&lt;IfModule mod_fastcgi.c&gt;
   SuexecUserGroup sue sue
   Alias /cgi-bin/ /var/www/bin/sue/
&lt;/IfModule&gt;
...
&lt;/VirtualHost&gt;
</pre>
<p>When combined with the <a href="#step_global_apache_settings">global apache settings</a> and the <a href="#step_create_wrappers">wrapper scripts</a>, this will launch the php-cgi binary using suEXEC to execute as the appropriate user and group whenever a <code>.php</code> file is requested.</p>
<p>There are several different ways to call the FastCGI binary.  On my hosts, users don&#8217;t have access to their cgi-bin directory.  The /var/www/bin directory is not accessible by ordinary users.  This doesn&#8217;t have to be the case, the cgi-bin directory could be stored in the user&#8217;s directory.  It is important to note that allowing the user to modify php.ini values allows them to modify their opcode cache size, which could have severe repercussions on RAM usage.</p>
<h4>Pros and Cons</h4>
<p>The implementation described above is only one of many ways to implement FastCGI and APC.  In my opinion, it is the best way to meet my goals, but in this section I&#8217;ll try to outline some of the advantages and disadvantages of my setup.</p>
<h5>Advantages</h5>
<ul>
<li>Different users can have different APC cache sizes</li>
<li>Multiple concurrent PHP requests can be handled simultaneously</li>
<li>RAM usage is predictable as a product of the number of users on the host</li>
<li>Server is better secured against attacks from the inside since PHP processes run as the user who owns the script</li>
<li>Resource usage can be monitored since each user has a separate PHP process</li>
<li>A PHP crash doesn&#8217;t mean an Apache crash.  If a PHP process crashes it is restarted automatically.
</ul>
<h5>Disadvantages</h5>
<ul>
<li>The process manager built into mod_fastcgi isn&#8217;t used.  One of the motivations behind mod_fcgid was to improve upon the process manager in mod_fastcgi.</li>
<li>The newer mod_fcgid cannot be used as it will only send one request at a time to the PHP process, thus multiple requests can&#8217;t be handled simultaneously</li>
<li>Maintaining separate opcode caches per user uses a considerably larger amount of RAM than a single opcode cache used with mod_php</li>
<li>Users cannot alter php.ini files</li>
<li>If a PHP script crashes it has potential to take down all of the PHP requests currently being processed for that user
</ul>
<h4>Performance</h4>
<p>In my next post I&#8217;ll try to cover RAM usage, performance, benchmarks, compatibility and best practices.  This post is already way too long; I&#8217;m surprised you are even still reading it!</p>
<p>Stay tuned for more information on using FastCGI with a PHP APC opcode cache.  In the meantime let me know what you think of this approach.  Have you tried it?  Know of a better way?  Found any bugs or problems?  Leave a comment below!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.brandonturner.net/blog/2009/07/fastcgi_with_php_opcode_cache/feed/</wfw:commentRss>
		<slash:comments>28</slash:comments>
		</item>
		<item>
		<title>DKIM and DomainKeys for qmail</title>
		<link>http://www.brandonturner.net/blog/2009/03/dkim-and-domainkeys-for-qmail/</link>
		<comments>http://www.brandonturner.net/blog/2009/03/dkim-and-domainkeys-for-qmail/#comments</comments>
		<pubDate>Thu, 19 Mar 2009 05:13:21 +0000</pubDate>
		<dc:creator>Brandon</dc:creator>
				<category><![CDATA[Server Admin]]></category>
		<category><![CDATA[DKIM]]></category>
		<category><![CDATA[DomainKeys]]></category>
		<category><![CDATA[email]]></category>
		<category><![CDATA[howto]]></category>
		<category><![CDATA[qmail]]></category>

		<guid isPermaLink="false">http://www.brandonturner.net/blog/?p=134</guid>
		<description><![CDATA[This patch adds support for signing and verifying DKIM and DomainKeys signatures to qmail.]]></description>
			<content:encoded><![CDATA[<p><a href="http://domainkeys.sourceforge.net/">DomainKeys</a> and its successor <a href="http://www.dkim.org/">DomainKeys Identified Mail (DKIM)</a> are technologies that allow organizations to take responsibility for a message.  This is done by cryptographically signing an email as it leaves an organization in route to its destination.  The signature can be verified using the DNS system to establish trust.  In theory the technologies help cut down on spam by proving a message originated from the domain it says it does.</p>
<p>Support for DomainKeys in qmail has existed for a while thanks to a <a href="http://www.qmail.org/qmail-1.03-dk-0.53.patch">patch</a> by Russel Nelson.  Kyle Wheeler created a set of <a href="http://www.memoryhole.net/qmail/#dkim">wrapper scripts</a> that can be used to provide support for DKIM and DomainKeys.  Mihai Secasiu has some <a href="http://patchlog.com/security/qmail-and-dkim/">wrapper scripts</a> similar to Kyle&#8217;s that provide support for DKIM via the libdkim library instead of Perl&#8217;s <a href="http://search.cpan.org/~jaslong/Mail-DKIM-0.31/">Mail::DKIM</a> module.</p>
<p>The current methods take different approaches to implement DKIM and DomainKeys.  The DomainKeys patch creates a single program, <code>qmail-dk</code> that is called before <code>qmail-queue</code>.  This program signs or verifies all <em>incoming</em> messages (that may later become outbound) based on the existence of the <code>DKSIGN</code> and <code>DKVERIFY</code> variables.  The DKIM wrapper scripts wrap <code>qmail-remote</code> to sign messages and wrap <code>qmail-queue</code> (or <code>qmail-dk</code>) to verify incoming messages.  This can be easier understood by looking at the <a href="http://www.nrg4u.com/">qmail big picture</a>.</p>
<p>I tend to agree with separate programs for signing outbound messages and verifying inbound messages as this allows signing <em>all</em> outbound messages, even those (such as NDRs) that never pass through <code>qmail-queue</code>.  I also prefer patching qmail as it tends to be a little easier and requires less configuration after qmail is installed.</p>
<p>In this post I will show you how to patch qmail to support DKIM as well as DomainKeys.  My <a href="http://www.bltweb.net/qmail/qmail-1.03-jms1.7.08-dkim-r1.patch">qmail DKIM/DomainKeys patch</a> uses neither Russel Nelson&#8217;s DomainKeys patch nor Kyle Wheeler&#8217;s DKIM/DomainKey wrappers, but borrows ideas from both.  My patch uses the <a href="http://sourceforge.net/projects/domainkeys/">libdomainkeys</a> and <a href="http://sourceforge.net/projects/libdkim/">libdkim</a> libraries to do the actual signing and verifying.  Rather than creating two new programs, I patch <code>qmail-smtpd</code> (for verifying) and <code>qmail-remote</code> (for signing) directly.</p>
<p>I&#8217;ll do my best to provide step by step instructions for patching and installing for you non-Gentoo users, but in my next post I&#8217;ll share my ebuild which does it all for you.</p>
<p><a name="libdomainkeys"></a><br />
<h4>1. Install libdomainkeys</h4>
<p>The <code>libdomainkeys</code> library is used to sign and verify DomainKeys signatures.</p>
<div class="prompt">
$ <span class="cmd">wget <a href="http://downloads.sourceforge.net/domainkeys/libdomainkeys-0.69.tar.gz">http://downloads.sourceforge.net/domainkeys/libdomainkeys-0.69.tar.gz</a></span><br />
$ <span class="cmd">tar -xzf libdomainkeys-0.69.tar.gz</span><br />
$ <span class="cmd">cd libdomainkeys-0.69</span><br />
$ <span class="cmd">make</span><br />
<span style="color: red;">(If you get errors during <code>make</code>, edit the Makefile and add <code>-lresolv</code> to the end of the <code>LIBS</code> line)</span><br />
$ <span class="cmd">sudo install -m 644 libdomainkeys.a /usr/local/lib</span><br />
$ <span class="cmd">sudo install -m 644 domainkeys.h dktrace.h /usr/local/include</span><br />
$ <span class="cmd">sudo install -m 755 dknewkey /usr/local/bin</span><br />
$ <span class="cmd">cd ..</span>
</div>
<p><a name="libdkim"></a><br />
<h4>2. Install libdkim</h4>
<p>The <code>libdkim</code> library is used to sign and verify DKIM signatures.  You&#8217;ll need g++ to compile this on your system.  The library claims to be portable, but I needed to patch it to get it to compile on my Gentoo box.  I&#8217;ve also included a (slightly modified) patch from <a href="http://patchlog.com/security/qmail-and-dkim/">Mihai Secasiu</a> that makes working with libdkimtest much easier.</p>
<div class="prompt">
$ <span class="cmd">wget <a href="http://downloads.sourceforge.net/libdkim/libdkim-1.0.19.zip">http://downloads.sourceforge.net/libdkim/libdkim-1.0.19.zip</a></span><br />
$ <span class="cmd">wget <a href="http://www.bltweb.net/qmail/libdkim-1.0.19-linux.patch">http://www.bltweb.net/qmail/libdkim-1.0.19-linux.patch</a></span><br />
$ <span class="cmd">wget <a href="http://www.bltweb.net/qmail/libdkim-1.0.19-extra-options.patch">http://www.bltweb.net/qmail/libdkim-1.0.19-extra-options.patch</a></span><br />
$ <span class="cmd">unzip libdkim-1.0.19.zip</span><br />
$ <span class="cmd">cd libdkim/src</span><br />
$ <span class="cmd">patch -p2 < ../../libdkim-1.0.19-linux.patch</span><br />
$ <span class="cmd">patch -p2 < ../../libdkim-1.0.19-extra-options.patch</span><br />
$ <span class="cmd">make</span><br />
$ <span class="cmd">sudo make install</span><br />
$ <span class="cmd">cd ../..</span>
</div>
<p><a name="install_qmail"></a><br />
<h4>3. Patch and install qmail</h4>
<p>I&#8217;m currently using <a href="http://qmail.jms1.net/patches/combined.shtml">John Simpson&#8217;s qmail Combined Patch Set</a> for my qmail installation.  The instructions below highlight how to apply my DKIM/DomainKeys patch on top of John&#8217;s combined patch.  I&#8217;d highly recommend checking out John&#8217;s combined patch as it is about as close as you can get to an actively maintained qmail.</p>
<p>I&#8217;m <strong>not</strong> attempting to describe or document John&#8217;s patch in anyway in this post, as John runs an excellent site about qmail (<a href="http://qmail.jms1.net/">qmail.jms1.net</a>) that contains far more information than is contained here.  Do not attempt to proceed without reading through John&#8217;s documentation as well as the rest of this post.</p>
<div class="prompt">
$ <span class="cmd">wget <a href="http://cr.yp.to/software/qmail-1.03.tar.gz">http://cr.yp.to/software/qmail-1.03.tar.gz</a></span><br />
$ <span class="cmd">wget <a href="http://qmail.jms1.net/patches/qmail-1.03-jms1.7.08.patch">http://qmail.jms1.net/patches/qmail-1.03-jms1.7.08.patch</a></span><br />
$ <span class="cmd">wget <a href="http://www.bltweb.net/qmail/qmail-1.03-jms1.7.08-dkim-r1.patch">http://www.bltweb.net/qmail/qmail-1.03-jms1.7.08-dkim-r1.patch</a></span><br />
$ <span class="cmd">tar -xzf qmail-1.03.tar.gz</span><br />
$ <span class="cmd">mv qmail-1.03 qmail-1.03-jms1.7.08</span><br />
$ <span class="cmd">cd qmail-1.03-jms1.7.08</span><br />
$ <span class="cmd">patch < ../qmail-1.03-jms1.7.08.patch</span><br />
$ <span class="cmd">patch -p1 < ../qmail-1.03-jms1.7.08-dkim-r1.patch</span><br />
$ <span class="cmd">sed -ie 	&#39;1s/$/ -DDKIM/&#39; conf-cc</span><br />
$ <span class="cmd">make</span><br />
$ <span class="cmd">make man</span><br />
$ <span class="cmd">sudo make setup check</span><br />
$ <span class="cmd">cd ..</span>
</div>
<p><a name="sign"></a><br />
<h4>4. Configure DKIM/DomainKeys signing</h4>
<p>Signing is done by <code>qmail-remote</code> and is controlled by the <code>dksign</code> control file.  Signatures are created using a private key on your system, and verified by a public key stored in the DNS for the email domain.</p>
<h5>Generate keys</h5>
<p>Before you can sign an email, you must create at least one public/private key pair.  You should create key pairs for every domain you wish to sign.  To create keys for <code>example.com</code>:</p>
<div class="prompt">
# <span class="cmd">mkdir -p /etc/domainkeys/example.com</span><br />
# <span class="cmd">cd /etc/domainkeys/example.com</span><br />
# <span class="cmd">dknewkey default 1024 > default.pub</span><br />
# <span class="cmd">chown -R root:root /etc/domainkeys</span><br />
# <span class="cmd">chmod 640 /etc/domainkeys/example.com/default</span><br />
# <span class="cmd">chown root:qmail /etc/domainkeys/example.com/default</span>
</div>
<p>It is very important that the default file be readable only by <code>root</code> and the group which <code>qmailr</code> (the <code>qmail-remote</code> user) belongs to.  This is the private key used for signing messages and, if compromised, would allow others to sign messages as your domain.</p>
<p>Now add a <code>TXT</code> entry to the DNS for <code>default._domainkey.example.com</code> containing the quoted part in the <code>/etc/domainkeys/example.com/default.pub</code>.  NOTE: You normally want to include the quotes!</p>
<h5>Configure control files</h5>
<p>Create a file <code>/var/qmail/control/dksign</code> containing one line:</p>
<div class="file">
/etc/domainkeys/%/default
</div>
<p>The <code>%</code> will be replaced with the domain name in the <code>From:</code> header (or the <code>Sender:</code> header if it exists).  If no file exists for the given domain, parent domains will be tried.  For example if the message is from <code>foo@bar.example.com</code>, <code>/etc/domainkeys/bar.example.com/default</code> will be tested first.  If the file does not exist, <code>/etc/domainkeys/example.com/default</code> will be tested.  If no key can be found, the message will not be signed.  If a key exists, but cannot be read or contains invalid data, the message will not be sent and will remain in the queue until the problem is fixed.</p>
<p>If you do not create the <code>/var/qmail/control/dksign</code> file, no messages will be signed.</p>
<h5>Test outbound signing</h5>
<p>Now that DKIM/DomainKeys signing is configured, you can test it by sending an email to <code>sa-test (at) sendmail dot net</code>.  This reflector will reply (within seconds) to the envelope sender with a status of the DomainKeys and DKIM signatures.</p>
<p>If you experience problems, consult the <code>qmail-remote</code> man page or post a comment below and I&#8217;ll try to help.</p>
<p><a name="verify"></a><br />
<h4>5. Configure DKIM/DomainKeys verification</h4>
<p>Verification is performed by <code>qmail-smtpd</code> and is controlled by the <code>DKVERIFY</code> environment variable.  Messages are only verified if <code>DKVERIFY</code> is set and RELAYCLIENT is <strong>not</strong> set.  You may control which IP addresses are verified using the tcpserver access file (sometimes stored in <code>/etc/tcprules.d/tcp.qmail-smtp</code>).</p>
<p>When verifying a message, the contents of <code>DKVERIFY</code> are checked against the status of the DomainKeys and DKIM results.  Each test result is represented by a letter.  <code>DKVERIFY</code> should contain a series of letters for DomainKeys results, a comma, and then a series of letters for the DKIM results.  If the letter is uppercase, the message will be rejected (hard error).  If the letter is lowercase, the message will be deferred (soft error).  The <code>DKVERIFY</code> variable can be set but empty, in which case messages will be verified and an <code>Authentication-Results:</code> header will be added but <em>all</em> messages will be accepted regardless of status.</p>
<p>The letters for DomainKeys results are:</p>
<table>
<tr>
<th>Code</th>
<th>Status</th>
<th>Description</th>
</tr>
<tr>
<td>A</td>
<td>OK</td>
<td>The message contained a signature which correctly matched the contents of the message.</td>
</tr>
<tr>
<td>B</td>
<td>BADSIG</td>
<td>The message contained a signature which DID NOT correctly match the contents of the message. The signature may be forged, or the content may have been changed after the original server applied the signature.</td>
</tr>
<tr>
<td>C</td>
<td>NOSIG</td>
<td>The message did not contain a <code>DomainKey-Signature</code> header, or contained one which was missing a required field, or had a signature header without a &#8220;From:&#8221; header.</td>
</tr>
<tr>
<td>D</td>
<td>NOKEY</td>
<td>The public key needed to verify the signature does not exist (i.e. the authoritative DNS server for the domain says that the TXT record which should contain the key does not exist.)</td>
</tr>
<tr>
<td>E</td>
<td>BADKEY</td>
<td>The public key which was found in DNS is not usable.</td>
</tr>
<tr>
<td>F</td>
<td>CANTVRFY</td>
<td>The public key needed to verify the signature cannot be found, because the DNS server which should have the key is not responding, or returned a temporary error condition. The domainkeys specification says that the server SHOULD treat this as a soft error, telling the client to try their delivery again at some point in the future.</td>
</tr>
<tr>
<td>G</td>
<td>SYNTAX</td>
<td>The message is not in the proper format. This could be an improperly formatted email address, a duplicate &#8220;From:&#8221; header in the message, or any number of things which &#8220;confuse&#8221; the program.</td>
</tr>
<tr>
<td>H</td>
<td>NORESOURCE</td>
<td>Out of memory. The domainkeys specification says that the server SHOULD treat this as a soft error, telling the client to try their delivery again at some point in the future.</td>
</tr>
<tr>
<td>I</td>
<td>ARGS</td>
<td>Arguments are not usable</td>
</tr>
<tr>
<td>J</td>
<td>REVOKED</td>
<td>The key which was used to generate the signature has been revoked.</td>
</tr>
<tr>
<td>K</td>
<td>INTERNAL</td>
<td>There was an internal error in the libdomainkeys library</td>
</tr>
</table>
<p>The letters for the DKIM results are:</p>
<table>
<tr>
<th>Code</th>
<th>Status</th>
<th>Description</th>
</tr>
<tr>
<td>A</td>
<td>OK</td>
<td>The message contained a signature which correctly matched the contents of the message.</td>
</tr>
<tr>
<td>B</td>
<td>FAIL</td>
<td>The message failed verification</td>
</tr>
<tr>
<td>C</td>
<td>BAD_SYNTAX</td>
<td>The <code>DKIM-Signature</code> header could not be parsed or had bad tags/values</td>
</tr>
<tr>
<td>D</td>
<td>SIG BAD</td>
<td>RSA verify failed</td>
</tr>
<tr>
<td>E</td>
<td>SIG BAD (testing)</td>
<td>RSA verify failed but testing</td>
</tr>
<tr>
<td>F</td>
<td>SIG EXPIRED</td>
<td>Signature is expired (x= is old)</td>
</tr>
<tr>
<td>G</td>
<td>SELECTOR INVALID</td>
<td>Selector doesn&#8217;t parse or contains invalid values</td>
</tr>
<tr>
<td>H</td>
<td>SELECTOR MISMATCH</td>
<td>Selector granularity doesn&#8217;t match</td>
</tr>
<tr>
<td>I</td>
<td>SELECTOR REVOKED</td>
<td>The selector was revoked (p= is empty)</td>
</tr>
<tr>
<td>J</td>
<td>DOMAIN TOO LONG</td>
<td>The domain name is too long to request</td>
</tr>
<tr>
<td>K</td>
<td>DNS TEMP FAIL</td>
<td>Temporary DNS error requesting public key</td>
</tr>
<tr>
<td>L</td>
<td>DNS PERM FAIL</td>
<td>Permanent DNS error requestion public key</td>
</tr>
<tr>
<td>M</td>
<td>PUBLIC KEY INVALID</td>
<td>Public key isn&#8217;t valid or can&#8217;t be parsed</td>
</tr>
<tr>
<td>N</td>
<td>NO SIG</td>
<td>The message contains no DKIM signatures</td>
</tr>
<tr>
<td>O</td>
<td>NO VALID SIG</td>
<td>The message contains no valid signatures</td>
</tr>
<tr>
<td>P</td>
<td>BAD BODY HASH</td>
<td>The message body doesn&#8217;t verify</td>
</tr>
<tr>
<td>Q</td>
<td>ALGORITHM MISMATCH</td>
<td>The selector (h=) doesn&#8217;t match signature (a=)</td>
</tr>
<tr>
<td>R</td>
<td>STAT INCOMPAT</td>
<td>Incompatible v=</td>
</tr>
</table>
<p>I recommend a <code>DKVERIFY</code> value of <code><strong>DEGIJKfh,CGHIJMQRkl</strong></code>.  This will only reject improperly formatted messages.  Messages that don&#8217;t verify will still be allowed.  I would advise against rejecting messages that don&#8217;t verify as there are still some problems with DomainKeys and DKIM (such as mailing lists).  Rather than rejecting bad signatures, incorporate the <code>Authentication-Results</code> header into your broader spam prevention strategy.</p>
<h5>The <code>Authentication-Results</code> header</h5>
<p>All messages received by <code>qmail-smtpd</code> when <code>DKVERIFY</code> is set will add an <code>Authentication-Results</code> header to the incoming message.  This header conforms to the <a href="http://tools.ietf.org/html/draft-kucherawy-sender-auth-header-20">IETF internet draft</a>.  Here&#8217;s an example from one of my emails:</p>
<pre>Authentication-Results: bltweb.net; domainkeys=pass (ok); dkim=pass (ok)</pre>
<p><a name="examples"></a><br />
<h4>6. Examples</h4>
<p>Here are some examples to help you configure your box.  Anything that normally should be private is made up.</p>
<h5>Keys</h5>
<p>For my bltweb.net domain name, here&#8217;s what my keys look like (these are not the actual keys installed on my system, those are private):</p>
<div class="prompt">
$ <span class="cmd">ls -l /etc/domainkeys/bltweb.net</span><br />
total 8.0K<br />
-rw-r&#45;&#45;&#45;&#45;&#45; 1 root qmail 887 Mar  4 18:49 default<br />
-rw-r&#45;&#45;r&#45;&#45; 1 root root&nbsp; 254 Mar  4 18:49 default.pub<br />
<br />
$ <span class="cmd">cat /etc/domainkeys/bltweb.net/default.pub</span><br />
default._domainkey	IN	TXT	&#8220;k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDbFnVeFZdlud6/xvLoMt2/g9qrQzZjg6mopp4IYgPwNxRfQTsvYJo4dxP/aIt5UcL1YWtEnOm6/VL+wzj33WvVGL8GWdJDcUWGpCOysWuKasH/sXCaxoZSFMNM02K5pOgzaIVinWZNLIv+yaDSnBC3zb35HoQOnU4KLySECWPRuQIDAQAB&#8221;<br />
<br />
$ <span class="cmd">sudo cat /etc/domainkeys/bltweb.net/default</span><br />
&#8212;&#8211;BEGIN RSA PRIVATE KEY&#8212;&#8211;<br />
MIICXAIBAAKBgQDbFnVeFZdlud6/xvLoMt2/g9qrQzZjg6mopp4IYgPwNxRfQTsv<br />
YJo4dxP/aIt5UcL1YWtEnOm6/VL+wzj33WvVGL8GWdJDcUWGpCOysWuKasH/sXCa<br />
xoZSFMNM02K5pOgzaIVinWZNLIv+yaDSnBC3zb35HoQOnU4KLySECWPRuQIDAQAB<br />
AoGAXuZniI2JuwK8Pg4LghEmhKK0waKnmIubnfYuVis+0XrKVEiJPoh1xSevfd7n<br />
K3IDJQ9By8K8a8b3gGtH7fX3ktWWFNz++DpewvWzFksC++7rhZoarBC1puWxVNYI<br />
M4xdqEtKXHIzaj3nRHM76RBD5htqa2hZkIDqfK7vDVZUkEECQQD0C5pmMGaBjO1K<br />
bC0hs8dMogxsrnwooIiHg1FO0WhOXGxKYuQGxXjR/fNz8gUyeicCPB3/piKaucGT<br />
OY1X0b9FAkEA5dHhTQTnkMD0pLow6yXTehy8NWzmIl9/EeIQu9HoXVpIGePy4Mrr<br />
ydJzaisQ+RJ8dO5C+1PeR89IRYdeGS/l5QJBAKHRG8SMbTuTdTe2uMozCYA/pttd<br />
asgJgd3Q7dXENlRXJhrArY/r2ivrJkUIAfgxVLI/qGh+AU30w2zaaWUEl70CQEe7<br />
wv8vULg2AiaIl0xOejvbTEPAwfRoqlkCnwaA9m5tB6RNKjpQHFjaf3vcBWg5BO/a<br />
jr2z5+WyJXTOU+i4sqECQC/lZY/0/cgEyyD0UL+oqYrVmlIm5Sc9Pnsu1fIRsfgC<br />
SnHS8/eTTUxNERGIYso4+wVFHR82oR8hucVYa8iY7CM=<br />
&#8212;&#8211;END RSA PRIVATE KEY&#8212;&#8211;
</div>
<h5>Signing Configuration</h5>
<p>To sign emails for all domains for which I have a key in <code>/etc/domainkeys</code>, I set the <code>control/dksign</code> configuration file:</p>
<div class="prompt">
$ <span class="cmd">ls -l /var/qmail/control/dksign</span><br />
-rw-r&#45;&#45;r&#45;&#45; 1 root root 31 Mar 17 14:02 /var/qmail/control/dksign<br />
<br />
$ <span class="cmd">cat /var/qmail/control/dksign</span><br />
/etc/domainkeys/%/default
</div>
<h5>Verify Configuration</h5>
<p>Here&#8217;s an example of my <code>/etc/tcprules.d/tcp.qmail-smtp</code> file.  Make sure you regenerate the cdb file after editing your <code>tcp.qmail-smtp</code> file!</p>
<div class="file">
# Connections from localhost are allowed to relay<br />
127.0.0.1:allow,RELAYCLIENT=&quot;&quot;,RBLSMTPD=&quot;&quot;<br />
<br />
# Everyone else can&#8217;t relay unless they auth<br />
# All signed mail is allowed, even if it&#8217;s bad, but still prepend the<br />
# Authentication-Results header<br />
:allow,DKVERIFY=&quot;&quot;,AUTH_UNSET_DKVERIFY=&quot;&quot;<br />
<br />
# Or if I want to use the recommend DKIM settings, comment out the line<br />
# above and use<br />
# :allow,DKVERIFY=&quot;DEGIJKfh,CGHIJMQRkl&quot;,AUTH_UNSET_DKVERIFY=&quot;&quot;
</div>
<p><a name="finished"></a><br />
<h4>7. Finished</h4>
<p>That&#8217;s it.  You should now have a qmail installation capable of signing and verifying messages.  More information is contained in the <code>qmail-smtpd</code> and <code>qmail-remote</code> man pages.</p>
<p>If you have any comments or find any bugs, please feel free to post a comment below.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.brandonturner.net/blog/2009/03/dkim-and-domainkeys-for-qmail/feed/</wfw:commentRss>
		<slash:comments>63</slash:comments>
		</item>
	</channel>
</rss>
