<?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>redemption in a blog &#187; Operating Systems</title>
	<atom:link href="http://blog.codefront.net/category/operating-systems/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.codefront.net</link>
	<description>Rails, Firefox, Anime, Mac</description>
	<lastBuildDate>Tue, 24 Jan 2012 01:47:54 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>Setting up virtualization on Ubuntu with KVM</title>
		<link>http://blog.codefront.net/2010/02/01/setting-up-virtualization-on-ubuntu-with-kvm/</link>
		<comments>http://blog.codefront.net/2010/02/01/setting-up-virtualization-on-ubuntu-with-kvm/#comments</comments>
		<pubDate>Mon, 01 Feb 2010 14:18:13 +0000</pubDate>
		<dc:creator>Chu Yeow</dc:creator>
				<category><![CDATA[Open Source]]></category>
		<category><![CDATA[Operating Systems]]></category>

		<guid isPermaLink="false">http://blog.codefront.net/?p=1271</guid>
		<description><![CDATA[These instructions have been tested on Ubuntu 9.10 (Karmic) 64-bit. Skip right to the instructions if you&#8217;re short on time. After being a happy Xen user for several years now, I&#8217;ve recently had to switch to an alternative virtualization solution. My colleague Arun (@iamclovin) actually struggled for a week with Xen VMs that locked up [...]]]></description>
			<content:encoded><![CDATA[<p>These instructions have been tested on <strong>Ubuntu 9.10 (Karmic) 64-bit</strong>. <a href="#kvm_guide_start">Skip right to the instructions</a> if you&#8217;re short on time.</p>
<p>After being a <a href="http://blog.codefront.net/2007/06/26/installing-xen-on-ubuntu-feisty-fawn-the-complete-newbies-guide/">happy Xen user</a> for several years now, I&#8217;ve recently had to switch to an alternative virtualization solution. My colleague Arun (<a href="http://twitter.com/iamclovin">@iamclovin</a>) actually struggled for a week with Xen VMs that locked up on Hardy; we&#8217;ve had much success with Hardy and Xen before, so we attributed it to a hardware problem since these were our first blade servers.</p>
<p>Out of ideas, we tried Karmic (Ubuntu 9.10) only to discover that Xen support via the apt package system is gone. I went down the path of compiling a <a href="http://wiki.xensource.com/xenwiki/XenParavirtOps">paravirt_ops</a> Dom0 kernel (<a href="http://www.itkovian.net/base/the-xen-hypervisor-with-ubuntu-karmic-koala/">this article</a> was <em>very</em> useful) but ended up deciding the process took far too long despite being successful.</p>
<p>With <a href="http://news.cnet.com/8301-13580_3-9867657-39.html">KVM gaining official support from Ubuntu</a> as <strong>the</strong> virtualization solution, I ended up ditching Xen and switching to <a href="http://www.linux-kvm.org/">KVM</a> for these new servers on Karmic. The rest of the entry is a step-by-step guide on setting up KVM VMs on a Ubuntu server; I&#8217;m putting this down because like all wikis, the <a href="https://help.ubuntu.com/community/KVM">Ubuntu KVM wiki</a> has grown a little too organically to be useful.</p>
<h3 id="kvm_guide_start">Preparing a host server for KVM</h3>
<ol>
<li>
    Update and upgrade apt packages (use your own discretion on whether this is necessary):</p>
<pre><code>aptitude update &#038;&#038; aptitude dist-upgrade</code></pre>
</li>
<li>
    Check whether CPU supports hardware virtualization:</p>
<pre><code>egrep '(vmx|svm)' --color=always /proc/cpuinfo</code></pre>
<p>    You should see lines with either &#8220;vmx&#8221; or &#8220;svm&#8221; highlighted.
  </li>
<li>
    Install these packages:</p>
<pre><code>aptitude install kvm libvirt-bin ubuntu-vm-builder bridge-utils</code></pre>
<p>    If you see a <code>FATAL: Error inserting kvm_intel</code> message during installation, it means that virtualization is not enabled in your machine&#8217;s BIOS. You&#8217;ll need to reboot your machine, enter the BIOS setup and enable virtualization (you&#8217;ll have to hunt for the option).<br />
    <a href="http://blog.codefront.net/wp-content/uploads/2010/02/BIOS-virtualization-option.png"><img src="http://blog.codefront.net/wp-content/uploads/2010/02/BIOS-virtualization-option.png" alt="" title="BIOS virtualization option" width="399" height="243" class="aligncenter size-full wp-image-1283" /></a><br />
    After enabling virtualization in the BIOS and rebooting, run:</p>
<pre><code>modprobe kvm-intel</code></pre>
<p>    There should be no error shown (in fact, no console response).
  </li>
<li>
    Optionally, install virt-top, a top-like tool for your VMs:</p>
<pre><code>aptitude install virt-top</code></pre>
</li>
<li>
    Verify that you can connect to the hypervisor:</p>
<pre><code>virsh -c qemu:///system list</code></pre>
<p>    You should see something like this:</p>
<pre><code>Connecting to uri: qemu:///system
 Id Name                 State
 ----------------------------------</code></pre>
</li>
<li>
    Setup a network bridge on the server for VMs. Edit <code>/etc/network/interfaces</code> so it looks like this (use your own IPs):</p>
<pre><code>auto lo
iface lo inet loopback

auto eth0
iface eth0 inet manual

auto br0
iface br0 inet static
 address 192.168.1.222
 netmask 255.255.255.0
 network 192.168.1.0
 broadcast 192.168.1.255
 gateway 192.168.1.167
 bridge_ports eth0
 bridge_stp off
 bridge_fd 9
 bridge_hello 2
 bridge_maxage 12
 bridge_maxwait 0</code></pre>
</li>
<li>
    Make sure that you have a direct console to the server because you&#8217;re going to restart networking:</p>
<pre><code>/etc/init.d/networking restart</code></pre>
</li>
<li>
    Verify that your changes took place with <code>ifconfig</code>. You should see 2 entries like these:</p>
<pre><code>br0       Link encap:Ethernet  HWaddr 00:11:22:33:44:55
          inet addr:192.168.1.215  Bcast:192.168.1.255  Mask:255.255.255.0
          inet6 addr: fe80::223:aeff:fefe:1f14/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:1099 errors:0 dropped:0 overruns:0 frame:0
          TX packets:50 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:74665 (74.6 KB)  TX bytes:6223 (6.2 KB)

eth0      Link encap:Ethernet  HWaddr 00:66:77:88:99:00
          inet6 addr: fe80::223:aeff:fefe:1f14/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:4939 errors:0 dropped:0 overruns:0 frame:0
          TX packets:39 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:532798 (532.7 KB)  TX bytes:5585 (5.5 KB)
          Interrupt:36 Memory:da000000-da012800</code></pre>
</li>
</ol>
<h3>Setting up a VM</h3>
<ol>
<li>
    Setup a VM with <code>vmbuilder</code>:</p>
<pre><code>vmbuilder kvm ubuntu \
    -v \
    --suite=karmic \
    --libvirt=qemu:///system \
    --arch=amd64 \
    --cpus=2 \
    --mem=2048 \
    --swapsize=4096 \
    --rootsize=20480 \
    --flavour=server \
    --hostname=billiejean \
    --ip=192.168.1.240 \
    --mask=255.255.255.0 \
    --net=192.168.1.0 \
    --bcast=192.168.1.255 \
    --gw=192.168.1.167 \
    --dns='202.157.163.157 202.157.131.118' \
    --bridge=br0 \
    --mirror=http://archive.ubuntu.com/ubuntu \
    --components='main,universe' \
    --addpkg=openssh-server \
    --user=administrator \
    --pass=icanhaspasswd \
    --dest=/root/vm-billiejean \
    --tmpfs=-</code></pre>
<p>    The options you need to care about are:</p>
<ol>
<li><code>suite</code>: Version of Ubuntu to install (e.g. karmic, hardy).</li>
<li><code>cpus</code>: Number of CPUs to assign to VM.</li>
<li><code>mem</code>: Amount of RAM in MB to assign to VM.</li>
<li><code>swapsize</code>: Size of swap in MB of VM.</li>
<li><code>rootsize</code>: Size of root filesystem in MB of VM.</li>
<li><code>flavour</code>: The &#8220;flavour&#8221; of kernel to use in the VM. Either &#8220;virtual&#8221; or &#8220;server&#8221;.</li>
<li><code>hostname</code>: Hostname of VM.</li>
<li><code>ip</code>: IP address of VM.</li>
<li><code>mask</code>: Netmask of VM.</li>
<li><code>net</code>: Network of VM.</li>
<li><code>bcast</code>: Broadcast address of VM.</li>
<li><code>gw</code>: Gateway of VM.</li>
<li><code>dns</code>: DNS server(s) for VM.</li>
<li><code>addpkg</code>: APT packages to install in the VM. openssh-server is needed so that we can login to the VM to setup the virsh console.</li>
<li><code>user</code> and <code>pass</code>: User account that&#8217;s setup for you to access the VM.</li>
<li><code>dest</code>: Destination directory on server where VM disk image will reside.</li>
</ol>
</li>
<li>
    If your VM is created successfully, there&#8217;ll be a config file for the VM in <code>/etc/libvirt/qemu/</code> (e.g. <code>/etc/libvirt/qemu/billiejean.xml</code>), and a disk image in the directory specified in the <code>--dest</code> option (e.g. <code>/root/vm-billiejean/disk0.qcow2</code>).
  </li>
<li>
    You can verify that it works by starting the VM and SSHing into it (virsh console will not work yet).</p>
<pre><code>virsh start billiejean</code></pre>
</li>
</ol>
<h3>Converting Disk Images to LVM Logical Volumes</h3>
<p>Now, we have the VM setup but it&#8217;s running off a disk image. For better performance, running the VM off a LVM logical volume will optimize disk IO.</p>
<p>vmbuilder is supposed to support the <code>--raw</code> option to write the VM to a block device (such as a LVM logical volume), but I&#8217;ve had no success with it (as does Mark Imbriaco, sysadmin of 37signals: <a href="http://twitter.com/markimbriaco/status/7437688341">http://twitter.com/markimbriaco/status/7437688341</a> and <a href="http://twitter.com/markimbriaco/status/7437699338">http://twitter.com/markimbriaco/status/7437699338</a>). We&#8217;re going to convert the disk images using qemu-img and write the bits into a LVM logical volume instead.</p>
<ol>
<li>Stop the VM if it&#8217;s running:
<pre><code>virsh shutdown billiejean</code></pre>
</li>
<li>Convert the VM&#8217;s qcow2 (QEMU image format) disk image to a raw disk image:
<pre><code>qemu-img convert disk0.qcow2 -O raw disk0.raw</code></pre>
</li>
<li>Create a logical volume to house the VM, making sure it&#8217;s big enough for the VM&#8217;s rootsize and swapsize options:
<pre><code>lvcreate -L24GB -n &lt;logical_volume_name&gt; &lt;volume_group_name&gt;</code></pre>
</li>
<li>Copy raw image into the logical volume:
<pre><code>dd if=disk0.raw of=/dev/&lt;volume_group_name&gt;/&lt;logical_volume_name&gt; bs=1M</code></pre>
<p>      This will take awhile (the bigger your image, the longer it takes).</li>
<li>Edit the VM&#8217;s config so that it uses your new logical volume:
<pre><code>virsh edit billiejean</code></pre>
<p>    Change <code>&lt;disk&gt;</code> to point to the logical volume:</p>
<pre><code>&lt;disk type='block' device='disk'&gt;
  &lt;source dev='/dev/&lt;volume_group_name&gt;/&lt;logical_volume_name&gt;'/&gt;
  &lt;target dev='hda' bus='ide'/&gt;
&lt;/disk&gt;</code></pre>
</li>
<li>Startup the VM. You might wanna rename the original <code>disk0.qcow2</code> image first just to make sure your VM isn&#8217;t still using it.</li>
<li>Once you&#8217;re sure your VM is running off your LVM logical volume, you can delete or backup the original qcow2 disk image.</li>
</ol>
<h3>Getting a console to your VM from the Host Server</h3>
<p>Now, we have to setup the VM so that virsh console works. This is a console to the VM from the host server that works even when the networking in the VM is not.</p>
<ol>
<li>Edit the VM&#8217;s settings:
<pre><code>virsh edit billiejean</code></pre>
<p>    In the <code>&lt;devices&gt;</code> block, add:</p>
<pre><code>&lt;serial type='pty'&gt;
  &lt;target port='0'/&gt;
&lt;/serial&gt;</code></pre>
</li>
<li>Startup your VM:
<pre><code>virsh start billiejean</code></pre>
</li>
<li>SSH into VM and create a file <code>/etc/init/ttyS0.conf</code>:
<pre><code>start on stopped rc RUNLEVEL=[2345]
stop on runlevel [!2345]

respawn
exec /sbin/getty -8 38400 ttyS0 vt102</code></pre>
<p>      Start the tty with:</p>
<pre><code>start ttyS0</code></pre>
</li>
<li>Still in the VM, install acpid so that the VM will respond to shutdown commands from the server:
<pre><code>aptitude install acpid</code></pre>
</li>
<li>Reboot the VM.</li>
<li>Verify the console works by opening a console to the VM from the server:
<pre><code>virsh console billiejean</code></pre>
<p>      You may have to hit &#8220;Enter&#8221; before you see any console output.
  </li>
</ol>
<h3>Miscellaneous VM Setup</h3>
<p>That&#8217;s it, your VM is ready! You&#8217;ll probably want to do these:</p>
<ul>
<li>Set a root password and possibly delete the user you setup using <code>vmbuilder</code>.</li>
<li>Set the timezone with <code>dpkg-reconfigure tzdata</code>.</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://blog.codefront.net/2010/02/01/setting-up-virtualization-on-ubuntu-with-kvm/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>God and your web server</title>
		<link>http://blog.codefront.net/2007/07/18/god-and-your-web-server/</link>
		<comments>http://blog.codefront.net/2007/07/18/god-and-your-web-server/#comments</comments>
		<pubDate>Wed, 18 Jul 2007 15:43:38 +0000</pubDate>
		<dc:creator>Chu Yeow</dc:creator>
				<category><![CDATA[Operating Systems]]></category>
		<category><![CDATA[Ruby]]></category>
		<category><![CDATA[Ruby on Rails]]></category>
		<category><![CDATA[Web development]]></category>

		<guid isPermaLink="false">http://blog.codefront.net/2007/07/18/god-and-your-web-server/</guid>
		<description><![CDATA[God is a new process monitoring Ruby framework with a rather apt name (no, it&#8217;s not that God). The config files looks something like that: God.meddle do &#124;god&#124; god.watch do &#124;w&#124; ... end end Interesting code to write. And feels safe too to have God watching over your mongrels. Oh and you can use it [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://god.rubyforge.org/">God</a> is a new process monitoring Ruby framework with a rather apt name (no, it&#8217;s not <em>that</em> <a href="http://en.wikipedia.org/wiki/God">God</a>). The config files looks something like that:</p>
<pre><code class="ruby">God.meddle do |god|
  god.watch do |w|
    ...
  end
end</code></pre>
<p>Interesting code to write. And feels safe too to have God watching over your mongrels. Oh and you can use it to clean up stale mongrel PID files without <a href="http://textsnippets.com/posts/show/931">patching mongrel_rails</a>. Right now I use <a href="http://www.tildeslash.com/monit/">monit</a> a lot and it&#8217;s really rather unDRY to have repeated configs for each mongrel on the server (is there a better way of doing this in monit?). God would be able to DRY it up.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.codefront.net/2007/07/18/god-and-your-web-server/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>logrotate and mongrel (mongrel_cluster)</title>
		<link>http://blog.codefront.net/2007/07/16/logrotate-and-mongrel-mongrel_cluster/</link>
		<comments>http://blog.codefront.net/2007/07/16/logrotate-and-mongrel-mongrel_cluster/#comments</comments>
		<pubDate>Mon, 16 Jul 2007 05:45:21 +0000</pubDate>
		<dc:creator>Chu Yeow</dc:creator>
				<category><![CDATA[Operating Systems]]></category>
		<category><![CDATA[Ruby on Rails]]></category>

		<guid isPermaLink="false">http://blog.codefront.net/2007/07/16/logrotate-and-mongrel-mongrel_cluster/</guid>
		<description><![CDATA[I&#8217;ve never actually explored log rotation tools in Linux and merely knew of the existence of logrotate and left it at that until log sizes really became a problem. Turns out logrotate is amazingly easy to configure, and thanks to this Logrotate and Mongrel blog post by Corey Donohoe I have it setup for my [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve never actually explored log rotation tools in Linux and merely knew of the existence of <a href="http://www.linuxcommand.org/man_pages/logrotate8.html">logrotate</a> and left it at that until log sizes really became a problem. Turns out logrotate is amazingly easy to configure, and thanks to <a href="http://www.atmos.org/2007/3/22/logrotate-and-mongrel">this Logrotate and Mongrel blog post by Corey Donohoe</a> I have it setup for my Rails applications that are running on <a href="http://mongrel.rubyforge.org/">Mongrel</a>. Here&#8217;s what my <code>/etc/logrotate.d/mongrel_cluster</code> looks like:</p>
<pre><code>/var/railsapps/APP_NAME/shared/log/production.log {
  daily
  rotate 28
  missingok
  compress
  sharedscripts
  postrotate
    for i in `ls /var/railsapps/APP_NAME/shared/log/*.pid`; do
      kill -USR2 `cat $i`
    done
  endscript
}</code></pre>
]]></content:encoded>
			<wfw:commentRss>http://blog.codefront.net/2007/07/16/logrotate-and-mongrel-mongrel_cluster/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>WTF is this? (Or how NIS and portmapper on Ubuntu Dapper Drake drove me nuts)</title>
		<link>http://blog.codefront.net/2007/07/02/wtf-is-this-or-how-nis-and-portmapper-on-ubuntu-dapper-drake-drove-me-nuts/</link>
		<comments>http://blog.codefront.net/2007/07/02/wtf-is-this-or-how-nis-and-portmapper-on-ubuntu-dapper-drake-drove-me-nuts/#comments</comments>
		<pubDate>Mon, 02 Jul 2007 11:42:00 +0000</pubDate>
		<dc:creator>Chu Yeow</dc:creator>
				<category><![CDATA[Open Source]]></category>
		<category><![CDATA[Operating Systems]]></category>

		<guid isPermaLink="false">http://blog.codefront.net/2007/07/02/wtf-is-this-or-how-nis-and-portmapper-on-ubuntu-dapper-drake-drove-me-nuts/</guid>
		<description><![CDATA[Not too long ago a couple of the Ubuntu Dapper Drake (6.06 LTS) VPSs we use abruptly became inaccessible. These VPSs were NIS clients that suddenly could no longer connect to the NIS master. Great. And as far as I could tell I didn&#8217;t do anything to those servers. I even managed to replicate the [...]]]></description>
			<content:encoded><![CDATA[<p>Not too long ago a couple of the Ubuntu Dapper Drake (6.06 LTS) <acronym title="Virtual Private Servers">VPS</acronym>s <a href="http://www.bezurk.com/">we</a> use abruptly became inaccessible. These VPSs were <a href="http://en.wikipedia.org/wiki/Network_Information_Service">NIS</a> clients that suddenly could no longer connect to the NIS master. Great. And as far as I could tell I didn&#8217;t do anything to those servers. I even managed to replicate the problem on another similar VPS (that was still accessble) simply by restarting the NIS daemon.</p>
<p>Thanks to <a href="http://rimuhosting.com/">Rimuhosting</a>&#8216;s fantabulous support, I managed to regain access to the VPSs. Oh yeah, <strong>big lesson learnt</strong> here: when configuring NIS clients, be sure to leave at least one user account with sudo privileges or set the root account&#8217;s password (Ubuntu doesn&#8217;t come with a root account enabled by default &#8211; run <code>sudo passwd</code> to set it and enable the root account as a side effect). Big big lesson learnt. Don&#8217;t let this bite you in the ass if you&#8217;re a sysadmin-ish person.</p>
<p>Anyway, <code>/var/log/syslog</code> was complaining this:</p>
<pre><code>ypbind[1026]: Unable to register (YPBINDPROG, YPBINDVERS, udp)</code></pre>
<p>Which turned out to be a portmap problem. So yeah portmap wasn&#8217;t running! For a moment there I thought we had an easy solution. Sadly, <code>/etc/init.d/portmap start</code> was throwing this inexplicable error (i.e. Google wasn&#8217;t of much help):</p>
<pre><code>root@zoidberg:/sbin# /etc/init.d/portmap  restart
 * Stopping portmap daemon...
   ...done.
 * Starting portmap daemon...
dhclient.4.x 2.*.5, December 30th, 2000
Compiled on Dec 12 2003 09:55:54
Features: DBG, SEE, ALS, SEF
init: Couldn't open the file ./libuuid.so -&gt;
   ...fail!</code></pre>
<p>It sure isn&#8217;t <a href="http://en.wikipedia.org/wiki/Lolcat">caturday</a>. After hours spent scrambling to find out why portmap can&#8217;t find libuuid.so, reinstalling the NIS .deb, comparing configuration files between working NIS clients and these busted ones, it finally dawned on me that I have yet to re-install portmap (not that it was logically sound that I&#8217;d have to reinstall it, but at this point I was willing to try anything). Annoyingly enough, it worked!</p>
<pre><code>apt-get remove portmap nis
apt-get install nis</code></pre>
<p>I still don&#8217;t know <acronym title="What The Fuck">WTF</acronym> happened there. If anyone has any clue please please point me to it.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.codefront.net/2007/07/02/wtf-is-this-or-how-nis-and-portmapper-on-ubuntu-dapper-drake-drove-me-nuts/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Installing Xen on Ubuntu Feisty Fawn &#8211; the complete newbie&#8217;s guide</title>
		<link>http://blog.codefront.net/2007/06/26/installing-xen-on-ubuntu-feisty-fawn-the-complete-newbies-guide/</link>
		<comments>http://blog.codefront.net/2007/06/26/installing-xen-on-ubuntu-feisty-fawn-the-complete-newbies-guide/#comments</comments>
		<pubDate>Tue, 26 Jun 2007 13:46:44 +0000</pubDate>
		<dc:creator>Chu Yeow</dc:creator>
				<category><![CDATA[Open Source]]></category>
		<category><![CDATA[Operating Systems]]></category>

		<guid isPermaLink="false">http://blog.codefront.net/2007/06/26/installing-xen-on-ubuntu-feisty-fawn-the-complete-newbies-guide/</guid>
		<description><![CDATA[I had to spend some time setting up Xen on one of the new Dell servers we bought and while there was some documentation around, I had to constantly refer to the different sources since there wasn&#8217;t a complete page which had everything I needed for my particular situation &#8211; I have a host machine [...]]]></description>
			<content:encoded><![CDATA[<p>I had to spend some time setting up <a href="http://www.xensource.com/xen">Xen</a> on one of the new Dell servers we bought and while there <a href="https://help.ubuntu.com/community/XenVirtualMachine/XenOnUbuntuFeisty">was</a> <a href="http://www.howtoforge.com/xen_3.0_ubuntu_dapper_drake">some</a> <a href="http://www.howtoforge.com/perfect_xen_setup_debian_ubuntu">documentation</a> <a href="http://tx.downloads.xensource.com/downloads/docs/user/">around</a>, I had to constantly refer to the different sources since there wasn&#8217;t a complete page which had everything I needed for my particular situation &#8211; I have a host machine with Ubuntu Feisty Fawn installed and wanted to install a couple of Xen guest domains on it. One other thing I found lacking in the documentation is the explanation of commands or answers to the question <em>&#8220;so why the hell am I doing this?&#8221;</em>. I&#8217;m not considering <a href="http://en.wikipedia.org/wiki/Logical_Volume_Manager_(Linux)">LVM</a> at the moment and am happy with loopback disk file images too.</p>
<p>So I think it&#8217;s a good idea to <em>write this down somewhere</em> for the next time I have to do the same bloody thing over again on any new servers.</p>
<p>Some caveats before we start:</p>
<ul>
<li>Like I said, I&#8217;m not gonna talk about LVM for disk images since I know next to nothing about configuring it at the moment. The host machine I have isn&#8217;t setup with LVM and I haven&#8217;t got the time to look into LVM either.</li>
<li>I&#8217;m quite the networking newbie, so my setup uses the default Xen bridge installed via apt-get. Check out <a href="http://wiki.xensource.com/xenwiki/XenNetworking">Xen networking on the Xen wiki</a> for more complex network setups.</li>
<li>I&#8217;m not gonna talk about putting a Linux distro other than that of the host machine into the Xen virtual machines. In other words, I have Feisty Fawn for both dom0 and all my domUs.</li>
<li>I probably did some completely stupid things. Stuff like <a href="http://www.xen-tools.org/software/xen-tools/">xen-tools</a> exist to simplify Xen administration, but I haven&#8217;t had a chance to use them. Let me know if you spot an error or have a better way of doing something please!</li>
</ul>
<p>Some terms that deserve explaining (most guides out there just use &#8220;DomU&#8221; and &#8220;Dom0&#8243; without any ceremony, and assume you know what they mean):</p>
<ul>
<li><strong>Domain-0</strong> or <strong>Dom0</strong>: This refers to the host machine OS. You know, the OS of the actual physical server that you have.</li>
<li><strong>DomU</strong>: This refers to a Xen guest domain. A DomU is a single Xen virtual machine. The &#8220;U&#8221; stands for &#8220;unprivileged&#8221; I believe.</li>
</ul>
<p>OK let&#8217;s go!</p>
<p><span id="more-980"></span></p>
<h3>Installing the Xen Server</h3>
<p>First off, we need to install the Xen server on the host machine (or Dom0). Thankfully, there is a Xen server package in Feisty Fawn&#8217;s apt-get repository.</p>
<ul>
<li>Make sure &#8216;universe&#8217; is enabled in <code>/etc/apt/sources.list</code> and run: <code>apt-get install ubuntu-xen-server</code></li>
<li>Reboot the machine. After boot, running <code>sudo xm list</code> should show you Domain-0 (which is the host machine that&#8217;s running Xen).</li>
<li>Edit /etc/xen/xend-config.sxp and uncomment this line:
<pre><code>(network-script network-bridge)</code></pre>
</li>
<li>Comment out this line:
<pre><code>(network-script network-dummy)</code></pre>
</li>
<li>Restart xend:
<pre><code>sudo xend restart</code></pre>
</li>
<li>When you run &#8216;ifconfig&#8217;, you should see the &#8216;xenbr0&#8242; interface. This is the Xen network bridge.</li>
</ul>
<h3>Creating a base image</h3>
<p>Now let&#8217;s create a base Xen image. We&#8217;ll use this as a template for any future images (domUs).</p>
<ul>
<li>Use &#8216;dd&#8217; to create the images (I place them in /xen-images/):
<pre><code>dd if=/dev/zero of=/xen-images/feisty_base.img bs=1024k count=4000
dd if=/dev/zero of=/xen-images/feisty_base_swap.img bs=1024k count=1000</code></pre>
<p>  These commands create image files of 4GB and 1GB for your virtual OS and its swap respectively. &#8216;count&#8217; is the number of blocks (block size = 1024k).</li>
<li>Create the filesystem (we&#8217;re using ext3 in this case) within the virtual OS image file.
<pre><code>mkfs.ext3 /xen-images/feisty_base.img</code></pre>
<p>   Answer &#8216;yes&#8217; to proceed anyway when it complains about the file not being a block device.</li>
<li>Do the same for the swap file:
<pre><code>mkswap /xen-images/feisty_base_swap.img</code></pre>
</li>
<li>Now, restrict the permissions on the images so no one else but root can screw around with them.
<pre><code>chmod 640 /xen-images/feisty_base*</code></pre>
</li>
<li>Create a mount point for the image. We need this to mount the image to install and configure Ubuntu Feisty Fawn the way we like it. We can then replicate this base image for any future virtual machines.
<pre><code>mkdir /xen-images/mnt</code></pre>
</li>
<li>Mount the base image via the loop device:
<pre><code>mount -o loop /xen-images/feisty_base.img /xen-images/mnt</code></pre>
<p>  Now we have full access to the base image&#8217;s filesystem. What we need to do now is to put a base install of Feisty Fawn on it.</li>
</ul>
<h3>Installing and configuring the base image</h3>
<p>Next, we have to put Ubuntu onto the image and configure it to our liking.</p>
<ul>
<li>Install debootstrap, a handy tool that bootstraps a basic Debian (Ubuntu in this case) system.
<pre><code>apt-get install debootstrap</code></pre>
</li>
<li>Bootstrap the base image with &#8216;feisty&#8217;:
<pre><code>debootstrap feisty /xen-images/mnt</code></pre>
<p>  After this is done you should see the basic Ubuntu file hierarchy:</p>
<pre><code>ls /xen-images/mnt</code></pre>
</li>
<li>Copy your sources.list into the base image:
<pre><code>cp /etc/apt/sources.list /xen-images/mnt/etc/apt/</code></pre>
</li>
<li>Copy your kernel modules as well (replace 2.6.19-4-server with whatever kernel version you have):
<pre><code>cp -a /lib/modules/2.6.19-4-server/ /xen-images/mnt/lib/modules/</code></pre>
</li>
<li>Install the <code>libc6-xen</code> package, which is a Xen-compatible glibc that allows applications to use Thread-Local Storage (TLS).
<pre><code>apt-get install libc6-xen</code></pre>
<p>  Taken from the <a href="http://wiki.xensource.com/xenwiki/XenFaq">Xen FAQ</a>:</p>
<blockquote><p>Some modern distributions ship with a &#8216;TLS&#8217; version of glibc that is not fully compatible with Xen. To use Xen reliably and with maximum performance you must disable the incompatible glibc.</p></blockquote>
</li>
<li>Configure networking by editing <code>/xen-images/mnt/etc/network/interfaces</code>:
<pre><code>auto lo
iface lo inet loopback

# Uncomment this and fill up with your networks settings.
#auto eth0
#iface eth0 inet static
#  address 192.168.0.201
#  netmask 255.255.255.0
#  broadcast 192.168.255.255
# gateway 192.168.0.1
#  dns-nameservers 192.168.0.1</code></pre>
<p>  Notice how the network settings are commented out &#8211; this is because we are leaving the base image as a template from which other images would be made from.</li>
<li>Edit the hosts file (<code>/xen-images/mnt/etc/hosts</code>):
<pre><code>127.0.0.1       localhost localhost.localdomain
127.0.0.1       guest

# The following lines are desirable for IPv6 capable hosts
::1     ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
ff02::3 ip6-allhosts</code></pre>
</li>
<li>Give the base image a generic hostname by editing <code>/xen-images/mnt/etc/hostname</code>. In this case I&#8217;m just naming it &#8216;guest&#8217; &#8211; actual virtual machines would have sensible hostnames.</li>
<li>Edit the filesystem table (<code>/xen-images/mnt/etc/fstab</code>).
<pre><code>proc            /proc           proc    defaults        0       0
/dev/hda1       /               ext3    defaults,errors=remount-ro 0       1
/dev/hda2       none            swap    sw              0       0</code></pre>
<p>  Don&#8217;t worry, the /dev/hda* would be configured to point to the images you created, not to your actual physical harddisks.</li>
<li>You&#8217;re done with the initial configuration and have enough to bootup the image. Let&#8217;s unmount the image:
<pre><code>umount /xen-images/mnt</code></pre>
</li>
<li>Now, we need to create a Xen config for the base image so we can boot into it. Create a file named <code>/etc/xen/vm_feisty_base.config.example.sxp</code> (you can name it whatever you like of course):
<pre><code>name = "feisty_base"
kernel = "/boot/vmlinuz-2.6.19-4-server"
ramdisk = "/boot/initrd.img-2.6.19-4-server"
root = "/dev/hda1 ro"
memory = 512
disk = ['file:/xen-images/feisty_base.img,hda1,w','file:/xen-images/feisty_base_swap.img,hda2,w']

# Network.
hostname = "feisty_base"
vif = ['bridge=xenbr0']
dhcp = "off"
ip = "192.168.0.201"
netmask = "255.255.255.0"
gateway = "192.168.0.1"</code></pre>
</li>
</ul>
<p>An explanation of the configuration options:</p>
<ul>
<li><strong>name</strong> &#8211; a descriptive name of your image.</li>
<li><strong>kernel</strong> &#8211; path to the kernel.</li>
<li><strong>ramdisk</strong> &#8211; path to the <a href="http://www.cyberciti.biz/tips/understanding-linux-initrd-initial-ram-disk.html">initrd</a> (initial RAM disk) image.</li>
<li><strong>root</strong> &#8211; point this to your host machine&#8217;s harddisk where your image files are.</li>
<li><strong>memory</strong> &#8211; the amount of memory assigned to the virtual machine in megabytes</li>
<li><strong>disk</strong> &#8211; specify a list of block devices that will be export to the virtual machine. In this example, we&#8217;re mapping the /xen-images/feisty_base.img image file to /dev/hda1 in the virtual image (same for the swap image). This should match whatever config you did in /xen-images/mnt/etc/fstab.</li>
<li><strong>hostname</strong> &#8211; hostname of your virtual machine.</li>
<li><strong>vif</strong> &#8211; virtual network interface that your virtual machine will use. In this case, we&#8217;re using the default &#8216;xenbr0&#8242; bridge that Xen installs. For alternative configurations, check out the <a href="http://wiki.xensource.com/xenwiki/XenNetworking">networking page on the Xen wiki</a>.</li>
<li><strong>ip</strong> &#8211; specify your virtual machine&#8217;s IP here.</li>
<li><strong>netmask</strong> and <strong>gateway</strong> &#8211; netmask and gateway that your virtual machine should use.</li>
</ul>
<ul>
<li>Now, start the base virtual machine:
<pre><code>xm create /etc/xen/vm_feisty_base.config.example.sxp -c</code></pre>
<p>  You should see a console (the &#8216;-c&#8217; option connects you to the console immediately after booting up the virtual machine. Login as root (empty password) &#8211; you&#8217;ll want to change the password (with &#8216;passwd&#8217;).</li>
<li>Enable shadowed passwords.
<pre><code>shadowconfig on</code></pre>
</li>
<li>Create a backup of <code>/etc/network/interfaces</code> and edit <code>/etc/network/interfaces</code> to put in correct values so you can access the Internet from the virtual machine:
<pre><code>cp /etc/network/interfaces /etc/network/interfaces.bak
vim /etc/network/interfaces</code></pre>
</li>
<li>Start networking:
<pre><code>ifup -a</code></pre>
</li>
<li>Install the Ubuntu standard system after running an update:
<pre><code>apt-get update
apt-get install ubuntu-standard</code></pre>
</li>
<li>I also like to upgrade any packages that have been updated, if any:
<pre><code>apt-get upgrade</code></pre>
</li>
<li>Install the OpenSSH server so that you can access the virtual machine via ssh:
<pre><code>apt-get install ssh</code></pre>
</li>
<li>At this point, do any configuration or installation of packages that you want this base image to have. Remember that we&#8217;re going to replicate this base image for future Xen virtual machines so <strong>don&#8217;t go overboard</strong> and install stuff you&#8217;re not gonna use.</li>
<li>Stop networking and put back the original /etc/network/interfaces:
<pre><code>ifdown -a
mv /etc/network/interfaces.bak /etc/network/interfaces</code></pre>
</li>
<li>Exit the guest console with <code>Ctrl-]</code>. This will bring you back to dom0&#8242;s shell.</li>
<li>Shutdown the base Xen domU (<code>-w</code> means &#8220;wait for the domU to shutdown completely&#8221;):
<pre><code>xm shutdown feisty_base -w</code></pre>
</li>
</ul>
<p>You&#8217;re done setting up the base image! Now you have a nicely configured base image.</p>
<h3>Creating your first virtual server</h3>
<p>The fruits of thy labor are almost at hand &#8211; with the base image, we can now make a copy of it for our first Xen virtual machine.</p>
<ul>
<li>Make copies of the base image and the swap image (let&#8217;s call our virtual server &#8220;yuki&#8221;):
<pre><code>cp /xen-images/feisty_base.img /xen-images/yuki.img
cp /xen-images/feisty_base_swap.img /xen-images/yuki_swap.img</code></pre>
<p>  You may want to <a href="#resizing">resize the base image</a> depending on your disk space needs. (And, of course, you can create your own swap image like we did earlier instead of copying the base image&#8217;s swap file.)</li>
<li>Make a copy of the base Xen configuration file that we created for our base image earlier (you can use whatever name you like):
<pre><code>cp /etc/xen/vm_feisty_base.config.example.sxp /etc/xen/vm_yuki.config.sxp</code></pre>
</li>
<li>Edit the <code>/etc/xen/vm_yuki.config.sxp file</code>, changing the values to suit your virtual server (you probably want to change at least the &#8216;name&#8217;, &#8216;disk&#8217;, &#8216;ip, and &#8216;hostname&#8217; values).
<pre><code>name = "yuki"
disk = ['file:/xen-images/yuki.img,hda1,w','file:/xen-images/yuki_swap.img,hda2,w']
hostname = "yuki"
ip = "192.168.0.202"</code></pre>
</li>
<li>Now start up your cloned virtual server and log into it like we did earlier with the base image (if you haven&#8217;t changed the password, you can login as root with an empty password).
<pre><code>xm create -c /etc/xen/vm_yuki.config.sxp</code></pre>
</li>
<li>The first thing you should do is to secure your root password (if you haven&#8217;t done so in the base image earlier).
<pre><code>passwd</code></pre>
</li>
<li>Now, you&#8217;ll want to change these files:
<ul>
<li>/etc/network/interfaces</li>
<li>/etc/hostname</li>
<li>/etc/hosts</li>
</ul>
</li>
<li>With the proper network settings, you should be able to bring up networking to connect to the internet (assuming that your dom0 is connected to the internet).
<pre><code>ifup -a
ping google.com</code></pre>
</li>
<li>At this point, you are free to customize your virtual machine as you see fit &#8211; install nginx for use as a static file server, Rails, MySQL server, whatever.</li>
<li>But first, let&#8217;s make sure this Xen virtual server starts up automatically on boot. Exit the virtual machine console with <code>Ctrl-]</code>
<pre><code>ln -s /etc/xen/vm_yuki.config.sxp /etc/xen/auto/</code></pre>
<p>  Any Xen domain configuration placed in <code>/etc/xen/auto/</code> will be started up automatically on boot (and shutdown when the host machine is shutdown too).</li>
</ul>
<p><strong>That&#8217;s it!</strong> You have a functional Xen guest domain that starts up on boot and that can connect to the Internet. Oh before I forget, some useful commands when dealing with the Xen images:</p>
<ul>
<li><code>xm create /path/to/config_file</code> &#8211; Starts up the guest domain with the given Xen domU configuration file. (<code>xm create -c</code> to login to the console immediately after booting the image.)</li>
<li><code>xm console yuki</code> &#8211; Open the console for the &#8216;yuki&#8217; Xen domain.</li>
<li><code>xm shutdown yuki</code> &#8211; Shutdown the &#8216;yuki&#8217; domU.</li>
<li><code>xm list</code> &#8211; Lists all the Xen domains you have running.</li>
</ul>
<h3 id="resizing">Resizing your virtual machine disk</h3>
<p>Let&#8217;s say you wanna add 1GB of disk space to your virtual machine (named &#8216;yuki&#8217;).</p>
<p><em>Note that LVM is usually recommended for Xen setups, so you may wanna take a look at that instead.</em></p>
<ul>
<li>Create a temporary 1GB file:
<pre><code>dd if=/dev/zero of=/tmp/temp_expand bs=1024k count=1000</code></pre>
</li>
<li>Bring down the virtual machine (I&#8217;ve found that a shutdown is needed so that the virtual machine recognizes the increased disk space):
<pre><code>xm shutdown yuki</code></pre>
</li>
<li><strong>Append</strong> the file to the disk image of the virtual machine (/xen-images/yuki.img in this example). <strong>Be sure to use &#8216;&gt;&gt;&#8217;</strong> (which means append) &#8211; using a single &#8216;&gt;&#8217; would overwrite the disk image with your temporary file, which you most definitely don&#8217;t want!
<pre><code>cat /tmp/temp_expand >> /xen-images/yuki.img</code></pre>
</li>
<li>Resize the file system:
<pre><code>resize2fs -f /xen-images/yuki.img</code></pre>
</li>
<li>Startup the virtual machine again:
<pre><code>xm create -c /etc/xen/vm_yuki.config.sxp</code></pre>
</li>
<li>Remember to login to your virtual machine to verify that the disk space has increased (<code>df -h</code>)</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://blog.codefront.net/2007/06/26/installing-xen-on-ubuntu-feisty-fawn-the-complete-newbies-guide/feed/</wfw:commentRss>
		<slash:comments>21</slash:comments>
		</item>
		<item>
		<title>So what exactly are you looking forward to in Leopard?</title>
		<link>http://blog.codefront.net/2007/06/13/so-what-exactly-are-you-looking-forward-to-in-leopard/</link>
		<comments>http://blog.codefront.net/2007/06/13/so-what-exactly-are-you-looking-forward-to-in-leopard/#comments</comments>
		<pubDate>Tue, 12 Jun 2007 17:02:35 +0000</pubDate>
		<dc:creator>Chu Yeow</dc:creator>
				<category><![CDATA[Applications]]></category>
		<category><![CDATA[Mac]]></category>
		<category><![CDATA[Operating Systems]]></category>

		<guid isPermaLink="false">http://blog.codefront.net/2007/06/13/so-what-exactly-are-you-looking-forward-to-in-leopard/</guid>
		<description><![CDATA[So there&#8217;s this big Leopard thing that&#8217;s the talk of Mac town (well, that and Safari) with all the new features being revealed (officially, at least, to the general public) at WWDC 2007. Some of the features are pretty cool, most of them are mundane. For me, I am really looking forward to: the new [...]]]></description>
			<content:encoded><![CDATA[<p>So there&#8217;s this big <a href="http://www.apple.com/macosx/leopard/">Leopard</a> thing that&#8217;s the talk of Mac town (well, that and Safari) with all the new features being revealed (officially, at least, to the general public) at <a href="http://developer.apple.com/wwdc/">WWDC 2007</a>.</p>
<div class="img"><img src='http://blog.codefront.net/wp-content/uploads/2007/06/apple-leopard-homepage.jpg' alt='Screenshot of Apple Leopard homepage' /></div>
<p><br style="clear: both;" /></p>
<p>Some of the features are pretty cool, most of them are mundane. For me, I am really looking forward to:</p>
<ul>
<li>the <a href="http://www.apple.com/macosx/leopard/features/finder.html">new Finder</a> &#8211; Finder sucks so bad as a file system interface. I use <a href="http://www.cocoatech.com/pf4/">Path Finder</a>, which incidentally had an <a href="http://www.cocoatech.com/changelog.php">upgrade</a> recently to 4.7. The new Finder looks pretty (Cover Flow for files, sexy!) but what I&#8217;m really hoping for is a Finder with which you can actually be productive.</li>
<li><a href="http://www.apple.com/macosx/leopard/technology/unix.html">Ruby and Rails baked right into Mac OS X</a> &#8211; while installing Rails and upgrading Ruby is a breeze on Mac OS X as it is right now, having these installed by default is pretty sweet. Even <a href="http://capify.org/">Capistrano</a> will be included. Now, how one upgrades Ruby is another thing though&#8230;</li>
<li><a href="http://www.apple.com/macosx/leopard/features/timemachine.html">Time Machine</a> &#8211; Even though I already own a licensed copy of <a href="http://www.shirt-pocket.com/SuperDuper/">SuperDuper!</a>, I&#8217;m still eager to use Time Machine. I mean, who isn&#8217;t hooked on the time travel metaphor yet? It&#8217;s like <a href="http://en.wikipedia.org/wiki/System_Restore">System Restore</a> done right (with the advantage of hindsight, of course).</li>
</ul>
<p>What are <strong>you</strong> looking forward in Leopard?</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.codefront.net/2007/06/13/so-what-exactly-are-you-looking-forward-to-in-leopard/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Nginx, PHP and a PHP FastCGI daemon init script</title>
		<link>http://blog.codefront.net/2007/06/11/nginx-php-and-a-php-fastcgi-daemon-init-script/</link>
		<comments>http://blog.codefront.net/2007/06/11/nginx-php-and-a-php-fastcgi-daemon-init-script/#comments</comments>
		<pubDate>Mon, 11 Jun 2007 13:18:32 +0000</pubDate>
		<dc:creator>Chu Yeow</dc:creator>
				<category><![CDATA[Open Source]]></category>
		<category><![CDATA[Operating Systems]]></category>
		<category><![CDATA[Ruby on Rails]]></category>

		<guid isPermaLink="false">http://blog.codefront.net/2007/06/11/nginx-php-and-a-php-fastcgi-daemon-init-script/</guid>
		<description><![CDATA[One of the things us ex-Apache httpd or ex-Lighttpd users have to get used to when installing nginx is how there isn&#8217;t built-in FastCGI support for process spawning. While these means nginx is more lightweight and faster, it does mean that you have to manage your FastCGI processes yourself. Having just upgraded to Ubuntu Feisty [...]]]></description>
			<content:encoded><![CDATA[<p>One of the things us ex-Apache httpd or ex-Lighttpd users have to get used to when installing <a href="http://nginx.net/">nginx</a> is how there isn&#8217;t built-in FastCGI support for process spawning. While these means nginx is more lightweight and faster, it does mean that you have to manage your FastCGI processes yourself.</p>
<p>Having just upgraded to Ubuntu Feisty Fawn, I set to installing nginx and tried to get WordPress (which needs PHP, of course) running on it. Thanks to the new nginx package in the Feisty universe repository, getting nginx up and PHP (CGI version) and running is really straightforward. There&#8217;re <a href="http://blog.dominiek.com/articles/2007/5/18/bye-redskin-zdravstvujte-redstar-nginx-tips/">lots</a> of <a href="http://www.urbanpuddle.com/articles/2007/05/09/install-ruby-on-rails-on-ubuntu-feisty-fawn">tutorials</a> to help you out as well.</p>
<p>So that&#8217;s that. The part that bugged me though, was how the tutorials always provided a script to start your PHP FastCGI processes, but never provided a way to ensure your FastCGI processes started up on a reboot (i.e. an init script). Once again, Google doesn&#8217;t disappoint, turning up this <a href="http://www.mail-archive.com/debian-bugs-dist@lists.debian.org/msg352883.html">php-cgi init script</a>. Tweak the init script a little, put it in /etc/init.d/php-fastcgi, <code>sudo chmod +x /etc/init.d/php-fastcgi</code>, run <code>sudo update-rc.d php-fastcgi defaults</code> and place the configuration for the script in /etc/default/php-fastcgi, and you&#8217;re done. You now have a PHP FastCGI init script that spawns and kills your PHP FastCGI processes.</p>
<p><strong>Note:</strong> Lighttpd does come with a <code>spawn-fcgi</code> binary that does the same, but I&#8217;m having trouble finding a suitable init script for spawn-fcgi (only the Gentoo emerge seems to have the init script). Still, this script works and I didn&#8217;t really want to install lightty on my starving <acronym title="Virtual Private Server">VPS</acronym>.</p>
<p><span id="more-966"></span></p>
<p><strong>The init script: /etc/init.d/php-fastcgi</strong></p>
<pre><code>#! /bin/sh
### BEGIN INIT INFO
# Provides:          php-fastcgi
# Required-Start:    $all
# Required-Stop:     $all
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: Start and stop php-cgi in external FASTCGI mode
# Description:       Start and stop php-cgi in external FASTCGI mode
### END INIT INFO

# Author: Kurt Zankl <[EMAIL PROTECTED]>

# Do NOT "set -e"

PATH=/sbin:/usr/sbin:/bin:/usr/bin
DESC="php-cgi in external FASTCGI mode"
NAME=php-fastcgi
DAEMON=/usr/bin/php-cgi
PIDFILE=/var/run/$NAME.pid
SCRIPTNAME=/etc/init.d/$NAME
PHP_CONFIG_FILE=/etc/php5/cgi/php.ini

# Exit if the package is not installed
[ -x "$DAEMON" ] || exit 0

# Read configuration variable file if it is present
[ -r /etc/default/$NAME ] &#038;&#038; . /etc/default/$NAME

# Load the VERBOSE setting and other rcS variables
. /lib/init/vars.sh

# Define LSB log_* functions.
# Depend on lsb-base (>= 3.0-6) to ensure that this file is present.
. /lib/lsb/init-functions

# If the daemon is not enabled, give the user a warning and then exit,
# unless we are stopping the daemon
if [ "$START" != "yes" -a "$1" != "stop" ]; then
        log_warning_msg "To enable $NAME, edit /etc/default/$NAME and set START=yes"
        exit 0
fi

# Process configuration
export PHP_FCGI_CHILDREN PHP_FCGI_MAX_REQUESTS
DAEMON_ARGS="-q -b $FCGI_HOST:$FCGI_PORT -c $PHP_CONFIG_FILE"

do_start()
{
        # Return
        #   0 if daemon has been started
        #   1 if daemon was already running
        #   2 if daemon could not be started
        start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON --test > /dev/null \
                || return 1
        start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON \
                --background --make-pidfile --chuid $EXEC_AS_USER --startas $DAEMON -- \
                $DAEMON_ARGS \
                || return 2
}

do_stop()
{
        # Return
        #   0 if daemon has been stopped
        #   1 if daemon was already stopped
        #   2 if daemon could not be stopped
        #   other if a failure occurred
        start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --pidfile $PIDFILE > /dev/null # --name $DAEMON
        RETVAL="$?"
        [ "$RETVAL" = 2 ] &#038;&#038; return 2
        # Wait for children to finish too if this is a daemon that forks
        # and if the daemon is only ever run from this initscript.
        # If the above conditions are not satisfied then add some other code
        # that waits for the process to drop all resources that could be
        # needed by services started subsequently.  A last resort is to
        # sleep for some time.
        start-stop-daemon --stop --quiet --oknodo --retry=0/30/KILL/5 --exec $DAEMON
        [ "$?" = 2 ] &#038;&#038; return 2
        # Many daemons don't delete their pidfiles when they exit.
        rm -f $PIDFILE
        return "$RETVAL"
}
case "$1" in
  start)
        [ "$VERBOSE" != no ] &#038;&#038; log_daemon_msg "Starting $DESC" "$NAME"
        do_start
        case "$?" in
                0|1) [ "$VERBOSE" != no ] &#038;&#038; log_end_msg 0 ;;
                2) [ "$VERBOSE" != no ] &#038;&#038; log_end_msg 1 ;;
        esac
        ;;
  stop)
        [ "$VERBOSE" != no ] &#038;&#038; log_daemon_msg "Stopping $DESC" "$NAME"
        do_stop
        case "$?" in
                0|1) [ "$VERBOSE" != no ] &#038;&#038; log_end_msg 0 ;;
                2) [ "$VERBOSE" != no ] &#038;&#038; log_end_msg 1 ;;
        esac
        ;;
  restart|force-reload)
        log_daemon_msg "Restarting $DESC" "$NAME"
        do_stop
        case "$?" in
          0|1)
                do_start
                case "$?" in
                        0) log_end_msg 0 ;;
                        1) log_end_msg 1 ;; # Old process is still running
                        *) log_end_msg 1 ;; # Failed to start
                esac
                ;;
          *)
                # Failed to stop
                log_end_msg 1
                ;;
        esac
        ;;
  *)
        echo "Usage: $SCRIPTNAME {start|stop|restart|force-reload}" >&#038;2
        exit 3
        ;;
esac</code></pre>
<p><strong>Config file for init script (the init script looks for this): /etc/default/php-fastcgi</strong></p>
<pre><code>START=yes

# Which user runs PHP? (default: www-data)

EXEC_AS_USER=www-data

# Host and TCP port for FASTCGI-Listener (default: localhost:9000)

FCGI_HOST=localhost
FCGI_PORT=9000

# Environment variables, which are processed by PHP

PHP_FCGI_CHILDREN=4
PHP_FCGI_MAX_REQUESTS=1000</code></pre>
<p><strong>nginx config file: /etc/nginx/nginx.conf</strong></p>
<pre><code>location ~ \.php$ {
  fastcgi_pass   127.0.0.1:9000;
  fastcgi_index  index.php;
  fastcgi_param  SCRIPT_FILENAME  /var/www/blog.codefront.net$fastcgi_script_name;
  include        /etc/nginx/fastcgi.conf;
}</code></pre>
<p><strong>My fastcgi.conf file (I&#8217;m not sure I need everything here&#8230;)</strong></p>
<pre><code>fastcgi_param  QUERY_STRING       $query_string;
fastcgi_param  REQUEST_METHOD     $request_method;
fastcgi_param  CONTENT_TYPE       $content_type;
fastcgi_param  CONTENT_LENGTH     $content_length;

fastcgi_param  SCRIPT_NAME        $fastcgi_script_name;
fastcgi_param  REQUEST_URI        $request_uri;
fastcgi_param  DOCUMENT_URI       $document_uri;
fastcgi_param  DOCUMENT_ROOT      $document_root;
fastcgi_param  SERVER_PROTOCOL    $server_protocol;

fastcgi_param  GATEWAY_INTERFACE  CGI/1.1;
fastcgi_param  SERVER_SOFTWARE    nginx;

fastcgi_param  REMOTE_ADDR        $remote_addr;
fastcgi_param  REMOTE_PORT        $remote_port;
fastcgi_param  SERVER_ADDR        $server_addr;
fastcgi_param  SERVER_PORT        $server_port;
fastcgi_param  SERVER_NAME        $server_name;

# PHP only, required if PHP was built with --enable-force-cgi-redirect
fastcgi_param  REDIRECT_STATUS    200;</code></pre>
]]></content:encoded>
			<wfw:commentRss>http://blog.codefront.net/2007/06/11/nginx-php-and-a-php-fastcgi-daemon-init-script/feed/</wfw:commentRss>
		<slash:comments>36</slash:comments>
		</item>
		<item>
		<title>Toilets and Linux evangelism</title>
		<link>http://blog.codefront.net/2007/06/05/toilets-and-linux-evangelism/</link>
		<comments>http://blog.codefront.net/2007/06/05/toilets-and-linux-evangelism/#comments</comments>
		<pubDate>Tue, 05 Jun 2007 06:44:54 +0000</pubDate>
		<dc:creator>Chu Yeow</dc:creator>
				<category><![CDATA[Mac]]></category>
		<category><![CDATA[Open Source]]></category>
		<category><![CDATA[Operating Systems]]></category>

		<guid isPermaLink="false">http://blog.codefront.net/2007/06/05/toilets-and-linux-evangelism/</guid>
		<description><![CDATA[Pardon the self-promoting cross-linking: Toilets and Linux evangelism (or what we use to build Bezurk) is an entry I just posted on the brand new Bezurk Blog about how the toilet is a good place to spread the word. If you&#8217;ve found other neat ways to use the free Ubuntu stickers (or even the Apple [...]]]></description>
			<content:encoded><![CDATA[<p>Pardon the self-promoting cross-linking: <a href="http://blog.bezurk.com/2007/06/05/toilets-and-linux-evangelism-or-what-we-use-to-build-bezurk/">Toilets and Linux evangelism (or what we use to build Bezurk)</a> is an entry I just posted on the brand new <a href="http://blog.bezurk.com/">Bezurk Blog</a> about how the toilet is a good place to spread the word. </p>
<p>If you&#8217;ve found other neat ways to use the free Ubuntu stickers (or even the Apple stickers that comes with iPods), do post it!</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.codefront.net/2007/06/05/toilets-and-linux-evangelism/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Axel &#8211; lightweight command line download accelerator</title>
		<link>http://blog.codefront.net/2007/04/29/axel-lightweight-command-line-download-accelerator/</link>
		<comments>http://blog.codefront.net/2007/04/29/axel-lightweight-command-line-download-accelerator/#comments</comments>
		<pubDate>Sun, 29 Apr 2007 08:50:09 +0000</pubDate>
		<dc:creator>Chu Yeow</dc:creator>
				<category><![CDATA[Open Source]]></category>
		<category><![CDATA[Operating Systems]]></category>

		<guid isPermaLink="false">http://blog.codefront.net/2007/04/29/axel-lightweight-command-line-download-accelerator/</guid>
		<description><![CDATA[I never really fancied download accelerators but Axel is different &#8211; it&#8217;s a command line application and is naturally significantly more lightweight then those graphical download managers I&#8217;ve stopped using since 1996 (teh intraweb was slower then, and I was sucking bits of it through a state of the art 33.6kbps dial-up modem). I&#8217;ve been [...]]]></description>
			<content:encoded><![CDATA[<p>I never really fancied download accelerators but <a href="http://wilmer.gaast.net/main.php/axel.html">Axel</a> is different &#8211; it&#8217;s a command line application and is naturally significantly more lightweight then those graphical download managers I&#8217;ve stopped using since 1996 (<em>teh intraweb</em> was slower then, and I was sucking bits of it through a state of the art 33.6kbps dial-up modem).</p>
<p>I&#8217;ve been using <code>wget</code> for its auto-resume support, but have switched to using Axel since one of my colleagues at <a href="http://bezurk.com/">Bezurk</a> introduced me to it. If you&#8217;re a <code>wget</code> or <code>curl</code> fan, Axel is almost a drop-in replacement (although it doesn&#8217;t handle multiple redirects or broken connections too well).</p>
<p>Install it:</p>
<pre><code>
# On a Mac, with Darwin Ports.
sudo port install axel

# On Ubuntu.
sudo apt-get install axel
</code></pre>
<p>Windows users would require <a href="http://sources.redhat.com/cygwin/">cygwin</a> to get Axel to work for them (what, a Windows user and you don&#8217;t have cygwin installed already?).</p>
<p>Now go download some files. If you need a good place just to test the speeds, go to <a href="http://developer.yahoo.com/yui/theater/">YUI Theater</a> and download some videos (watch them too, most of them are pretty good, like Douglas Crockford&#8217;s and the Firebug videos). Run it on the command line by typing:</p>
<pre><code>axel -n 10 http://example.com/some_file.mov</code></pre>
<p>The <code>-n 10</code> option tells Axel to use a maximum of 10 simultaneous connections when downloading the file. Another useful option is <code>-a</code>, which outputs a <code>wget</code>-like report of download progress in a few lines rather than filling up your screen with download progress messages.</p>
<p>Check out the speeds I managed to get:</p>
<div class="img"><img src="http://blog.codefront.net/wp-content/uploads/2007/04/axel-super-download-speed.jpg" alt="Check out the 1MB+/s download speed with Axel" /></div>
<p><br style="clear: both;" /></p>
<p>250MB in 3 minutes, with an average download speed of 1339KB/s. That&#8217;s pretty damn fast. Comparatively, I could only get speeds of around 40KB/s using Firefox. It&#8217;s hard not to love this raw speed and I think you might too.</p>
<p>Oh, and to go off-topic here, it&#8217;s nice to know we are steadily chipping away at the Windows user base in <a href="http://bezurk.com/">Bezurk</a>. The colleague who introduced me to Axel recently switched to Ubuntu (he&#8217;s been waiting for Ubuntu 7.04). It was painful to set it up correctly (the KDE part of Kubuntu, not Ubuntu itself), but I think he&#8217;s much happier working on Linux for some inexplicable reason.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.codefront.net/2007/04/29/axel-lightweight-command-line-download-accelerator/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>Setting up svnsync-ed (mirrored) SVN repositories on Ubuntu (part 2 of 2)</title>
		<link>http://blog.codefront.net/2007/03/31/setting-up-svnsync-ed-mirrored-svn-repositories-on-ubuntu-part-2-of-2/</link>
		<comments>http://blog.codefront.net/2007/03/31/setting-up-svnsync-ed-mirrored-svn-repositories-on-ubuntu-part-2-of-2/#comments</comments>
		<pubDate>Sat, 31 Mar 2007 15:12:31 +0000</pubDate>
		<dc:creator>Chu Yeow</dc:creator>
				<category><![CDATA[Open Source]]></category>
		<category><![CDATA[Operating Systems]]></category>
		<category><![CDATA[Web development]]></category>

		<guid isPermaLink="false">http://blog.codefront.net/2007/03/31/setting-up-svnsync-ed-mirrored-svn-repositories-on-ubuntu-part-2-of-2/</guid>
		<description><![CDATA[Note: if you haven&#8217;t already, you may want to read part 1 of this article first. Phew, and that was all the work you needed to do to migrate your Subversion repository to another server. We&#8217;ve barely touched that other server that we wanted to use for mirroring the repository! &#8220;Bootstrapping&#8221; your mirror SVN server [...]]]></description>
			<content:encoded><![CDATA[<p><ins>Note: if you haven&#8217;t already, you may want to read <a href="/2007/03/29/setting-up-svnsync-ed-mirrored-svn-repositories-on-ubuntu-part-1-of-2/">part 1 of this article</a> first.</ins></p>
<p>Phew, and that was all the work you needed to do to migrate your Subversion repository to another server. We&#8217;ve barely touched that other server that we wanted to use for mirroring the repository!</p>
<h3>&#8220;Bootstrapping&#8221; your mirror SVN server for svnsync</h3>
<p>This mirror SVN server also needs Subversion 1.4.x installed, so go ahead and do the (almost) same things we&#8217;ve done in <a href="/2007/03/29/setting-up-svnsync-ed-mirrored-svn-repositories-on-ubuntu-part-1-of-2/">part 1</a> to get Subversion installed. You should be able to use the <code>.deb</code> package generated by <code>checkinstall</code> on your main Subversion server to install Subversion 1.4.x on the mirror SVN server. Just scp it to the mirror SVN server and install it (<code>dpkg -i subversion-1.4.3.deb</code>).</p>
<p>With Subversion installed, create a new Subversion repository (using <code>svnadmin create</code>, remember?), but <em>don&#8217;t</em> load the repository dump like we did on the main SVN server in <a href="/2007/03/29/setting-up-svnsync-ed-mirrored-svn-repositories-on-ubuntu-part-1-of-2/">part 1</a> (of course, since we are going to be mirroring the repository!).</p>
<h3>Setting up svnsync to mirror your repository</h3>
<p>First, create a SVN user for svnsync to use &#8211; let&#8217;s call this the &#8216;svnsync user&#8217;. The easiest (and best) way to do this is edit the svnserve.conf and passwd files:</p>
<p><strong>conf/svnserve.conf</strong></p>
<pre><code>
# Uncomment this line.
password-db = passwd
</code></pre>
<p><strong>conf/passwd</strong></p>
<pre><code>
svnsync = secret
</code></pre>
<p>This gives read and write access to the &#8216;svnsync user&#8217;. The <code>svnsync</code> program will authenticate with our repositories as this user via the <code>svn://</code> protocol (i.e. via svnserve).</p>
<p>Next, we need to create a <code>pre-revprop-change</code> hook for the destination repository. The <a href="http://svn.collab.net/repos/svn/trunk/notes/svnsync.txt">svnsync documentation</a> has a detailed explanation. Create a <code>hooks/pre-revprop-change</code> file under your destination repository&#8217;s directory.</p>
<pre><code>
#!/bin/sh
USER="$3"

if [ "$USER" = "svnsync" ]; then exit 0; fi

echo "Only the svnsync user can change revprops" >&#038;2
exit 1</code></pre>
<p>Make it executable, and then initialize the sync:</p>
<pre><code>
chmod +x hooks/pre-revprop-change
svnsync init file:///var/svn/repositories/destination_repos svn://source.host/source_repos</code></pre>
<p>Don&#8217;t worry, this only sets up the sync &#8211; there&#8217;s no actual data copying yet. Syncing your repository data may take a long time if you have a big source repository, so I suggest using <code>nohup</code> to run the code overnight (or something), or at least saving the output in a log. Either way, the command to start the sync is:</p>
<pre><code>svnsync sync --username svnsync file:///var/svn/repositories/testsync/</code></pre>
<p>You should start seeing svnsync committing in changes from your source repository. Instant gratification (well, almost)! Should your svnsync process get aborted or killed, you can remove the hanging lock by running:</p>
<pre><code>svn propdel svn:sync-lock --revprop -r 0</code></pre>
<h3>Setting up &#8216;on-the-fly&#8217; syncing</h3>
<p>So now you have your source and destination repositories synced, but what happens when you start committing changes to your source repository? Nothing! That&#8217;s because svnsync is merely a passive syncing tool (meaning you have to run it to sync, instead of it knowing when to sync automatically).</p>
<p>There are two ways you can setup &#8216;real-time&#8217; syncing:</p>
<ol>
<li>
    Use <code>cron</code> (or a similar scheduler) on the destination repository server. Add something like this to your <code>crontab</code>:</p>
<pre><code>* * * * * /usr/local/bin/svnsync --non-interactive sync svn://source.host/source_repos</code></pre>
<p>    This basically runs svnsync on your destination repository server every minute to pull down any changes to your source repository.
  </li>
<li>Add a post-commit hook to the source repository. I found this <a href="http://journal.paul.querna.org/articles/2006/09/14/using-svnsync">svnsync entry by Paul Querna</a> that has a sample post-commit hook. If I recall correctly I tried it but it didn&#8217;t work for me, so I settled on using cron to sync up my repositories.</li>
</ol>
<h3>Things that I skipped</h3>
<p>There&#8217;re some things that I skipped over while writing this, mainly to do with SVN authentication.</p>
<ul>
<li>
    If you&#8217;re accessing your repository via the <code>svn+ssh://</code> protocol, you&#8217;ve to manage the (group) permissions of the repository files in the filesystem appropriately (basically the repository should be group writable by your users). <code>chmod</code> and <code>chown</code> are your friends, as is <acronym title="Network Information Service">NIS</acronym> (or something similar) to manage your users. I use these steps to create a new SVN repository that gets access via the <code>svn+ssh://</code> protocol:</p>
<pre><code>
sudo mkdir /var/svn/repositories/funky_project
mkdir /tmp/funky_project
mkdir /tmp/funky_project/trunk
mkdir /tmp/funky_project/branches
mkdir /tmp/funky_project/tags
sudo svnadmin create /var/svn/repositories/funky_project
sudo svn import /tmp/YourProjectNameHere file:////var/svn/repositories/funky_project -m "Initial import."
rm -rf /tmp/funky_project
sudo chown -R www-data:www-data /var/svn/repositories/funky_project
sudo chmod -R g+w /var/svn/repositories/funky_project
    </code></pre>
<p>    As you can see, my SVN users are part of the www-data group, and the repository directory is made group-writable.
  </li>
<li>The <code>svn://</code> protocol has authentication configuration files in the <code>conf/</code> directory of your repository. The SVN book has a <a href="http://svnbook.red-bean.com/nightly/en/svn.serverconfig.svnserve.html#svn.serverconfig.svnserve.auth">section explaining how to configure authentication</a> for <code>svnserve</code>.</li>
<li>Apache httpd can be used to expose your SVN repositories via the WebDAV protocol. This allows for the very commonly seen <code>http://</code> repository URLs (especially for Open Source projects). Configuration is a little more involved and you would probably have to install Apache from source as well. The SVN book has <a href="http://svnbook.red-bean.com/nightly/en/svn.serverconfig.httpd.html">the details</a>.</li>
</ul>
<h3>Wrapping up</h3>
<p>I hope someone found this entry useful &#8211; I know I could have used one when I was setting up Subversion and svnsync.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.codefront.net/2007/03/31/setting-up-svnsync-ed-mirrored-svn-repositories-on-ubuntu-part-2-of-2/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>Setting up svnsync-ed (mirrored) SVN repositories on Ubuntu (part 1 of 2)</title>
		<link>http://blog.codefront.net/2007/03/29/setting-up-svnsync-ed-mirrored-svn-repositories-on-ubuntu-part-1-of-2/</link>
		<comments>http://blog.codefront.net/2007/03/29/setting-up-svnsync-ed-mirrored-svn-repositories-on-ubuntu-part-1-of-2/#comments</comments>
		<pubDate>Wed, 28 Mar 2007 17:34:36 +0000</pubDate>
		<dc:creator>Chu Yeow</dc:creator>
				<category><![CDATA[Open Source]]></category>
		<category><![CDATA[Operating Systems]]></category>
		<category><![CDATA[Web development]]></category>

		<guid isPermaLink="false">http://blog.codefront.net/2007/03/29/setting-up-svnsync-ed-mirrored-svn-repositories-on-ubuntu-part-1-of-2/</guid>
		<description><![CDATA[This is a 2-part journal on setting up migrating and upgrading a Subversion repository, and then using svnsync to mirror the newly created repository. (Part 2) Initial setup Ever since Subversion 1.4 was released, I&#8217;d been eying the new svnsync tool because we had a single repository that was not, erm, really backed up (we [...]]]></description>
			<content:encoded><![CDATA[<p>This is a 2-part journal on setting up migrating and upgrading a Subversion repository, and then using svnsync to mirror the newly created repository. (<a href="http://blog.codefront.net/2007/03/31/setting-up-svnsync-ed-mirrored-svn-repositories-on-ubuntu-part-2-of-2/">Part 2</a>)</p>
<h3>Initial setup</h3>
<p>Ever since <a href="http://subversion.tigris.org/">Subversion</a> 1.4 was <a href="http://subversion.tigris.org/svn_1.4_releasenotes.html">released</a>, I&#8217;d been eying the new <a href="http://svn.collab.net/repos/svn/trunk/notes/svnsync.txt">svnsync</a> tool because we had a single repository that was not, erm, <em>really</em> backed up (we had daily server backups and occasional manual repository dumps but that was it). svnsync promised to make repository mirroring simple, and after doing some repository migration and upgrading, I can assure you it really does make things easier than any other (more manual) repository backup solutions I had seen before. This is a walkthrough of how you can upgrade your pre-1.4 <acronym title="Subversion">SVN</acronym> repositories to 1.4.x, and setup svnsync to mirror your repositories. It&#8217;s going to be very biased to Ubuntu but I&#8217;m sure you can translate any Ubuntu specific steps to your favorite distros.</p>
<p>Here&#8217;s our initial setup:</p>
<ul>
<li>A pre-1.4 (it was version 1.2.3) SVN repository that needed to be upgraded <em>and</em> migrated to another server.</li>
<li>2 cleanly installed Ubuntu 6.06 <acronym title="Long Term Support">LTS</acronym> <acronym title="Virtual Private Servers">VPSs</acronym>, one of which is the intended target for the repository migration. The other would mirror the new 1.4.x repository (using svnsync).</li>
</ul>
<h3>An un-installable Subversion 1.4.x?</h3>
<p>I wish I could have simply ran <code>sudo apt-get install subversion</code> and have Ubuntu pull down the latest 1.4.x .debs. Unfortunately, the version of Subversion in the Ubuntu apt-get repository is still 1.3.1 (which doesn&#8217;t have svnsync). If anyone knows a reliable way to install Subversion 1.4.x via apt-get, let me know! I looked around for a good edge sources.list but came back empty-handed.</p>
<p>I balk at installing stuff from source because I never did figure out how to easily clean out the stuff that gets installed. All thanks to this reluctance, I went digging around and found <a href="http://asic-linux.com.mx/~izto/checkinstall/">checkinstall</a>. This thing is <strong>awesome</strong> &#8211; I wonder why I didn&#8217;t manage to find it earlier.</p>
<p>What <code>checkinstall</code> basically allows you to do is, instead of running the usual <code>make install</code> after the usual <code>configure</code> and <code>make</code> steps, it creates a Debian package (it also does RPMs and Slackware packages) for you that is easily un-installable with <code>dpkg</code>, and then proceeds to install the files just as it would have for any other deb.</p>
<p>On Ubuntu it&#8217;s really easy to install <a href="http://asic-linux.com.mx/~izto/checkinstall/">checkinstall</a>, just:</p>
<pre><code>sudo apt-get install checkinstall</pre>
<p></code></p>
<p>Now, you no longer should type 'make install' - always use the 'checkinstall' command instead:</p>
<pre><code>
./configure
make
sudo checkinstall # instead of "make install"</code></pre>
<p><code>checkinstall</code> will ask you a bunch of stuff but you can just go with the defaults for most of them - I did name my packages 'XXX <strong>from source</strong>', like 'Subversion 1.4.3 from source' so it's easier to check which packages are <code>checkinstall</code>-generated with a simple grep to <code>dpkg -l</code>.</p>
<p><code>checkinstall</code> generates a .deb (Debian) package before it actually installs your software (Subversion, in this case). It should tell you right at the end of its installation process about where to find this .deb and how to uninstall your newly installed (from source!) package (something like <code>dpkg -r subversion-1.4.3</code>). Don't delete this .deb yet as we will be using it to install Subversion 1.4.x on our mirror SVN server.</p>
<h3>Installing an un-installable Subversion 1.4.x on Ubuntu</h3>
<p>Now, blessed with our new checkinstall-granted powers, we can install Subversion from source without any qualms. Before we start, be sure to purge any existing Subversion packages you may have installed (do note that if you're using any packages that depend on the official Ubuntu Subversion packages, you may run into library version problems).</p>
<pre><code>
dpkg -l | grep svn
dpkg -l | grep subversion

sudo dpkg --purge subversion
sudo dpkg --purge libsvn0</code></pre>
<p>Now, it's time to get the source. Get it from the <a href="http://subversion.tigris.org/">official Subversion website</a>. Look for the source code download - the file should be something like this: <a href="http://subversion.tigris.org/downloads/subversion-1.4.3.tar.gz">http://subversion.tigris.org/downloads/subversion-1.4.3.tar.gz</a>. Remember to get SVN dependencies (something like this: <a href="http://subversion.tigris.org/downloads/subversion-deps-1.4.3.tar.gz">http://subversion.tigris.org/downloads/subversion-deps-1.4.3.tar.gz</a>) as well as these are needed for access to 'http://' scheme SVN repositories. If you want to use Subversion to connect to a server via a http:// or https:// URL, you will require these dependencies (more specifically, the Neon library).</p>
<p>Use something efficient like wget, curl or <a href="http://wilmer.gaast.net/main.php/axel.html">Axel</a> (<em>love</em> Axel) to get the sources on the server where you want to install Subversion. Unpack them to the same directory. configure. make. <strong>checkinstall</strong>.</p>
<pre><code>
tar zxf subversion-1.4.3.tar.gz
tar zxf subversion-deps-1.4.3.tar.gz
cd subversion-1.4.3
./configure  # Be sure to read the INSTALL file for any options you may want to set (such as SSL)
make
sudo checkinstall</code></pre>
<p>If you get a warning "configure: WARNING: we have configured without BDB filesystem support" during your <code>configure</code> step, you'll get by just fine. Unless you specifically want your Subversion repositories in Berkeley DB format, we can ignore the warning (Subversion will use FSFS filesystem for your repositories) - see <a href="http://svn.collab.net/repos/svn/trunk/notes/fsfs">FSFS notes</a> and <a href="http://svnbook.red-bean.com/nightly/en/svn.reposadmin.planning.html#svn.reposadmin.basics.backends">Choosing a Data Store</a> if you want to make an educated decision.</p>
<p>Anyway, now with a brand new Subversion 1.4.x installed, we are finally ready for the real work - migrating your Subversion repository!</p>
<h3>Dumping and importing a repository</h3>
<p>Dumping a Subversion repository is dead easy:</p>
<pre><code>
svnadmin dump /path/to/repository > repository_name.dump</code></pre>
<p>Depending on how big your repository is, you could end up with a pretty large dump file. gzip it, then scp it over to your new server, then gunzip it. Use svnadmin to load the repository dump.</p>
<pre><code>
cd /var/svn  # I like to keep my svn repositories under /var/svn
mkdir repository_name
svnadmin create repository_name
svnadmin load repository_name &lt; /path/to/repository_name.dump</code></pre>
<p>If you have a good pipe between the source and destination servers, you can do this in a one-liner:</p>
<pre><code>svnadmin dump /path/to/repository | ssh -C [IP/domain of destination server] svnadmin load /path/to/new_repository</code></pre>
<p>Of course, all this dumping would require a temporary suspension of any repository write actions otherwise you're just going to have an inconsistent dump - just send out an email to your fellow developers and disable svn access.</p>
<h3>Setting up access to your new repository</h3>
<p>Now, you have a Subversion repository that is only accessible via the local filesystem (file:// 'protocol'), which isn't very useful. We'll need to setup remote access. Your Subversion repository can be accessed in a variety of ways, including:</p>
<ul>
<li><a href="http://svnbook.red-bean.com/nightly/en/svn.serverconfig.svnserve.html">svnserve</a> standalone daemon (svn://)</li>
<li><a href="http://svnbook.red-bean.com/nightly/en/svn.serverconfig.svnserve.html">svnserve</a> with <code>inetd</code> (svn://)</li>
<li><a href="http://svnbook.red-bean.com/nightly/en/svn.serverconfig.svnserve.html">svnserve</a> over a SSH tunnel (svn+ssh://)</li>
<li>over the HTTP protocol (http:// and https://)</li>
</ul>
<p>The <a href="http://svnbook.red-bean.com/nightly/en/svn.serverconfig.svnserve.html">svnserve documentation</a> details how to deal with the first 3, and setting up http:// and https:// access to your protocol is really a subject that deserves its own tutorial. Try the <a href="http://svnbook.red-bean.com/nightly/en/svn.serverconfig.httpd.html">SVN book</a> or Google.</p>
<p>Personally I prefer svn+ssh:// access for internal projects since it allows me to unify authentication for my Subversion repositories with UNIX user accounts. Be wary of an angry cadre Windows developers though, since they need to take quite a good number of steps to setup public key authentication and integrate it with their svn clients on Windows machines. Integration with TortoiseSVN is quite a pain, though my Windows-using colleague at work found these useful: <a href="http://www.mono-project.com/Putty_and_TortoiseSvn">Putty and TortoiseSVN</a>, <a href="http://brondsema.net/blog/index.php/2005/05/03/using_cygwin_keychain_svn_ssh_and_tortoi">Using Cygwin, Keychain, SVN+SSH and TortoiseSVN in Windows</a>.</p>
<h4>svn:// access</h4>
<p>I also expose my repositories via svn:// (as we'll see later, this is useful for allowing access to a svnsync user without messing around with any UNIX user accounts) and use the <code>xinetd</code> daemon (<code>apt-get install xinetd</code> on Ubuntu to install) to launch svnserve process. If you're taking this path, create a file (I name it 'svn') in <code>/etc/xinet.d</code> to tell xinetd about svnserve.</p>
<p>In /etc/xinet.d/svn:</p>
<pre><code>
service svn
{
        port                    = 3690
        socket_type             = stream
        protocol                = tcp
        wait                    = no
        user                    = www-data
        server                  = /usr/local/bin/svnserve
        server_args             = -i -r /var/svn
}</code></pre>
<p>Notice that I needed to use the full path to svnserve (do a <code>which svnserve</code> to get the full path, making sure this is the 1.4.x version that you just installed). The <code>server_args</code> parameter also bears some explanation. The <code>-i</code> option tells svnserve to use inetd (xinetd is a variant of inetd, sorta). The <code>-r /var/svn</code> option tells svnserve to only expose repositories below that path. This basically translates your repository at <code>/var/svn/my_cool_project</code> to be accessible via <code>svn://your.hostname/my_cool_project</code>.</p>
<h4>svn+ssh:// access</h4>
<p>Accessing your repository this way basically logs in to the host server of your repository over SSH, invokes the svnserve process, and accesses your repository in a very file://-like manner. What this means is that your repository path is taken from the root of your filesystem. An example: a repository located in <code>/var/svn/my_cool_project</code> would be available at <code>svn+ssh://your.hostname/var/svn/my_cool_project</code>. For this reason I often symlink <code>/svn</code> to <code>/var/svn</code> (to get repository URLs like <code>svn+ssh://your.hostname/svn/my_cool_project</code> instead).</p>
<h3>Relocating working copies</h3>
<p>Now, all your working copies are still pointing to the old Subversion server - no need to fret, a simple <code>svn switch</code> fixes things:</p>
<pre><code>svn switch --relocate [from] [to]</code></pre>
<p>Replace '[from]' and '[to]' with the source and destination Subversion repository URLs.</p>
<p>Remember to stop access to your old server so no one is making commits to the wrong place.</p>
<h3>Setting up svnsync</h3>
<p>I'd intended to write this entire piece in one blog post, but I'm running out of steam at this point. In <a href="http://blog.codefront.net/2007/03/31/setting-up-svnsync-ed-mirrored-svn-repositories-on-ubuntu-part-2-of-2/">Part 2</a>, we'll actually setup svnsync for some repository mirroring goodness!</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.codefront.net/2007/03/29/setting-up-svnsync-ed-mirrored-svn-repositories-on-ubuntu-part-1-of-2/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>A Singapore MRT WTF</title>
		<link>http://blog.codefront.net/2007/03/16/a-singapore-mrt-wtf/</link>
		<comments>http://blog.codefront.net/2007/03/16/a-singapore-mrt-wtf/#comments</comments>
		<pubDate>Fri, 16 Mar 2007 02:28:02 +0000</pubDate>
		<dc:creator>Chu Yeow</dc:creator>
				<category><![CDATA[Fun]]></category>
		<category><![CDATA[Operating Systems]]></category>

		<guid isPermaLink="false">http://blog.codefront.net/2007/03/16/a-singapore-mrt-wtf/</guid>
		<description><![CDATA[The Singapore MRT has to be one of the best public rail transport systems in the world (I fancy the Tokyo train/subway system as well &#8211; the fare adjustment machine is one of those &#8220;since sliced bread&#8221; ideas), but they still have room to screw up in a Daily WTF-worthy way. This sign at Raffles [...]]]></description>
			<content:encoded><![CDATA[<p>The <a href="http://en.wikipedia.org/wiki/Mass_Rapid_Transit_(Singapore)">Singapore MRT</a> has to be one of the best public rail transport systems in the world (I fancy the Tokyo train/subway system as well &#8211; the fare adjustment machine is one of those &#8220;since sliced bread&#8221; ideas), but they still have room to screw up in a <a href="http://thedailywtf.com/">Daily WTF</a>-worthy way.</p>
<p>This sign at Raffles Place MRT used to show train arrival times:</p>
<div class="img"><img src="http://blog.codefront.net/wp-content/uploads/2007/03/mrt-rebooting.png" alt="MRT signboard rebooting" /></div>
<p><br style="clear:both;" /></p>
<p>It&#8217;s been there for about 3 days, was still there when I checked this morning.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.codefront.net/2007/03/16/a-singapore-mrt-wtf/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Debugging SSH public key authentication problems</title>
		<link>http://blog.codefront.net/2007/02/28/debugging-ssh-public-key-authentication-problems/</link>
		<comments>http://blog.codefront.net/2007/02/28/debugging-ssh-public-key-authentication-problems/#comments</comments>
		<pubDate>Tue, 27 Feb 2007 18:51:25 +0000</pubDate>
		<dc:creator>Chu Yeow</dc:creator>
				<category><![CDATA[Operating Systems]]></category>

		<guid isPermaLink="false">http://blog.codefront.net/2007/02/28/debugging-ssh-public-key-authentication-problems/</guid>
		<description><![CDATA[After a longer than desired struggle with getting sshd to accept my public key, I think a blog post is in order to remind myself not to repeat the same mistakes. Here&#8217;s how you should go about debugging your SSH public key authentication woes: Getting more debug info when connecting with your ssh client: Add [...]]]></description>
			<content:encoded><![CDATA[<p>After a longer than desired struggle with getting sshd to accept my public key, I think a blog post is in order to remind myself not to repeat the same mistakes. Here&#8217;s how you should go about debugging your SSH public key authentication woes:</p>
<ul>
<li><strong>Getting more debug info when connecting with your ssh client</strong>: Add a &#8216;-v&#8217; option to your ssh command (e.g. ssh chuyeow@remotehost -v -v -v). Add more &#8216;-v&#8217; for more detailed debug (you can do up to &#8216;-v -v -v&#8217; I think).</li>
<li><strong>Debugging on the remote host by running sshd in debug mode</strong>: Run &#8216;/usr/sbin/sshd -d -p 2222&#8242; on the remote host and connect to it. &#8217;2222&#8242; here is the port number of the sshd process you started on the remote host.</li>
<li><strong>tail the authentication log</strong>: Run &#8216;tail -f /var/log/auth.log&#8217; on the remotehost. You can watch the log as you try to connect via SSH with your key.</li>
<li><strong>Make sure your ssh key agent is running</strong>: Do a &#8216;ps aux|grep ssh-agent&#8217;. Make sure your key agent is running. If you&#8217;re not using ssh-agent (I like keychain from Gentoo, or SSHKeyChain for Mac OS X), do whatever you have to do to ensure that your keychain is running.</li>
<li><strong>Make sure your private key is added to the ssh key agent</strong>: Do a &#8216;ssh-add -l&#8217; to check that ssh-agent has your key. Likewise, if you are using something else, check your keychain application has your private key.</li>
<li><strong>Check the permissions on your home directory, .ssh directory, and the authorized_keys file</strong>: If your ssh server is running with &#8216;StrictModes on&#8217;, it will refuse to use your public keys in the ~/.ssh/authorized_keys file. Your home directory should be writable only by you, ~/.ssh should be 700, and authorized_keys should be 600.</li>
</ul>
<p>Tailing the authentication log was the clincher for me this time &#8211; my problem was the group permissions on the home folder were incorrectly set (the error message I got from auth.log was: &#8216;Authentication refused: bad ownership or modes for directory /home/chuyeow&#8217;). Just had to fix it so it was no longer group-writable. Of course, this can also be fixed by turning setting &#8216;StrictModes off&#8217; in your sshd config (/etc/ssh/sshd_config), but it&#8217;s not really recommended. Plus, you may not always have the rights to edit that file anyway.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.codefront.net/2007/02/28/debugging-ssh-public-key-authentication-problems/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>Sharing a USB printer from Mac OS X to Windows</title>
		<link>http://blog.codefront.net/2007/02/05/sharing-a-usb-printer-from-mac-os-x-to-windows/</link>
		<comments>http://blog.codefront.net/2007/02/05/sharing-a-usb-printer-from-mac-os-x-to-windows/#comments</comments>
		<pubDate>Mon, 05 Feb 2007 12:47:08 +0000</pubDate>
		<dc:creator>Chu Yeow</dc:creator>
				<category><![CDATA[Mac]]></category>
		<category><![CDATA[Operating Systems]]></category>

		<guid isPermaLink="false">http://blog.codefront.net/2007/02/05/sharing-a-usb-printer-from-mac-os-x-to-windows/</guid>
		<description><![CDATA[Not too long ago I was asked to use hook up the Mac Mini that was collecting dust in our office to our HP Deskjet printer (HP Deskjet 1280 to be exact) and have it function as a &#8220;print server&#8221; of sorts (we have since replaced it with a NAS with print server functionality, which [...]]]></description>
			<content:encoded><![CDATA[<p>Not too long ago I was asked to use hook up the Mac Mini that was collecting dust in our office to our HP Deskjet printer (HP Deskjet 1280 to be exact) and have it function as a &#8220;print server&#8221; of sorts (we have since replaced it with a <acronym title="Network Attached Storage">NAS</acronym> with print server functionality, which subsequently broke &#8211; that&#8217;s how long this post has been sitting in my drafts folder). While setting it up to be shared with Mac machines was a cinch (we have a grand total of 3 Mac machines in the office, including the Mac Mini and my treasured MacBook Pro), sharing the printer from the Mac (Mini) to Windows machines was significantly more difficult. After some trial and error, first with what made the most sense, and then with stuff I could glean off the Internet, I finally arrived at something that works. Maybe this would be useful for the next unfortunate bloke that needs to do this sharing of printers from Mac to Windows machines without a print server.</p>
<p>First point of reference: <a href="http://www.macosxhints.com/article.php?story=20040208122655345">Print from Windows XP to a shared Mac printer tip on Mac OS X Hints</a>. The tip suggests you select a PostScript driver in Windows after finding it on the network (which requires you to do several things first, but we will come to that later). This worked, but it was <strong>sub-optimal</strong> because you couldn&#8217;t use the printer driver software to do stuff like 2-up printing (i.e. print 2 pages per side per sheet). This post will show you how to share a USB printer from Mac OS X to Windows PCs with <strong>full driver capability</strong>.</p>
<ol>
<li>On the Mac (the one that the USB printer that you want to share is connected to), go to the Sharing preferences pane and ensure <strong>Printer Sharing</strong> and <strong>Windows Sharing</strong> are both turned on.</li>
<li>Fire up your browser and go to <a href="http://127.0.0.1:631">http://127.0.0.1:631</a> &#8211; this is the web interface to <a href="http://www.cups.org/"><acronym title="Common UNIX Printing System">CUPS</acronym></a>. When asked to enter a password, login with your Mac OS X user account (it has to be an administrator account).</li>
<li>Go to the Printers tab and <strong>add a new printer</strong> (yes, <em>in addition</em> to any existing printer configuration that already exist for the same printer). Choose a name that&#8217;s short and descriptive (no spaces). For the purposes of this guide, let&#8217;s call it &#8216;uberprinter&#8217;. Best to keep it under 12 characters since Windows is finicky.</li>
<li>When asked to select a device, select <strong>USB printer</strong>.</li>
<li>You&#8217;ll be asked for a Device URI. To find out, open up a terminal and type <code>lpinfo -v</code>. You should see your USB printer coming up. Mine came up as &#8216;direct usb://HP/Deskjet%201280?serial=CN516851RPUN&#8217;. Copy and paste this (<strong>without the &#8216;direct&#8217; part</strong> &#8211; i.e., I&#8217;d have copied &#8216;usb://HP/Deskjet%201280?serial=CN516851RPUN&#8217;) into the &#8216;Device URI&#8217; field.</li>
<li>Select a &#8216;Make&#8217; of &#8216;<strong>Raw</strong>&#8216;. Keep going until the printer is added.</li>
<li>You&#8217;re <strong>done configuring from the Mac</strong>. But before you go, determine your Mac&#8217;s IP address (do a &#8216;ifconfig&#8217; in a shell or fire up System Profiler and check out the &#8216;Network&#8217; item) &#8211; note it down somewhere. Now it&#8217;s time to hook up your Windows machine to use the shared printer.</li>
<li>OK now go to your Windows machine and add a new printer (Control Panel -> Printers and Faxes). Select &#8216;A network printer&#8230; blah blah&#8217;. Don&#8217;t browse for the printer, you will enter its IP address directly in the &#8216;URL&#8217; field. Enter &#8216;http://your.macs.ip.address:631/printers/uberprinter&#8217; (replacing &#8216;your.macs.ip.address&#8217; with your Mac&#8217;s IP address and &#8216;uberprinter&#8217; with the short name you gave your printer). If you can&#8217;t remember your printer&#8217;s name, just scurry back to the Mac and browse to <a href="http://127.0.0.1:631/printers/">http://127.0.0.1:631/printers/</a>. You should be able to see the printer you added listed there &#8211; its name is linked there.</li>
<li>Now, all that&#8217;s left is to install the correct Windows printer driver on the Windows machine. If you&#8217;re lucky Windows already has your driver, if not do whatever you need to get the proper driver &#8211; after all, the purpose of jumping through all these hoops is to get full printer driver functionality off the shared Mac printer.</li>
</ol>
<p>That&#8217;s it. That&#8217;ll teach you for not getting a print server or one of those new printers with network functionality.</p>
<h3>Problems?</h3>
<p>Some readers wrote in with their own difficulties and have kindly allowed me to share their solutions. First off, Patrick McKrell who had a solution for cases where you still are just not able to print from the Windows machine (it involves killing a daemon so it&#8217;s pretty sweet).</p>
<blockquote><p>Thank you for making available your instructions for sharing a USB printer connected to a Mac using OS X with a Windows PC.  All of your points worked flawlessly on the Mac.  My Mac is a B&#038;W G3 running OS X 10.2.8.  The printer is an HP PSC 1510.</p>
<p>&#8230;</p>
<p>Back to Windows Add Printer.  Is my driver there? No.  I browsed the Windows file system to Program Files/HP/.  No luck.  Couldn&#8217;t find or add my driver.  Next I unplugged the printer&#8217;s USB cable from the Mac and into the PC.  Windows detected the new hardware, created whatever files it needed, and automatically created the USB-connected PSC 1500 series printer in Printers and Faxes.  Well, that&#8217;s pretty darn close. I opened the printer&#8217;s properties, changed the port from USB to Internet Port (as per your configuration guidance), sent a print job&#8230;.and nothing.  Hmmm.</p>
<p>Finally, I recalled seeing someone&#8217;s web post &#8211;thanks to your point of reference.  I followed the poster&#8217;s instructions, and, yeah, it prints, and in color.  Thanks again, Chu, for your post.  It was easy to follow, and importantly, it worked with my setup (despite the color issue).</p>
<p>Patrick McKrell</p></blockquote>
<p>The solution? Change your CUPS configuration to allow raw printing:</p>
<blockquote><p>Basically, I saw that every job on the windows side had &#8220;error&#8221;.</p>
<p>After looking at the error logs for cups on the mac box (/var/log/cups/), I noticed this line repeatedly:</p>
<p>print_job: Unsupported format &#8216;application/octet-stream&#8217;!</p>
<p>Did some googling, and found a post with the answer:</p>
<p> ><br />
 > You probably need to uncomment the following lines in<br />
 > /etc/cups/mime.types and /etc/cups/mime.convs:<br />
 ><br />
 ><br />
 > <strong>/etc/cups/mime.types</strong>:<br />
 > #application/octet-stream<br />
 ><br />
 ><br />
 > <strong>/etc/cups/mime.convs</strong>:<br />
 > #application/octet-stream application/vnd.cups-raw 0<br />
 > -<br />
 ><br />
 ><br />
 > That will allow raw printing.</p>
<p>Then, kill -HUP the cups daemon, and you&#8217;re good to go.</p></blockquote>
]]></content:encoded>
			<wfw:commentRss>http://blog.codefront.net/2007/02/05/sharing-a-usb-printer-from-mac-os-x-to-windows/feed/</wfw:commentRss>
		<slash:comments>94</slash:comments>
		</item>
		<item>
		<title>One stupid thing you can do with a UNIX shell and root access</title>
		<link>http://blog.codefront.net/2007/02/05/one-stupid-thing-you-can-do-with-a-unix-shell-and-root-access/</link>
		<comments>http://blog.codefront.net/2007/02/05/one-stupid-thing-you-can-do-with-a-unix-shell-and-root-access/#comments</comments>
		<pubDate>Mon, 05 Feb 2007 12:06:39 +0000</pubDate>
		<dc:creator>Chu Yeow</dc:creator>
				<category><![CDATA[Operating Systems]]></category>

		<guid isPermaLink="false">http://blog.codefront.net/2007/02/05/one-stupid-thing-you-can-do-with-a-unix-shell-and-root-access/</guid>
		<description><![CDATA[sudo chown -R dick / instead of sudo chown -R dick ./ You won&#8217;t be able to su &#8211; or sudo to chown the ownerships back properly because the sudo executable needs to be owned by root. Some people should never have unfettered sudo rights&#8230; like me.]]></description>
			<content:encoded><![CDATA[<pre><code>sudo chown -R dick /</code></pre>
<p>instead of</p>
<pre><code>sudo chown -R dick ./</code></pre>
<p>You won&#8217;t be able to su &#8211; or sudo to chown the ownerships back properly because the sudo executable needs to be owned by root. Some people should never have unfettered sudo rights&#8230; like me.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.codefront.net/2007/02/05/one-stupid-thing-you-can-do-with-a-unix-shell-and-root-access/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
	</channel>
</rss>

