<?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>Odynia.org blogOdynia.org blog</title>
	<atom:link href="http://blog.odynia.org/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.odynia.org</link>
	<description>I write about things.</description>
	<lastBuildDate>Wed, 17 Oct 2012 12:01:28 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	
		<item>
		<title>OmniGraffle Stencil for Amazon Web Services (AWS)</title>
		<link>http://blog.odynia.org/2012/10/omnigraffle-stencil-for-amazon-web-services-aws/</link>
		<comments>http://blog.odynia.org/2012/10/omnigraffle-stencil-for-amazon-web-services-aws/#comments</comments>
		<pubDate>Wed, 17 Oct 2012 12:01:28 +0000</pubDate>
		<dc:creator>Rob</dc:creator>
				<category><![CDATA[Apple / Mac / iOS]]></category>
		<category><![CDATA[aws]]></category>
		<category><![CDATA[omnigraffle]]></category>

		<guid isPermaLink="false">http://blog.odynia.org/?p=631</guid>
		<description><![CDATA[So I got annoyed at the available AWS Stencils on Graffletopia. Like many other stencils they end up being an image embedded inside a shape. For the most part this is OK: the shapes scale reasonably nicely. There is some occasional stretching if you want to try a different aspect ratio, but it works. The [...]]]></description>
				<content:encoded><![CDATA[<p>So I got annoyed at the available AWS Stencils on <a href="http://www.graffletopia.com/">Graffletopia</a>. Like many other stencils they end up being an image embedded inside a shape. For the most part this is OK: the shapes scale reasonably nicely. There is some occasional stretching if you want to try a different aspect ratio, but it works.</p>
<p>The problem comes when you try to snap objects to it with magnets or edit the shapes in any way. You realise its just a square box with an image inside. You can&#8217;t remove elements, change colours or manipulate it in any way.</p>
<p>Additionally, the existing set didn&#8217;t have any labels so you would need to check regularly as to what they all were.</p>
<p>So I set out to see if I couldn&#8217;t create better shapes from the Amazon&#8217;s <a href="http://aws.amazon.com/architecture/icons/">original vector icons</a>.</p>
<p>My results are linked at the bottom and are going up on Graffletopia shortly.</p>
<p>To make this I used the following process:</p>
<ol>
<li>Download and unzip the EPS/SVG package available <a href="http://media.amazonwebservices.com/architecturecenter/icons/AWS_Simple_Icons_svg_eps.zip">here</a>.</li>
<li>Using Terminal, change to the downloaded directory, and then to the subdirectory <code>eps_v1.4</code>.</li>
<li>Convert the EPS files to PDF using <code>pstopdf</code>:<br />
<pre class="crayon-plain-tag">$ mkdir pdf
$ for i in *.eps; do pstopdf &quot;$i&quot; -o &quot;pdf/$i.pdf&quot;; done</pre>
</li>
<li>The PDF files will now be available in the <code>pdf</code> subdirectory.</li>
<li>In OmniGraffle, touch the cog at the top of the Stencil window and select <em>New Stencil</em>.</li>
<li>Now, if you drag the converted PDF files to the OmniGraffle icon in your dock it will create a new graffle document (called Untitled) with the PDF contents converted to shapes.</li>
<li><em>Don&#8217;t just drag the pdf files directly into your graffle documents, this will just add the PDF&#8217;s preview image (a PNG) to your document.</em></li>
</ol>
<p>Note: I did try the Visio stencils first thinking that might be easier but OmniGraffle Pro 5.4.2 (v139.16) did not like them at all.</p>
<p>Anyway, the resulting stencils are available <a href="http://shana.odynia.org/downloads/AWS.zip">here</a>. To use, extract the zip file and drag the <code>AWS</code> folder into <code>Library/Application Support/The Omni Group/OmniGraffle/Stencils/</code>.</p>
<p>-Rob</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.odynia.org/2012/10/omnigraffle-stencil-for-amazon-web-services-aws/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>jubeat plus / jukebeat: An iOS Game Review</title>
		<link>http://blog.odynia.org/2012/10/jubeat-plus-jukebox-plus-an-ios-game-review/</link>
		<comments>http://blog.odynia.org/2012/10/jubeat-plus-jukebox-plus-an-ios-game-review/#comments</comments>
		<pubDate>Wed, 17 Oct 2012 08:02:33 +0000</pubDate>
		<dc:creator>Rob</dc:creator>
				<category><![CDATA[App Review]]></category>
		<category><![CDATA[iOS]]></category>
		<category><![CDATA[iPad]]></category>
		<category><![CDATA[iPhone]]></category>
		<category><![CDATA[japan]]></category>
		<category><![CDATA[jubeat]]></category>

		<guid isPermaLink="false">http://blog.odynia.org/?p=557</guid>
		<description><![CDATA[Let&#8217;s get it out-of-the-way up front: I like arcades. So much so that I spent a good chunk of time in my not-so-recent (May 2012) trip to Japan in their arcades (Taito Stations, Game Stations, etc) throwing 100円 coins in pachinko, slots and UFO machines (or skill testers as they are more commonly referred to [...]]]></description>
				<content:encoded><![CDATA[<div id="attachment_580" class="wp-caption alignright" style="width: 256px"><a href="http://www.flickr.com/photos/st3f4n/2949366095/"><img class="size-full wp-image-580" title="TaitoStation" src="http://blog.odynia.org/wp-content/uploads/2012/09/2949366095_02ee824d3f_n.jpg" alt="" width="246" height="320" /></a><p class="wp-caption-text">Photo: <a href="http://www.flickr.com/photos/st3f4n/">Stéfan</a></p></div>
<p>Let&#8217;s get it out-of-the-way up front: I like arcades. So much so that I spent a good chunk of time in my not-so-recent (May 2012) trip to Japan in their arcades (Taito Stations, Game Stations, etc) throwing 100円 coins in pachinko, slots and UFO machines (or skill testers as they are more commonly referred to here). There is a huge variety of video games available in a Japanese arcade that you could  easily blow your large chunks of your travel budget there, unlike the typical fare in the Australian equivalents.</p>
<p>But I digress; while there are many posts that could be written on the Japanese arcade, this one is about my favourite of them: <a href="http://www.konami-asia.com/bemani/jubeat/copious/whats/?lang=en">Konami&#8217;s Jubeat</a> machines (the Engrish on that site is great).</p>
<p>While I initially avoided them due to lack of familiarity I did eventually give them a go in Kyoto at an arcade on Kawaramachi-dori. And I was hooked, first go. It&#8217;s a simple concept, like Guitar Hero and its cohorts: tap the squares in time with the music.</p>
<p>Unlike Guitar Hero et al, Jubeat&#8217;s main screen is actually inside the squares themselves. A 4&#215;4 grid of plastic squares contain the displays that prompt your interaction; the squares light up in sequence and you hit them at the appropriate time, in harmony with the music, to score points.</p>
<p>Anyway, while attempting to find an iOS game that might replicate the functionality of the original game I discovered that KONAMI&nbsp;had released the original game to the app store as <a href="http://itunes.apple.com/au/app/jukebeat/id447276082?mt=8">jukebeat</a> (Australian/US Store) or <a href="http://itunes.apple.com/jp/app/jubeat-plus/id395192484?l=en&amp;mt=8">jubeat plus</a> (Japanese iTunes Store link). Imagine my surprise! An opportunity to throw hours at the game that capitivated me in Japan without the need to feed the machine 100円 coins.</p>
<div id="attachment_592" class="wp-caption alignright" style="width: 235px"><a href="http://blog.odynia.org/wp-content/uploads/2012/09/450px-Jubeat_copious_hontai.jpg" rel="lightbox[557]"><img class="size-medium wp-image-560" title="Jubeat Copious" src="http://blog.odynia.org/wp-content/uploads/2012/09/450px-Jubeat_copious_hontai-225x300.jpg" alt="" width="225" height="300" /></a><p class="wp-caption-text">jubeat copious. Source: Wikimedia Commons</p></div>
<p>I installed the original Japanese version of the game (as that is the one I fell for, after all; but a Japanese iTunes account is required) but a few minutes with the jukebeat game from the Australian stores suggests they are the same, aside from the available music. The game itself is free. Konami charges for additional music tracks available via in-app purchase, should you wish to progress beyond the three bundled songs.</p>
<p>Each track has three levels available: a Basic level for beginner and intermediate players, an Advanced level, and an Extreme level for those who consider themselves insane. Naturally the levels are arranged in order of difficultly from 1-10, with your typical Basic level running 1-5, Advanced 5-8 and Extreme 7-10.</p>
<p>Playing the game by yourself can be quite amusing, hit the Single button to start a song on your own and attempt to beat your own score. Your performance is ranked a <strong>Failure</strong> (D and below), or <strong>Clear</strong> (C, B, A, S, SS and SSS). Hitting every square at the right time during the song will net you a <strong>Full Combo</strong>.</p>
<p>The difficulty curve is quite decent, though some games of the same level vary in difficulty; presumably that comes down to your playing style. It is pretty simple to learn to play though, and quite hard to master.</p>
<p>The music choice is varied. Interestingly, a decent chunk of the Japanese music is available via in-app purchase in the Australian/US version but not vice-versa. The majority of the music available is stuff that KONAMI has created themselves &#8211; either as originals for the game (KONAMI or copious packs) or from other games they have created. There&#8217;s a few packs in there from pop/rock/oldies though so it mixes it up reasonably well.</p>
<p>Additionally, you can host and join games (much like the original jubeat machines which are networked) over the local network and bluetooth (I was unable to find anyone willing to subject themselves to humiliating defeat in a match against me); just pick your song and host a game. Likewise Game Centre is built in, its depressing looking at the leader boards though.</p>
<p>But the proof is in the pudding: I&#8217;ve spent about ~40 hours playing since I rediscovered it a few weeks back. It is rather addictive; the innocent thought &#8220;one more go&#8221; common among the pounding of the iOS device screen. Speaking of, I&#8217;ve found it easier to play on my iPad than my iPhone (Giraffe Phone or otherwise) as you can use full hands and many fingers to play. My iPad has so far survived several dozen drummings without being worse for wear; but gentle players need not hammer the screen at all, just press carefully.</p>
<p>My advice: give it a go. It&#8217;s great fun and can be quite addictive. And if you&#8217;re after a challenge on a real jubeat machine, the old Hollywood Karaoke building on Bourke St in the Melbourne CBD (next to Hungry Jacks) has an arcade with two Jubeat machines. Be ready to take a pocket of shiny gold coins though: $1 will buy you four songs.</p>
<p>-Rob</p>
<p>&nbsp;</p>
<table style="text-align: center; width: auto !important;" border="0" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td><a href="http://blog.odynia.org/wp-content/uploads/2012/10/mzl.rrzejuzi.640x960-75.jpg" rel="lightbox[557]"><img class="size-medium wp-image-622" title="mzl.rrzejuzi.640x960-75" src="http://blog.odynia.org/wp-content/uploads/2012/10/mzl.rrzejuzi.640x960-75-200x300.jpg" alt="" width="200" height="300" /></a></td>
<td><a href="http://blog.odynia.org/wp-content/uploads/2012/10/mzl.ryuizdqj.640x960-75.jpg" rel="lightbox[557]"><img class="size-medium wp-image-620" title="mzl.ryuizdqj.640x960-75" src="http://blog.odynia.org/wp-content/uploads/2012/10/mzl.ryuizdqj.640x960-75-200x300.jpg" alt="" width="200" height="300" /></a></td>
</tr>
</tbody>
</table>
<p>PS. For fun, here&#8217;s someone attempting one of the bundled songs (Japanese version) on Extreme:</p>
<p><iframe width="420" height="315" src="http://www.youtube.com/embed/0gXylm-eiE4" frameborder="0" allowfullscreen=""></iframe></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.odynia.org/2012/10/jubeat-plus-jukebox-plus-an-ios-game-review/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Installing Apache and Its Ecosystem: Part 2</title>
		<link>http://blog.odynia.org/2012/07/installing-apache-and-its-ecosystem-part-2/</link>
		<comments>http://blog.odynia.org/2012/07/installing-apache-and-its-ecosystem-part-2/#comments</comments>
		<pubDate>Fri, 13 Jul 2012 09:00:21 +0000</pubDate>
		<dc:creator>Rob</dc:creator>
				<category><![CDATA[Server Build]]></category>
		<category><![CDATA[apache]]></category>
		<category><![CDATA[freebsd]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[ports]]></category>
		<category><![CDATA[server build]]></category>
		<category><![CDATA[shana]]></category>

		<guid isPermaLink="false">http://blog.odynia.org/?p=485</guid>
		<description><![CDATA[Back here in Apache Land it is time to continue with the install. In this post I&#8217;ll be installing PHP. Part 3 will cover Subversion, and Part 4 I&#8217;ll be running through my standard configuration and website setup. Installing PHP 5.4.4 At the time of writing PHP 5.4.4 is the current stable release of PHP, [...]]]></description>
				<content:encoded><![CDATA[<p>Back here in Apache Land it is time to continue with the install. In this post I&#8217;ll be installing PHP. Part 3 will cover Subversion, and Part 4 I&#8217;ll be running through my standard configuration and website setup.</p>
<h2>Installing PHP 5.4.4</h2>
<p>At the time of writing PHP 5.4.4 is the current stable release of PHP, so we&#8217;ll be installing that and a dozen or so modules. I used to be a PHP developer in a past life (or so it feels, sometimes) so there are a lot of modules I used to make regular use of.</p>
<p>Additionally, I run a lot of the usual software like WordPress, Roundcube,  Gallery2, WebSVN, etc.</p>
<p>A quick look at the modules installed on Tyrande (the existing server):</p><pre class="crayon-plain-tag">[root@tyrande /]$ php -m
# [PHP Modules]
# bz2
# Core
# ctype
# curl
# date
# dom
# ereg
# fileinfo
# filter
# gd
# gettext
# hash
# iconv
# imap
# json
# ldap
# libxml
# mbstring
# mcrypt
# mhash
# mysql
# mysqli
# openssl
# pcre
# PDO
# pdo_mysql
# pdo_pgsql
# pdo_sqlite
# pgsql
# posix
# Reflection
# session
# SimpleXML
# snmp
# soap
# sockets
# SPL
# SQLite
# ssh2
# standard
# tidy
# tokenizer
# xml
# xmlreader
# xmlwriter
# zip
# zlib
# 
# [Zend Modules]

[root@tyrande /]$</pre><p></p>
<p>Read on for full installation instructions..<br />
<span id="more-485"></span></p>
<p>Back on Shana, let&#8217;s go installing! We&#8217;ll be using the ports tree for the installation, so make sure it is up to date.</p>
<p>We want the following options in the port config:</p>
<ul>
<li>CLI (default)</li>
<li>APACHE</li>
<li>IPV6 (default)</li>
<li>LINKTHR (default)</li>
</ul>
<p></p><pre class="crayon-plain-tag">[root@shana /]$ cd /usr/ports/lang/php5

[root@shana /usr/ports/lang/php5]$ make install clean
# ===&amp;gt;  License PHP301 accepted by the user
# ===&amp;gt;  Found saved configuration for php5-5.4.4
# =&amp;gt; php-5.4.4.tar.bz2 doesn't seem to exist in /usr/ports/distfiles/.
# &amp;lt;snip&amp;gt;
# ***************************************************************
#
# Make sure index.php is part of your DirectoryIndex.
# 
# You should add the following to your Apache configuration file:
# 
# AddType application/x-httpd-php .php
# AddType application/x-httpd-php-source .phps
# 
# ***************************************************************
# &amp;lt;snip&amp;gt;
# ===&amp;gt;  Cleaning for apache-2.2.22_5
# ===&amp;gt;  Cleaning for php5-5.4.4</pre><p>Once we&#8217;ve installed PHP we can check what modules are installed by default:</p><pre class="crayon-plain-tag">[root@shana /usr/ports/lang/php5]$ php -m
# [PHP Modules]
# Core
# date
# ereg
# libxml
# mysqlnd
# pcre
# Reflection
# SPL
# standard
# 
# [Zend Modules]</pre><p>Not many at all. Fortunately, installing the rest is easy, if a little bit time consuming. Lets start with <em>bz2</em>.</p>
<h3>Installing PHP Modules</h3>
<p>Modules are available to be installed through ports also. This is rather useful as it will check for dependencies and install those if necessary. To install a module, you need to locate its port. The ports are generally named <code>php5-&lt;modulename&gt;</code>, like so:</p><pre class="crayon-plain-tag">[root@shana /usr/ports/lang/php5]$ whereis php5-bz2
php5-bz2: /usr/ports/archivers/php5-bz2</pre><p>To install it, change over to there and run the usual <code>make install clean</code>.</p><pre class="crayon-plain-tag">[root@shana /usr/ports/lang/php5]$ cd /usr/ports/archivers/php5-bz2
[root@shana /usr/ports/archivers/php5-bz2]$ make install clean
# ===&amp;gt;  License PHP301 accepted by the user
# ===&amp;gt;  Extracting for php5-bz2-5.4.4
# =&amp;gt; SHA256 Checksum OK for php-5.4.4.tar.bz2.
# ===&amp;gt;  Patching for php5-bz2-5.4.4
# ===&amp;gt;   php5-bz2-5.4.4 depends on file: /usr/local/bin/phpize - found
# ===&amp;gt;   php5-bz2-5.4.4 depends on file: /usr/local/bin/autoconf-2.69 - found
# ===&amp;gt;  PHPizing for php5-bz2-5.4.4
# Configuring for:
# PHP Api Version:         20100412
# Zend Module Api No:      20100525
# Zend Extension Api No:   220100525
# &amp;lt;snip&amp;gt;
# ===&amp;gt;  Installing for php5-bz2-5.4.4
# ===&amp;gt;   php5-bz2-5.4.4 depends on file: /usr/local/include/php/main/php.h - found
# ===&amp;gt;   Generating temporary packing list
# ===&amp;gt;  Checking if archivers/php5-bz2 already installed
# ===&amp;gt;   Registering installation for php5-bz2-5.4.4
# ****************************************************************************
#
# The following line has been added to your /usr/local/etc/php/extensions.ini
# configuration file to automatically load the installed extension:
# 
# extension=bz2.so
# 
# ****************************************************************************
# ===&amp;gt;  Cleaning for php5-bz2-5.4.4</pre><p>What happens is the following:</p>
<ol>
<li>It extracts the PHP source into a separate working directory.</li>
<li>Changes into the extensions subdirectory.</li>
<li>Runs <code>phpize</code>, which will setup the subdirectory with your local PHP configuration ready to build.</li>
<li>Runs <code>./configure</code> in the extension&#8217;s subdirectory.</li>
<li>Runs <code>make</code> in the extension&#8217;s subdirectory.</li>
<li>Runs <code>make install</code> to install the extension and activates it in your <code>/usr/local/etc/php/extensions.ini</code></li>
</ol>
<p>Pretty easy, yes? It gets even easier. If you&#8217;ve installed <em>portupgrade</em> (and you should if you haven&#8217;t), you can condense the above into a single command:</p><pre class="crayon-plain-tag">[root@shana /]$ portinstall php5-dom
# [Updating the pkgdb &amp;lt;format:bdb_btree&amp;gt; in /var/db/pkg ... - 74 packages found (-0 +0)  done]
# [Gathering depends for textproc/php5-dom ................................................... done]
# ** Port marked as IGNORE: www/apache22:
# 	Do not install. Installed manually.
# ---&amp;gt;  Skipping 'textproc/php5-dom' because a requisite port 'www/apache22' failed (specify -k to force)
# ** Listing the failed packages (-:ignored / *:skipped / !:failed)
# 	- www/apache22
# 	* textproc/php5-dom</pre><p>You will see that that failed because the dependency of apache22 is marked as IGNORE. What can we do? Just run <code>portinstall -k &lt;portname&gt;</code> and it will install it anyway.</p><pre class="crayon-plain-tag">[root@shana /]$ portinstall -k php5-dom
[Gathering depends for textproc/php5-dom ................................................... done]
# ---&amp;gt;  Installing 'php5-dom-5.4.4' from a port (textproc/php5-dom)
# ---&amp;gt;  Building '/usr/ports/textproc/php5-dom'
# ===&amp;gt;  Cleaning for php5-dom-5.4.4
# &amp;lt;snip&amp;gt;
# ===&amp;gt;  License PHP301 accepted by the user
# ===&amp;gt;  Extracting for php5-dom-5.4.4
# =&amp;gt; SHA256 Checksum OK for php-5.4.4.tar.bz2.
# ===&amp;gt;  Patching for php5-dom-5.4.4
# ===&amp;gt;   php5-dom-5.4.4 depends on file: /usr/local/bin/phpize - found
# ===&amp;gt;   php5-dom-5.4.4 depends on file: /usr/local/bin/autoconf-2.69 - found
# ===&amp;gt;   php5-dom-5.4.4 depends on executable: pkg-config - found
# ===&amp;gt;   php5-dom-5.4.4 depends on shared library: xml2.5 - found
# ===&amp;gt;  PHPizing for php5-dom-5.4.4</pre><p>You can repeat this for the rest of your modules.</p>
<p>WARNING: Some of these ports have dependencies on x11 (the graphical user interface). To prevent ports from installing x11, you need to add <code>WITHOUT_X11=yes</code> to your <code>/etc/make.conf</code>.</p>
<p>Then you can install whatever modules you need.</p><pre class="crayon-plain-tag">[root@shana /]$ portinstall php5-ctype
[root@shana /]$ portinstall php5-curl
[root@shana /]$ portinstall php5-fileinfo
[root@shana /]$ portinstall php5-filter
[root@shana /]$ portinstall php5-gd
[root@shana /]$ portinstall php5-gettext
[root@shana /]$ portinstall php5-hash
[root@shana /]$ portinstall php5-iconv
[root@shana /]$ portinstall php5-imap
[root@shana /]$ portinstall php5-json
[root@shana /]$ portinstall php5-ldap
[root@shana /]$ portinstall php5-mbstring
[root@shana /]$ portinstall php5-mcrypt
[root@shana /]$ portinstall php5-mysql
[root@shana /]$ portinstall php5-mysqli
[root@shana /]$ portinstall php5-openssl
[root@shana /]$ portinstall php5-pdo
[root@shana /]$ portinstall php5-pdo_mysql
[root@shana /]$ portinstall php5-pgsql
[root@shana /]$ portinstall php5-pdo_pgsql
[root@shana /]$ portinstall php5-sqlite3
[root@shana /]$ portinstall php5-pdo_sqlite
[root@shana /]$ portinstall php5-posix
[root@shana /]$ portinstall php5-session
[root@shana /]$ portinstall php5-simplexml
[root@shana /]$ portinstall php5-snmp
[root@shana /]$ portinstall php5-soap
[root@shana /]$ portinstall php5-ssh2
[root@shana /]$ portinstall php5-tidy
[root@shana /]$ portinstall php5-tokenizer
[root@shana /]$ portinstall php5-xml
[root@shana /]$ portinstall php5-xmlreader
[root@shana /]$ portinstall php5-xmlwriter
[root@shana /]$ portinstall php5-zip
[root@shana /]$ portinstall php5-zlib</pre><p></p>
<h2>Enabling PHP support in Apache</h2>
<p>Now that we&#8217;re setup, the last step is to enable support for PHP in Apache. It will have already done one step of this process for us, adding this line:</p>
<pre class="crayon-plain-tag">LoadModule php5_module &nbsp; &nbsp; &nbsp; &nbsp;/usr/local/libexec/apache22/libphp5.so</pre>
<p>to your <code>/var/www/conf/httpd.conf</code> file.</p>
<p>The other bit, as mentioned above when we installed PHP is to add the .php extension.</p>
<p>Open up your <code>/var/www/conf/httpd.conf</code> file, and search for the existing AddType references. It shows up on about line 359 for me.</p>
<p>Add these in anywhere there; I put mine in after the <code>AddType application/x-gzip .gz .tgz</code> line.</p>
<pre class="crayon-plain-tag">AddType application/x-httpd-php .php
AddType application/x-httpd-php-source .phps</pre>
<p>And we&#8217;re done! In the next part we&#8217;ll install Subversion, then in Part 4 we configure Apache and setup some websites.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.odynia.org/2012/07/installing-apache-and-its-ecosystem-part-2/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Installing Apache and its Ecosystem: Part 1</title>
		<link>http://blog.odynia.org/2012/07/installing-apache-and-its-ecosystem-part-1/</link>
		<comments>http://blog.odynia.org/2012/07/installing-apache-and-its-ecosystem-part-1/#comments</comments>
		<pubDate>Tue, 10 Jul 2012 07:20:21 +0000</pubDate>
		<dc:creator>Rob</dc:creator>
				<category><![CDATA[Server Build]]></category>
		<category><![CDATA[apache]]></category>
		<category><![CDATA[freebsd]]></category>
		<category><![CDATA[http]]></category>
		<category><![CDATA[ports]]></category>
		<category><![CDATA[server build]]></category>
		<category><![CDATA[shana]]></category>

		<guid isPermaLink="false">http://blog.odynia.org/?p=475</guid>
		<description><![CDATA[I guess it is time for the big boy. Apache can be one of the most complicated things you install, mostly for the additional languages and modules. Like many, I have my own way of configuring it. I&#8217;ll lay this out up front: I don&#8217;t like the FreeBSD layout for Apache. Everything is scattered throughout [...]]]></description>
				<content:encoded><![CDATA[<p>I guess it is time for the big boy. Apache can be one of the most complicated things you install, mostly for the additional languages and modules. Like many, I have my own way of configuring it.</p>
<p>I&#8217;ll lay this out up front: I don&#8217;t like the FreeBSD layout for Apache. Everything is scattered throughout <code>/usr/local</code> and buried deep in the system. I got used to using the OpenBSD layout during my stint with that OS, and so I continue to use that on FreeBSD. It puts everything in <code>/var/www/</code> and keeps it nice and clean together.</p>
<p>That said, the binaries and other bits and pieces should remain in <code>/usr/local/</code>.</p>
<h2>Building from Scratch</h2>
<p>For once we&#8217;re not going to install Apache from ports. Why? Because it&#8217;s too damn hard to adjust the layout without building a completely custom port. What we can do though is use the ports tree to do a big chunk of the work for us.</p>
<h3>Configure your options</h3>
<p>Run <code>make config</code> in the port and select the options you want installed. I go with the defaults here usually.</p><pre class="crayon-plain-tag">[root@shana /]$ cd /usr/ports/www/apache22
[root@shana /usr/ports/www/apache22]$ make config</pre><p></p>
<h3>Install the dependencies</h3>
<p>Now that we&#8217;ve selected our options, we can also use it to build and install the dependencies, much the same as we would do if we were installing Apache through ports.</p><pre class="crayon-plain-tag">[root@shana /usr/ports/www/apache22]$ make depends
# ===&amp;gt;   apache-2.2.22_5 depends on file: /usr/local/bin/perl5.12.4 - found
# ===&amp;gt;   apache-2.2.22_5 depends on file: /usr/local/bin/perl5.12.4 - found
# ===&amp;gt;   apache-2.2.22_5 depends on shared library: expat - found
# ===&amp;gt;   apache-2.2.22_5 depends on shared library: apr-1 - found
# ===&amp;gt;   apache-2.2.22_5 depends on shared library: pcre - found
# ===&amp;gt;   apache-2.2.22_5 depends on shared library: iconv.3 - found
# ===&amp;gt;   apache-2.2.22_5 depends on file: /usr/local/bin/perl5.12.4 - found
# ===&amp;gt;   apache-2.2.22_5 depends on file: /usr/local/bin/autoconf-2.69 - found
# ===&amp;gt;   apache-2.2.22_5 depends on package: libtool&amp;gt;=2.4 - found
# ===&amp;gt;   apache-2.2.22_5 depends on file: /usr/local/bin/perl5.12.4 - found</pre><p>So that is everything we should need.</p>
<h3>Generating the configure command</h3>
<p>Now we let the port install get as far as configuring the build, that will generate the <code>configure</code> command that was used, and we can copy that command and use it to build our own setup.</p><pre class="crayon-plain-tag">[root@shana /usr/ports/www/apache22]$ make configure
#
#  To enable a module category: WITH_&amp;lt;CATEGORY&amp;gt;_MODULES
#  To disable a module category: WITHOUT_&amp;lt;CATEGORY&amp;gt;_MODULES
#
#  Per default categories are:
#   AUTH AUTHN AUTHZ DAV CACHE MISC
#  Categories available:
#   AUTH AUTHN AUTHZ CACHE DAV EXPERIMENTAL LDAP  MISC PROXY SSL SUEXEC THREADS
#
#   To see all available knobs, type make show-options
#   To see all modules in different categories, type make show-categories
#   You can check your modules configuration by using make show-modules
#
# ===&amp;gt;  Found saved configuration for apache-2.2.22_5
# ===&amp;gt;  Extracting for apache-2.2.22_5
# &amp;lt;snip&amp;gt;
# config.status: creating include/ap_config_auto.h
# config.status: executing default commands</pre><p></p>
<h2>Setting up our own build environment</h2>
<p>Now we&#8217;ve had our fun with ports it is time to build our own copy of Apache. I do my compilation in a directory called <code>/archive/compile</code>, but you can do it anywhere you like.<br />
<span id="more-475"></span></p>
<h3>Grab the source</h3>
<p>Ports will have also downloaded the source for you, so you can just extract it directly.</p><pre class="crayon-plain-tag">[root@shana /archive/compile]$ tar -zxf /usr/ports/distfiles/apache22/httpd-2.2.22.tar.bz2 
[root@shana /archive/compile]$ cd httpd-2.2.22/
[root@shana /archive/compile/httpd-2.2.22]$</pre><p></p>
<h3>Create our custom layout</h3>
<p>Now we also need to add the layout to the <code>config.layout</code> file. Just add this to the bottom of <code>/archive/compile/httpd-2.2.22/config.layout</code>.</p><pre class="crayon-plain-tag">#   iTransit Layout
&amp;lt;Layout iTransit&amp;gt;
    prefix:        /var/www
    exec_prefix:   /usr/local
    bindir:        ${exec_prefix}/bin
    sbindir:       ${exec_prefix}/sbin
    libdir:        ${exec_prefix}/lib
    libexecdir:    ${exec_prefix}/libexec/apache22 
    mandir:        ${exec_prefix}/man      
    sysconfdir:    ${prefix}/conf
    datadir:       ${prefix}
    installbuilddir: ${exec_prefix}/share/apache22/build
    errordir:      ${prefix}/error
    iconsdir:      ${prefix}/icons
    htdocsdir:     ${prefix}/htdocs
    manualdir:     ${exec_prefix}/share/doc/apache22
    cgidir:        ${prefix}/cgi-bin
    includedir:    ${exec_prefix}/include/apache22  
    localstatedir: ${prefix}
    runtimedir:    ${prefix}/logs
    logfiledir:    ${prefix}/logs
    proxycachedir: ${prefix}/proxy
&amp;lt;/Layout&amp;gt;</pre><p>This layout is a mixture of the FreeBSD and OpenBSD layouts.</p>
<h3>Obtain the configure script</h3>
<p>When you run <code>configure</code> it will create a file called <code>config.nice</code> that has the command used to call <code>configure</code>. Copy it to your current directory under a different name. This would work for most people:</p><pre class="crayon-plain-tag">[root@shana /archive/compile/httpd-2.2.22]$ cp /usr/ports/www/apache22/work/httpd-2.2.22/config.nice t.sh</pre><p>It would create a file called <code>t.sh</code> in your local directory. If, like me, you&#8217;ve moved your ports working directory, check under that.</p><pre class="crayon-plain-tag">[root@shana /archive/compile/httpd-2.2.22]$ cp /usr/obj/usr/ports/www/apache22/work/httpd-2.2.22/config.nice t.sh</pre><p></p>
<h3>Customise the configure script</h3>
<p>You can now modify your <code>t.sh</code> file to make whatever adjustments you need to <code>configure</code>. In my case we want to use the custom layout we added above. Open up <code>t.sh</code> and change line 9 from:</p><pre class="crayon-plain-tag">&quot;--enable-layout=FreeBSD&quot; \</pre><p>to</p><pre class="crayon-plain-tag">&quot;--enable-layout=iTransit&quot; \</pre><p>Then head on down to line 59 and delete the prefix line, otherwise it will overwrite the prefix specified in the layout.</p><pre class="crayon-plain-tag">&quot;--prefix=/usr/local&quot; \</pre><p></p>
<h3>Applying Patches</h3>
<p>There are a couple of FreeBSD-specific patches that we should really apply before we start compiling it. Without these, your custom build of Apache won&#8217;t build at all.</p>
<p>Patches can be found in <code>/usr/ports/www/apache22/files/</code>, we&#8217;ll take what we need and apply them directly.</p><pre class="crayon-plain-tag">[root@shana /archive/compile/httpd-2.2.22]$ patch &amp;lt;/usr/ports/www/apache22/files/patch-server__util_pcre.c 
# Hmm...  Looks like a unified diff to me...
# The text leading up to this was:
# --------------------------
# |--- server/util_pcre.c.orig	2005-11-10 16:20:05.000000000 +0100
# |+++ server/util_pcre.c	2012-02-13 23:11:17.898984171 +0100
# --------------------------
# Patching file server/util_pcre.c using Plan A...
# Hunk #1 succeeded at 137.
# done</pre><p>So that&#8217;s one done, lets do the rest.</p><pre class="crayon-plain-tag">[root@shana /archive/compile/httpd-2.2.22]$ patch &amp;lt;/usr/ports/www/apache22/files/patch-configure.in
[root@shana /archive/compile/httpd-2.2.22]$ patch &amp;lt;/usr/ports/www/apache22/files/patch-modules__proxy__mod_proxy_connect.c
[root@shana /archive/compile/httpd-2.2.22]$ patch &amp;lt;/usr/ports/www/apache22/files/patch-server__core.c
[root@shana /archive/compile/httpd-2.2.22]$ patch &amp;lt;/usr/ports/www/apache22/files/patch-support__Makefile.in
[root@shana /archive/compile/httpd-2.2.22]$ patch &amp;lt;/usr/ports/www/apache22/files/patch-support__ab.c 
[root@shana /archive/compile/httpd-2.2.22]$ patch &amp;lt;/usr/ports/www/apache22/files/patch-support__apachectl.in
[root@shana /archive/compile/httpd-2.2.22]$ patch &amp;lt;/usr/ports/www/apache22/files/patch-support__apxs.in</pre><p></p>
<h2>Installing Apache</h2>
<p>Now we can build and install Apache the same way we would for anything else we&#8217;re building from source.</p>
<h3>Running configure</h3>
<p>To configure the source directory with all the pre-requisites, just run the <code>t.sh</code> command from earlier.</p><pre class="crayon-plain-tag">[root@shana /archive/compile/httpd-2.2.22]$ ./t.sh
# checking for chosen layout... iTransit
# checking for working mkdir -p... yes
# &amp;lt;snip&amp;gt;
# config.status: creating include/ap_config_auto.h
# config.status: executing default commands</pre><p></p>
<h3>Building the Source</h3>
<p>So the <em>configure</em> completed successfully, now we just run <em>make</em>.</p><pre class="crayon-plain-tag">[root@shana /archive/compile/httpd-2.2.22]$ make
# Making all in srclib
# Making all in os
# Making all in unix
&amp;lt;snip&amp;gt;
# /usr/local/share/apr/build-1/libtool --silent --mode=link cc -g -I/usr/local/include  -O2 -pipe -I/usr/include -fno-strict-aliasing  -rpath=/usr/lib:/usr/local/lib -L/usr/lib -L/usr/local/lib -L/usr/local/lib/db42  -rpath=/usr/lib:/usr/local/lib -L/usr/lib    -o mod_rewrite.la -rpath /usr/local/libexec/apache22 -module -avoid-version  mod_rewrite.lo</pre><p></p>
<h3>Creating the users</h3>
<p>If you haven&#8217;t already, we&#8217;ll need to create the users. The port normally does this for you but it is a requirement that it is done. Run the following commands:</p><pre class="crayon-plain-tag">[root@shana /archive/compile/httpd-2.2.22]$ pw groupadd -n www -g 80
[root@shana /archive/compile/httpd-2.2.22]$ pw useradd -n www -u 80 -d /nonexistent -g www -s /usr/sbin/nologin</pre><p>Installing Apache</p>
<p>Now that that is all done, lets install this beast.</p><pre class="crayon-plain-tag">[root@shana /archive/compile/httpd-2.2.22]$ make install
# Making install in srclib
# Making install in os
# Making install in unix
# &amp;lt;snip&amp;gt;
# Installing configuration files
# mkdir /var/www/conf
# mkdir /var/www/conf/extra
# mkdir /var/www/conf/original
# mkdir /var/www/conf/original/extra
# Installing HTML documents
# mkdir /var/www/htdocs
# Installing error documents
# mkdir /var/www/error
# Installing icons
# mkdir /var/www/icons
# Installing CGIs
# mkdir /var/www/cgi-bin
# Installing header files
# Installing build system files
# Installing man pages and online manual</pre><p>All installed! And in the correct places too.</p>
<h3>Creating the <em>rc</em> scripts</h3>
<p>Now we just need to create the necessary <em>rc</em> files to control starting/stopping Apache. Fortunately ports has us covered there too. We just need some minor modifications to the ones supplied with ports in order to get our very on <code>/usr/local/etc/rc.d/apache22</code> and <code>/usr/local/etc/rc.d/htcacheclean</code> files.</p><pre class="crayon-plain-tag">[root@shana /archive/compile/httpd-2.2.22]$ cat /usr/ports/www/apache22/files/apache22.in | sed 's/%%PREFIX%%/\/usr\/local/g' &amp;gt; /usr/local/etc/rc.d/apache22
[root@shana /archive/compile/httpd-2.2.22]$ cat /usr/ports/www/apache22/files/htcacheclean.in | sed 's/%%PREFIX%%/\/usr\/local/g' &amp;gt; /usr/local/etc/rc.d/htcacheclean</pre><p></p>
<h3>Preventing the port from installing</h3>
<p>The other thing we will want to do is prevent the port from installing. In some cases another port will have Apache listed as a dependency. Ports, being the clever thing it is, will attempt to install those missing dependencies for you, which will blow away your custom Apache install.</p>
<p>Lets mark the port as forbidden, add this to the top of <code>/usr/ports/www/apache22/Makefile</code>:</p>
<pre class="crayon-plain-tag">FORBIDDEN= &nbsp; &nbsp; &nbsp; Do not install. This was installed manually.</pre>
<p>And that&#8217;s it. We&#8217;re finished.</p>
<p>In the next part, I&#8217;ll setup some test virtual hosts, install PHP and Subversion.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.odynia.org/2012/07/installing-apache-and-its-ecosystem-part-1/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Firewalling: The OpenBSD Packet Filter</title>
		<link>http://blog.odynia.org/2012/07/firewalling-the-openbsd-packet-filter/</link>
		<comments>http://blog.odynia.org/2012/07/firewalling-the-openbsd-packet-filter/#comments</comments>
		<pubDate>Mon, 09 Jul 2012 14:00:15 +0000</pubDate>
		<dc:creator>Rob</dc:creator>
				<category><![CDATA[Server Build]]></category>
		<category><![CDATA[dns]]></category>
		<category><![CDATA[firewall]]></category>
		<category><![CDATA[freebsd]]></category>
		<category><![CDATA[http]]></category>
		<category><![CDATA[imap]]></category>
		<category><![CDATA[mail]]></category>
		<category><![CDATA[pf]]></category>
		<category><![CDATA[pop3]]></category>
		<category><![CDATA[server build]]></category>
		<category><![CDATA[shana]]></category>
		<category><![CDATA[smtp]]></category>
		<category><![CDATA[ssh]]></category>

		<guid isPermaLink="false">http://blog.odynia.org/?p=463</guid>
		<description><![CDATA[It is time to get security conscious! Installing and using pf for your firewall is a breeze, so this post will mostly be describing my firewall configuration and some of the awesome things you can do. Warning: This is another long one. I use the OpenBSD Packet Filter, or pf, for my server-level firewall. Why? [...]]]></description>
				<content:encoded><![CDATA[<p>It is time to get security conscious! Installing and using <em>pf</em> for your firewall is a breeze, so this post will mostly be describing my firewall configuration and some of the awesome things you can do.</p>
<p>Warning: This is another long one.</p>
<p>I use the <a href="http://www.openbsd.org/faq/pf/">OpenBSD Packet Filter</a>, or <em>pf</em>, for my server-level firewall. Why? Based originally on <em>ipf</em>, I find it to be much simpler and more powerful than the usual tools like <em>iptables</em>. How powerful? One line will normalise all incoming traffic. Normalisation is the process of cleaning up bad or invalid packets that can wreak havoc in poorly written server software.</p>
<p>It has the usual port filtering and Network Address Translation (NAT) features, plus traffic redirection (port forwarding),  Operating System-based filtering, packet queuing, prioritisation, address pools, and load balancing. Yep, when paired with <em>CARP</em> (the Common Address Redundancy Protocol), <em>pf</em> can bring you the same level of redundancy and load balancing as enterprise level Cisco gear. I had a series of four servers setup in an old workplace, each was redundant for the other using <em>CARP</em> + <em>pf.</em> You could even control the order of failover across all four servers.</p>
<p>Anyway, <em>pf</em> is installed by default, we just need to setup our rules and enable it. The first thing you need to know though, is <strong>don&#8217;t turn it on with untested</strong> <strong>rules</strong>. If you do you&#8217;re more than likely to lock yourself out of the server, at which point you&#8217;d better hope your console access is working.</p>
<p>Before we dive into my configuration, an overview of the configuration file is probably in order. A <em>pf.conf</em> file is generally broken into several sections.</p>
<table class="blogTable" width="100%" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<th>Macros</th>
<td>Variables that you can set to be re-used later on.</td>
</tr>
<tr>
<th>Tables</th>
<td>Variables that can hold a list of data, like a list of IP Addresses</td>
</tr>
<tr>
<th>Options</th>
<td>Options that control how <em>pf</em> functions.</td>
</tr>
<tr>
<th>Queuing</th>
<td>Rules and options to support queuing and prioritisation</td>
</tr>
<tr>
<th>Filter Rules</th>
<td>The bulk of your firewall ruleset, providing port filtering, NAT and traffic redirection.</td>
</tr>
</tbody>
</table>
<p>Now, while my general configuration has a few interesting things you can do with <em>pf</em>, it is actually rather boring compared to some setups I&#8217;ve done in the past. I don&#8217;t use traffic redirection, queuing, prioritisation or load balancing. It&#8217;s just a server firewall.</p>
<p>The most useful resource you will find for <em>pf</em> is the <a href="http://www.openbsd.org/faq/pf/">OpenBSD FAQ page</a> on the topic.</p>
<p>Read on for my configuration and the step by step instructions to set it up.<br />
<span id="more-463"></span></p>
<h2>My Entire Configuration</h2>
<p>This is my <em>/etc/pf.conf</em> file in its entirety.</p>
<pre class="crayon-plain-tag">#
# Shana pf.conf
#

# Variables
ext_if = &quot;bge0&quot;
ext_ip = &quot;( &quot; $ext_if &quot; )&quot;

# Tables
table persist file '/etc/pf.china'
table persist file '/etc/pf.korea'
table persist
table persist file '/etc/pf.blacklist'

#
# Options
#

# Return a reset for all blocks
set block-policy return

# Gather stats for the primary interface
set loginterface bge0

# Ignore the loopback
set skip on lo0

# Normalisation
scrub in all

#
# Rules
#

# Default deny
block log all

# Anything in the blacklist should be stopped here
block in quick on $ext_if from to any
block in quick on $ext_if from to any
block in quick on $ext_if from to any
block in quick on $ext_if from to any

# Outgoing traffic
pass out on $ext_if proto { tcp, udp } from $ext_ip to any keep state

# Allow ICMP traffic
pass proto icmp all

# Allow SSH
pass in on $ext_if proto tcp from any to $ext_ip port 22 flags S/SA keep state (max-src-conn-rate 5/60, overload flush global)
pass out on $ext_if proto tcp from $ext_ip to any port 22 keep state

# NTP
pass out on $ext_if proto { tcp, udp } from $ext_ip to any port ntp keep state

# Allow web
pass in on $ext_if proto tcp from any to $ext_ip port { 80, 443 } keep state
pass out on $ext_if proto tcp from $ext_ip to any port { 80, 443 } keep state

# Allow mail
pass in on $ext_if proto tcp from any to $ext_ip port { 25, 143, 993, 995 } keep state
pass out on $ext_if proto tcp from $ext_ip to any port { 25, 143, 993, 995 } keep state

# Allow DNS
pass in on $ext_if proto { tcp, udp } from any to $ext_ip port 53 keep state
pass out on $ext_if proto { tcp, udp } from $ext_ip to any port 53 keep state</pre>
<h2>My Configuration Explained</h2>
<p>There&#8217;s a lot there, so lets step through that one section at a time.</p>
<h3>Macros and Tables</h3>
<pre class="crayon-plain-tag"># Variables
ext_if = &quot;bge0&quot;
ext_ip = &quot;( &quot; $ext_if &quot; )&quot;</pre>
<p>Here we set a couple of very simple variables.</p>
<table class="blogTable" width="100%" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<th>ext_if</th>
<td>A variable that holds our external network interface name. For this series of HP servers that I use, it is <em>bge0</em>. This allows me to reference <em>$ext_if</em> anywhere I need to specify the interface name.</td>
</tr>
<tr>
<th>ext_ip</th>
<td>A variable that holds our external IP. The contents of the variable is actually &#8220;( bge0 )&#8221; when expanded. <em>pf</em> will automatically add any IP addresses on that interface to the ruleset when this setup is used. So if you add another or change the IP address on bge0, the firewall updates automatically.</td>
</tr>
</tbody>
</table>
<pre class="crayon-plain-tag"># Tables
table persist file '/etc/pf.china'
table persist file '/etc/pf.korea'
table persist
table persist file '/etc/pf.blacklist'</pre>
<p>And some very simple tables. The <em>&lt;china&gt;</em> and <em>&lt;korea&gt;</em> tables load up a couple of files. Those files contain a list (a list with an IP Address or subnet on each line) of subnets that are typically in use in China and Korea, respectively. Why do I block those? I do no business with anyone in those countries, and don&#8217;t host any resources they might need. However, putting a blanket block on those ranges dramatically reduces the amount of security issues I have to deal with. Everything from attempts to bruteforce my SSH server (more on this later) to worms hitting my websites.</p>
<p>The <em>&lt;ssh_bruteforce&gt;</em> is a special table that holds IP Addresses of people who have attempted to bruteforce the SSH server, and the<em> <em>&lt;blacklist&gt;</em></em> table holds ranges and IP addresses that I&#8217;ve blacklisted manually. More on those two at the end of this post.</p>
<h3>PF Options</h3>
<p>Here I set some of the <a href="http://www.openbsd.org/faq/pf/options.html">runtime options</a> for <em>pf</em>. One by one they are:</p>
<pre class="crayon-plain-tag"># Return a reset for all blocks
set block-policy return</pre>
<p>This will cause <em>pf</em> to return a reset on blocked packets. By default most firewalls will just silently drop blocked packets, which means the connecting client has to wait for a timeout on their end. I return a reset for a couple of reasons:</p>
<ul>
<li>Client performance. If I&#8217;m trying to connect to the server but specify the wrong port it gets annoying, you either need to kill your connection and try again, or wait for the timeout. This penalises legitimate connections to your server.</li>
<li>Security. Port scanning tools like <a href="http://nmap.org/">nmap</a>know the difference between a blocked (dropped packet) and a closed port. So if you&#8217;re scanned while dropping packets, it will return a list of all ports that are open (you&#8217;re running a service on that port), ports that are closed (the port isn&#8217;t firewalled, but there is no service listening on that port), and ports that are firewalled. This gives a potential attacker extra information; that you are running a firewall, and that some services that are normally running aren&#8217;t running.If you return a reset, though, then all ports are either open or closed and the scanner doesn&#8217;t know if it is because they&#8217;re firewalled or not.</li>
</ul>
<pre class="crayon-plain-tag"># Gather stats for the primary interface
set loginterface bge0</pre>
<p>This line sets our log interface. <em>pf </em>will gather statistics on that interface, like packets and bytes in/out. In my case I want to gather statistics for all traffic on my external interface.</p>
<pre class="crayon-plain-tag"># Ignore the loopback
set skip on lo0</pre>
<p>And a simple skip mechanism for the loopback. This means that any traffic sent to localhost/127.0.0.1 on the loopback interface won&#8217;t be filtered by the firewall. After all, if the traffic is already internal to the server filtering it again won&#8217;t be much help, but processing all loopback traffic could be a large performance hit on your server.</p>
<h3>Normalisation</h3>
<p>Here is a one of the niceties that found their origins in <em>pf</em>. I&#8217;m not sure if it&#8217;s available in other firewalls or not these days, but it&#8217;s certainly useful.</p>
<pre class="crayon-plain-tag"># Normalisation
scrub in all</pre>
<p>From the FAQ:</p>
<blockquote><p>&#8220;Scrubbing&#8221; is the normalization of packets so there are no ambiguities in interpretation by the ultimate destination of the packet. The scrub directive also reassembles fragmented packets, protecting some operating systems from some forms of attack, and drops TCP packets that have invalid flag combinations.</p></blockquote>
<p>Pretty cool, eh? For this rule we&#8217;re just scrubbing on the <strong>in</strong> direction.</p>
<h3>Port Filtering</h3>
<p>Now we get into the meat of my setup. Let&#8217;s dive right in:</p>
<pre class="crayon-plain-tag"># Default deny
block log all</pre>
<p>This is the default behaviour. It is a good idea at this point to mention that <em>pf</em> will run a packet through an entire ruleset and use the rule that it matched <strong>last</strong>. (Unless you use the <em>quick</em> keyword, see the next bit).</p>
<p>This means that you put your default behaviour at the top of your ruleset, and then your allow rules after it. So by default I block everything that comes in, then specifically allow ports that I want to be open.</p>
<p>As this is the first rule we&#8217;ve encountered, it might be good to explain the syntax. The <a href="http://www.openbsd.org/faq/pf/filter.html">FAQ</a> also explains it in painstaking detail.</p>
<table class="blogTable" width="100%" cellspacing="0">
<tbody>
<tr>
<th style="width: 30%;">block</th>
<td>The action, usually either <em>block</em> or <em>pass</em>.</td>
</tr>
<tr>
<th>log</th>
<td>We drop in a log keyword to tell <em>pf</em> to log any packets that match this rule.</td>
</tr>
<tr>
<th>all</th>
<td>And the additional filtering. Normally you put the from/to address and port matching here. <em>all</em> simply expands to match everything.</td>
</tr>
</tbody>
</table>
<pre class="crayon-plain-tag"># Anything in the blacklist should be stopped here
block in quick on $ext_if from to any
block in quick on $ext_if from to any
block in quick on $ext_if from to any
block in quick on $ext_if from to any</pre>
<p>This is where our blacklists are configured. The <em>quick</em> keyword tells <em>pf</em> to stop processing the rules that follow if the packet matches. I don&#8217;t log these blocks. We&#8217;ve expanded the syntax here, so another breakdown might be good.</p>
<table class="blogTable" width="100%" cellspacing="0">
<tbody>
<tr>
<th style="width: 30%;">block</th>
<td>The action, usually either <em>block</em> or <em>pass</em>.</td>
</tr>
<tr>
<th>in</th>
<td>The direction. <em>in</em> for incoming packets, <em>out</em> for outgoing, and left blank for both.</td>
</tr>
<tr>
<th>quick</th>
<td>The <em>quick</em> keyword causes <em>pf</em> to stop processing the rules that follow, and execute the action in this rule.</td>
</tr>
<tr>
<th>on $ext_if</th>
<td>Our <em>on &lt;interface&lt; matching checks that the packet is travelling through the specified interface.</em></td>
</tr>
<tr>
<th>from &lt;blacklist&gt;</th>
<td>This is a standard <em>from</em> statement. It matches against the source IP address. You can specify an IP address, subnet, list of addresses/subnets or a table. See the <a href="http://www.openbsd.org/faq/pf/filter.html">FAQ</a> for more <em>from</em> and <em>to</em> syntax options.</td>
</tr>
<tr>
<th>to any</th>
<td>Another shortcut, this time using the <em>to</em> keyword to match against the packet&#8217;s destination. <em>any</em> expands to be any valid IP address (0.0.0.0/0).</td>
</tr>
</tbody>
</table>
<pre class="crayon-plain-tag"># Outgoing traffic
pass out on $ext_if proto { tcp, udp } from $ext_ip to any keep state</pre>
<p>This is our first <em>pass</em> rule, and an important one at that. It allows all outgoing traffic on the external interface.</p>
<table class="blogTable" width="100%" cellspacing="0">
<tbody>
<tr>
<th style="width: 30%;">pass</th>
<td>The action, in this case we&#8217;re <em>pass</em>ing the packet, or allowing it through the firewall.</td>
</tr>
<tr>
<th>out</th>
<td>The direction, outgoing.</td>
</tr>
<tr>
<th>on $ext_if</th>
<td>Travelling through our external network interface.</td>
</tr>
<tr>
<th>proto { tcp, udp }</th>
<td>Using either the TCP or UDP protocols. You can specify a list of values like this for almost any keyword, just put them in braces ({}), separated by commas.</td>
</tr>
<tr>
<th>from $ext_ip</th>
<td>From our external IP Address. This is important as it means any service on our server that tries to send a packet as an IP Address other than our configured one will be blocked.</td>
</tr>
<tr>
<th>to any</th>
<td>To any valid IP Address on the Internet.</td>
</tr>
<tr>
<th>keep state</th>
<td>What to do with the state information for the packet. In almost all cases you want <em>pf</em> to keep your state, which is the default behaviour.</td>
</tr>
</tbody>
</table>
<pre class="crayon-plain-tag"># Allow ICMP traffic
pass proto icmp all</pre>
<p>Allow all ICMP traffic. Some people who are extremely security conscious may block all ICMP traffic, but I find it invaluable for monitoring and troubleshooting. You&#8217;re left to yourself to decide how pedantic you want to get with ICMP filtering.</p>
<h3>Filtering for Specific Services</h3>
<p>Here is where things get interesting. We now go in and allow specific services (ports) through the firewall.</p>
<pre class="crayon-plain-tag"># NTP
pass out on $ext_if proto { tcp, udp } from $ext_ip to any port ntp keep state</pre>
<p>This will allow NTP traffic out from our local server to any NTP server on port 123 (NTP).</p>
<p>But wait, if I&#8217;ve already passed all outgoing traffic, what is this rule for? Simple: statistics. The <em>loginterface</em> we specified above does more than just do general statistics for the interface, it does it for <strong>every rule on that interface</strong>.<em></em> That means by adding a more specific pass rule, even if the packet was already passed, we can get statistics on how many packets out and bytes out for this rule. I do this for all services I host so I can get detailed stats on how much bandwidth each is consuming. There will be a follow up post that goes into detail on the stats I consume and where I get them from.</p>
<pre class="crayon-plain-tag"># Allow web
pass in on $ext_if proto tcp from any to $ext_ip port { 80, 443 } keep state
pass out on $ext_if proto tcp from $ext_ip to any port { 80, 443 } keep state</pre>
<p>These two rules allow incoming (and the corresponding outgoing) packets to our local web server on ports 80 (HTTP) and 443 (HTTPS).</p>
<pre class="crayon-plain-tag"># Allow mail
pass in on $ext_if proto tcp from any to $ext_ip port { 25, 143, 993, 995 } keep state
pass out on $ext_if proto tcp from $ext_ip to any port { 25, 143, 993, 995 } keep state</pre>
<p>These two rules allow incoming and outgoing packets to our postfix and dovecot setup on ports 25 (SMTP), 143 (IMAP), 993 (IMAPS) and 995 (POP3S).</p>
<pre class="crayon-plain-tag"># Allow DNS
pass in on $ext_if proto { tcp, udp } from any to $ext_ip port 53 keep state
pass out on $ext_if proto { tcp, udp } from $ext_ip to any port 53 keep state</pre>
<p>These two rules allow DNS traffic to our server on port 53 (DNS).</p>
<pre class="crayon-plain-tag"># Allow SSH
pass in on $ext_if proto tcp from any to $ext_ip port 22 flags S/SA keep state (max-src-conn-rate 5/60, overload flush global)
pass out on $ext_if proto tcp from $ext_ip to any port 22 keep state</pre>
<p>And the fun one. These rules allow traffic to our SSH server on port 22 (SSH). The bit at the end is quite powerful, it is an extra you can do for your stateful connections and rate limiting, or blacklisting in my case.</p>
<p>When another server connects more than 5 times in 60 seconds (<em>max-src-conn-rate 5/60</em>), add the IP address to the table &lt;ssh_bruteforce&gt; (<em>overload &lt;ssh_bruteforce&gt;</em>) and kills any matching states for that IP (<em>flush global</em>). When coupled with the <em>block quick from &lt;ssh_bruteforce&gt;</em> rule above it means that any attacker that tries to brute force my SSH server gets five shots at it before they&#8217;re blacklisted.</p>
<p>It also means that if I connect more than 5 times in a minute that I&#8217;ll get blacklisted, but that hasn&#8217;t happen to me yet.</p>
<h2>Enabling <em>pf</em> and Testing the Configuration</h2>
<p>Now that our ruleset has been created (the ruleset goes into <em>/etc/pf.conf</em>, by the way), we can enable <em>pf</em> and get started with our testing.</p>
<p>To enable <em>pf</em>, just add the following to your <em>/etc/rc.conf</em>.</p>
<pre class="crayon-plain-tag">pf_enable=&quot;YES&quot;
pflog_enable=&quot;YES&quot;</pre>
<p><em>pflog</em> is the logging setup, if you don&#8217;t want to worry about logging then you don&#8217;t have to enable it.</p>
<p>Now the first thing you want to do before starting <em>pf</em> though is to check your rules. Run the following to parse your ruleset, but not load it.</p><pre class="crayon-plain-tag">[root@shana /]$ pfctl -nf /etc/pf.conf
# /etc/pf.conf:13: cannot load &quot;/etc/pf.china&quot;: No such file or directory
# /etc/pf.conf:14: cannot load &quot;/etc/pf.korea&quot;: No such file or directory
# /etc/pf.conf:16: cannot load &quot;/etc/pf.blacklist&quot;: No such file or directory</pre><p>Right, I need to populate those files first!</p><pre class="crayon-plain-tag">[root@shana /]$ scp xxx@172.16.0.13:/Volumes/Drobo/Backup/itransit/tyrande/etc/pf.{china,korea,blacklist} /etc/
# pf.china                                     100%    0     0.0KB/s   00:00    
# pf.korea                                     100%    0     0.0KB/s   00:00    
# pf.blacklist                                 100%    0     0.0KB/s   00:00</pre><p>A straight copy from the backups of Tyrande will do it. As mentioned, those files are just text files with an IP address or subnet on each line. Let&#8217;s try that parsing again now.</p><pre class="crayon-plain-tag">[root@shana /]$ pfctl -nf /etc/pf.conf

[root@shana /]$</pre><p>No errors? Great! Now the fun bit. To start <em>pf</em> and hope that you haven&#8217;t just locked yourself out, run:</p><pre class="crayon-plain-tag">[root@shana /]# /etc/rc.d/pf start
# Enabling pf
# No ALTQ support in kernel
# ALTQ related functions disabled
# No ALTQ support in kernel
# ALTQ related functions disabled
# Write failed: Broken pipe

[bok@Macbook ~]$</pre><p>Oh no. Looks like I just locked myself out! Even I&#8217;m not immune to this sort of trap either. The server is pingable, so it looks like the ICMP rule was correct. Better go plug in that console&#8230;</p>
<h2>So you&#8217;ve locked yourself out</h2>
<p>Right, now that I&#8217;ve connected a monitor and keyboard, lets see what the console says. There are a few commands here that you will find useful. For starters, you can list the loaded ruleset:</p><pre class="crayon-plain-tag">[root@shana /]$ pfctl -s rules
# No ALTQ support in kernel
# ALTQ related functions disabled
# scrub in all fragment reassemble
# block return log all
# &amp;lt;snip&amp;gt;
# pass in on bge0 proto udp from any to (bge0) port = domain keep state</pre><p>By the way, you can ignore the ALTQ warnings unless you&#8217;re looking for queuing and prioritisation support.</p>
<p>You can scan that to see what you did wrong, or you can check the logs. If you&#8217;ve enabled <em>pflog</em> support, then it will have created a psuedo-interface called <em>pflog0</em>. You can then use <em>tcpdump</em> to watch that interface, and <em>pf</em> will log all packets matched with a <em>log</em> keyword there.</p>
<p>The following <em>tcpdump</em> command line will show you what packets are being dropped, I&#8217;m not going to go into detail on it though as that is beyond the scope of this article. The last bit is useful though; I&#8217;ve lost SSH access on port 22 to the server. At the end of the <em>tcpdump</em> statement you usually put a filter; this is useful if you&#8217;re on a local network with Windows boxes that will be spouting crap all across your filters. All of which will be being logged now.</p>
<p>It is generally a good idea to be narrow in your troubleshooting if you can afford to be, it helps you be more specific and get to the bottom faster than wading through thousands of lines of the log. Anyway, lets go:</p><pre class="crayon-plain-tag">[root@shana /]$ tcpdump -A -e -ttt -i pflog0 port 22
# tcpdump: WARNING: pflog0: no IPv4 address assigned
# tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
# listening on pflog0, link-type PFLOG (OpenBSD pflog file), capture size 65535 bytes</pre><p>Now that we&#8217;re listening for logged packets, let&#8217;s try connecting again via SSH and see what comes up.</p>
<pre class="crayon-plain-tag">00:00:00.000000 rule 0..16777216/0(match): block in on bce0: 172.16.0.127.52101 &amp;gt; 172.16.0.4.ssh: Flags [S], seq 2892016496, win 65535, options [mss 1460,nop,wscale 3,nop,nop,TS val 854162648 ecr 0,sackOK,eol], length 0</pre>
<p>A matched packet! This tells you that a packet from 172.16.0.127 (my Macbook) bound for 172.16.0.4 (Shana) on port 22 was blocked using the rule <em>block in on bce0</em>.</p>
<p>Wait, <em>bce0?</em> Uh oh. Looks like the network driver in this server is different from my old server, hence it appears to have a different network interface name.</p><pre class="crayon-plain-tag">[root@shana /]$ ifconfig | grep flags
# bce0: flags=8843&amp;lt;UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST&amp;gt; metric 0 mtu 1500
# bce1: flags=8802&amp;lt;BROADCAST,SIMPLEX,MULTICAST&amp;gt; metric 0 mtu 1500
# lo0: flags=8049&amp;lt;UP,LOOPBACK,RUNNING,MULTICAST&amp;gt; metric 0 mtu 16384
# pflog0: flags=141&amp;lt;UP,RUNNING,PROMISC&amp;gt; metric 0 mtu 33152</pre><p>Yep, looks like I have <em>bce0</em> and <em>bce1</em> instead of <em>bge0</em> and <em>bge1</em> on this server. That should be a simple fix, open the <em>/etc/pf.conf</em> and update the <em>ext_if</em> Macro to use <em>bce0</em> instead.</p>
<p>We can then reload the ruleset and try connecting again.</p><pre class="crayon-plain-tag">[root@shana /]$ pfctl -f /etc/pf.conf
# No ALTQ support in kernel
# ALTQ related functions disabled</pre><p>Success! I can SSH back in, and <em>telnet</em>s to the other ports work as expected.<br />
<a name="sshlockdown"></a><br />
<h2>Update: Lets lock down SSH further (05/09/2012)</h2>
<p>So in the last few days the number of brute force connections against Shana have skyrocketed. Previously there would be 3-4 cracks at it a day (remembering that each remote host is blacklisted after 5 connection attempts), but now there are dozens and each attempt is trying password authentication at least three times per connection (the limit).</p>
<p>Why they didn&#8217;t do that previously I&#8217;m not sure, but here we are.</p>
<p>I discovered too that my blacklists for <code>/etc/pf.china</code> and <code>/etc/pf.korea</code> were empty. I found a website with a good database for it too over <a href="http://software77.net/geo-ip/">here</a>. In the right hand column pick your country, make sure CIDR format selected and copy/paste the resulting subnet list into your file.</p>
<p>Anyway, China and Korea aren&#8217;t the only countries with a high percentage of malware infected machines, they can come from anywhere and your server can&#8217;t be cut off from the entire world; that would defect the purpose. What we can do though is lock down SSH to our country of origin only. I&#8217;m 99% sure I&#8217;ll never need to SSH into Shana from outside of Australia, and if I did there are other hosts I can connect through anyway.</p>
<h3>Create the Australian table</h3>
<p>So lets create <code>/etc/pf.australia</code> with the Australian IP database. Then we can add a table for australia in our <code>/etc/pf.conf</code> up the top in the Tables section, like so:</p>
<pre class="crayon-plain-tag">table &amp;lt;australia&amp;gt; persist file '/etc/pf.australia'</pre>
<p>It&#8217;s a good idea to test several of the IP Addresses (like your home connection, work, etc) against your new table before we activate it, to make sure you won&#8217;t be locked out. To do that you can use <code>pfctl</code>.</p><pre class="crayon-plain-tag"># Reload the configuration file to activate our new table
[root@shana /]$ pfctl -f /etc/pf.conf

# Test an IP against the table
[root@shana /]$ pfctl -t australia -T test 202.62.159.130
# 1/1 addresses match.</pre><p>It&#8217;s a match! We can move on.</p>
<h3>Restrict SSH access to that table</h3>
<p>Now we can update the SSH rule to lock it down to the &lt;australia&gt; table:</p>
<pre class="crayon-plain-tag"># Allow SSH
pass in on $ext_if proto tcp from &lt;australia&gt; to $ext_ip port 22 flags S/SA keep state (max-src-conn-rate 5/60, overload &lt;ssh_bruteforce&gt; flush global)
pass out on $ext_if proto tcp from $ext_ip to &lt;australia&gt; port 22 keep state</pre>
<p>So here we change the <code>from any to $ext_ip</code> to be <code>from &lt;australia&gt; to $ext_ip</code>. Similarly with the pass out but reversed.</p>
<p>Restart <code>pf</code> and hope you don&#8217;t get locked out and we&#8217;re done. Those pesky security emails should be quieter now.</p>
<p>&nbsp;</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.odynia.org/2012/07/firewalling-the-openbsd-packet-filter/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>DNS Setup: The Pitfall of Bind</title>
		<link>http://blog.odynia.org/2012/07/dns-setup-the-pitfall-of-bind/</link>
		<comments>http://blog.odynia.org/2012/07/dns-setup-the-pitfall-of-bind/#comments</comments>
		<pubDate>Mon, 09 Jul 2012 10:52:39 +0000</pubDate>
		<dc:creator>Rob</dc:creator>
				<category><![CDATA[Server Build]]></category>
		<category><![CDATA[bind]]></category>
		<category><![CDATA[dns]]></category>
		<category><![CDATA[freebsd]]></category>
		<category><![CDATA[named]]></category>
		<category><![CDATA[server build]]></category>
		<category><![CDATA[shana]]></category>
		<category><![CDATA[SPF]]></category>

		<guid isPermaLink="false">http://blog.odynia.org/?p=453</guid>
		<description><![CDATA[DNS can be a vastly complicated thing, particularly setting up Bind the most common DNS server product in use. However, it doesn&#8217;t have to be scary. In this post I&#8217;ll go through setting up Bind and configuring a test domain. If you&#8217;re not sure what DNS is or how it works, hit up Google and [...]]]></description>
				<content:encoded><![CDATA[<p>DNS can be a vastly complicated thing, particularly setting up Bind the most common DNS server product in use. However, it doesn&#8217;t have to be scary.</p>
<p>In this post I&#8217;ll go through setting up Bind and configuring a test domain. If you&#8217;re not sure what DNS is or how it works, hit up Google and find out. <a href="http://www.howstuffworks.com/dns.htm">This article</a> by How Stuff Works isn&#8217;t too bad an overview either.</p>
<p>For my DNS setup, I run Bind as the master server, and have an account with <a href="https://web.easydns.com/">EasyDNS</a> for additional DNS servers that synchronise changes from the master server to their copy. This is more commonly known as a Secondary DNS.</p>
<p>Picture time! (I like pictures).</p>
<div id="attachment_454" class="wp-caption aligncenter" style="width: 499px"><a href="http://blog.odynia.org/wp-content/uploads/2012/07/Blog-DNS.png" rel="lightbox[453]"><img class="size-full wp-image-454" title="Blog DNS" src="http://blog.odynia.org/wp-content/uploads/2012/07/Blog-DNS.png" alt="" width="489" height="363" /></a><p class="wp-caption-text">Overview of my DNS Setup</p></div>
<p>What happens when a DNS request comes in (say you want to load this blog), is that your ISP&#8217;s DNS servers will lookup the name servers for my domain, which would return one of the four options above. At that point your ISP&#8217;s DNS server will pick one at random and ask it for the IP address of my blog (known as an A record). Your computer can then connect directly to the server and open the blog.</p>
<p>Each of the EasyDNS servers listed above is actually an <a href="https://web.easydns.com/our_nameservers.php">anycast constellation</a>, which means it has four or five DNS servers spread across the globe. For example, at the time of writing, the EasyDNS 1 constellation had servers in Ashburn, Chicago, San Jose, Amsterdam and Tokyo.</p>
<p>The EasyDNS servers stay in sync through a method called a zone transfer. When I update the records on Shana, she will send a message to the EasyDNS transfer server that there is an update available for a specific domain. EasyDNS then requests a zone transfer to grab the most recent copy of the DNS records for that domain and updates their local server records.</p>
<h2>Installing Bind</h2>
<p>That&#8217;s probably enough of an overview of my setup for now, lets get cracking on installing and configuring Bind. Fortunately, we don&#8217;t have to do anything here, Bind is already installed by default on FreeBSD.</p><pre class="crayon-plain-tag">[root@shana /]$ named -V
# BIND 9.8.1-P1 built with '--prefix=/usr' '--infodir=/usr/share/info' '--mandir=/usr/share/man' '--enable-threads' '--enable-getifaddrs' '--disable-linux-caps' '--with-openssl=/usr' '--with-randomdev=/dev/random' '--without-idn' '--without-libxml2'
# using OpenSSL version: OpenSSL 0.9.8q 2 Dec 2010</pre><p>It is worth noting here that the service/daemon that runs is actually called <em>named.</em> From here on out I&#8217;ll refer to everything using named as the product name &#8220;Bind&#8221; is rarely mentioned.</p>
<h2>Configuring Named</h2>
<p>As it is already installed, you can imagine that a good chunk of the setup is already done for you too. This is true, all of the named configuration files can be found in <em>/etc/namedb/</em>. Lets check what we have in there.</p><pre class="crayon-plain-tag">[root@shana /etc/namedb]$ ls -F -1
# dynamic/
# master/
# named.conf
# named.root
# slave/
# working/</pre><p></p>
<table class="blogTable" width="100%" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<th>dynamic/</th>
<td>A subdirectory where dynamic zones live. Dynamic zones are typically updatable by client systems.</td>
</tr>
<tr>
<th>master/</th>
<td>A subdirectory where master zones live. Master zones are ones where we (this server) are considered authoritative for.</td>
</tr>
<tr>
<th>named.conf</th>
<td>The main Named configuration file.</td>
</tr>
<tr>
<th>named.root</th>
<td>A list of the root name servers that make up the core of DNS.</td>
</tr>
<tr>
<th>slave/</th>
<td>A subdirectory where slave/secondary zones live. Slave zones are ones where we retrieve config via zone transfer from somewhere else.</td>
</tr>
<tr>
<th>working/</th>
<td>A subdirectory named keeps its working files.</td>
</tr>
</tbody>
</table>
<p>You might notice too that the <em>dynamic, slave</em> and <em>working</em> directories are owned and writable by the <em>bind</em> user. That is because named will write to these directories itself.</p>
<p>For this post, we&#8217;re only really interested in the <em>named.conf</em> file and the <em>master</em> subdirectory.<br />
<span id="more-453"></span></p>
<h3>General Configuration</h3>
<p>There are a few general setup items we need to change, these all exist inside the <em>options</em> directive.</p>
<p>Firstly, turn recursion off for an authoritative server. We don&#8217;t need to be serving requests from users for domains that we are not authoritative for. While it is unlikely someone will try to use us for recursive DNS, it is still a waste of CPU cycles and network if they do.</p>
<pre class="crayon-plain-tag">recursion no;</pre>
<p>Secondly, if we&#8217;re serving domains we need to listen on the external IP address, otherwise no one can reach us.</p>
<pre class="crayon-plain-tag">listen-on { 127.0.0.1;; };</pre>
<h2>Adding a Zone</h2>
<p>Time to add our test zone! We&#8217;ll go ahead and setup a fake somedomain.com for testing <em>named</em>.</p>
<h3>Creating the Zone in named.conf</h3>
<p>Add the following to the bottom of your <em>/etc/namedb/named.conf</em> file.</p>
<pre class="crayon-plain-tag">// somedomain.com - A Test domain
zone &quot;somedomain.com&quot; {
type master;
file &quot;/etc/namedb/master/somedomain.com&quot;;
zone-statistics true;

allow-transfer { ww.xx.yy.zz; };
also-notify { ww.xx.yy.zz; };
};</pre>
<p>Please be very specific about the placement of your semicolons (;), otherwise it will fail. In more detail:</p>
<pre class="crayon-plain-tag">zone &quot;somedomain.com&quot; {</pre>
<p>This line starts a zone record, with the domain name of the zone. In this case it is <em>somedomain.com</em>.</p>
<pre class="crayon-plain-tag">type master;</pre>
<p>The type of zone, we want to be authoritative and returns results for this zone, so we&#8217;re the <em>master</em>.</p>
<pre class="crayon-plain-tag">file &quot;/etc/namedb/master/somedomain.com&quot;;</pre>
<p>This line tells <em>named</em> where to find the file that contains the DNS records for that zone.</p>
<pre class="crayon-plain-tag">zone-statistics true;</pre>
<p>I enable zone statistics on my zones for reporting and dashboards. With a simple script I can see how many requests are being served for this domain, etc. More detail on how to do this will follow in a later post.</p>
<pre class="crayon-plain-tag">allow-transfer { ww.xx.yy.zz; };</pre>
<p>By default, zone transfers are not allowed for any domain. This is for security reasons mostly as there is no need to let clients know all of the records you have. They might find your porn server, for instance. This line will allow specific IP Addresses to request a zone transfer for this domain.</p>
<pre class="crayon-plain-tag">also-notify { ww.xx.yy.zz; };</pre>
<p>To take it the step further, this line will cause<em> named</em> to notify the IP address(es) listed whenever the serial number on this zone is updated.</p>
<p>For a better overview of how your <em>named.conf</em> file works and the configuration options available, check out <a href="https://www.centos.org/docs/2/rhl-rg-en-7.2/s1-bind-configuration.html">this guide</a> from CentOS.</p>
<h2>Creating the Zone File</h2>
<p>I generally name the files in my <em>master/</em> subdirectory the same as the domain name themselves. Lets create our <em>somedomain.com</em> file and we&#8217;ll step through what it means.</p>
<pre class="crayon-plain-tag">;
; somedomain.com Zone File
;
; Created: 6 July 2012
; By: Rob Amos
;
$ORIGIN somedomain.com.
$TTL 6h

@ IN SOA shana.somedomain.com. postmaster.somedomain.com (
2012070601 ; serial number
1h ; refresh time
30m ; retry values
7d ; record cache expiry
1h ; minimum time to cache
)

; Name Servers
NS shana.somedomain.com.

; Mail Servers
MX 5 shana.somedomain.com.

; SPF Record
TXT &quot;v=spf1 mx:somedomain.com ~sll&quot;

; Subdomains
A 172.16.0.4
shana A 172.16.0.4
www CNAME shana.somedomain.com.</pre>
<p>And in some more detail:</p>
<pre class="crayon-plain-tag">$ORIGIN somedomain.com.</pre>
<p>The <em>$ORIGIN</em> record is the domain that would be appended to any unqualified records. Meaning that if you wrote <em>subdomain</em> instead of <em>subdomain.somedomain.com</em>, then the <em>somedomain.com</em> would be appended automatically.</p>
<pre class="crayon-plain-tag">$TTL 6h</pre>
<p>Our <em>$TTL</em> (Time to Live) value tells servers how long these records should remain valid for.</p>
<pre class="crayon-plain-tag">@ IN SOA shana.somedomain.com. postmaster.somedomain.com (
2012070601 ; serial number
1h ; refresh time
30m ; retry values
7d ; record cache expiry
1h ; minimum time to cache
)</pre>
<p>This is our <em>Start of Authority</em> record, more commonly known as the SOA. This provides information about the authoritative server and zone information for this domain. Read <a href="https://www.centos.org/docs/2/rhl-rg-en-7.2/s1-bind-configuration.html#BIND-RR-SOA-SAMPLE">this guide</a> for more info, but I will suggest you set the serial number to today&#8217;s date plus a two digit counter that you increment the more times you change it during that day.</p>
<p>The serial number is especially important when you&#8217;ve got slave or secondary name servers. They use the serial number to know whether they need to update your domain, so make sure you increment the serial number every time you make a change.</p>
<pre class="crayon-plain-tag">NS shana.somedomain.com.</pre>
<p>A name server record, there should be one of these for each of your servers, the order doesn&#8217;t matter.</p>
<pre class="crayon-plain-tag">MX 5 shana.somedomain.com.</pre>
<p>A Mail Exchange (MX) record. This tells email clients where to find your mail server. The number indicates the priority of the server record with the lowest number having the highest priority. Note the trailing dot (.), it is very important. If you do not put that there <em>named</em> will append <em>$ORIGIN</em> to the listed name.</p>
<pre class="crayon-plain-tag">TXT &quot;v=spf1 mx:somedomain.com ~all&quot;</pre>
<p>An SPF record. This one says that only the MX record for <em>subdomain.com</em> is allowed to send email for <em>somedomain.com</em>. Microsoft has a <a href="http://www.microsoft.com/mscorp/safety/content/technologies/senderid/wizard/">handy tool</a> to generate SPF records.</p>
<pre class="crayon-plain-tag">A 172.16.0.4
shana A 172.16.0.4</pre>
<p>Address (A) records. This maps a subdomain to an IP address. It is useful to note that column left blank will use the record before it. So we left the first column blank for all records until <em>shana</em>. That means it used the last one listed, which was the @ symbol. The @ refers to the domain itself, not a subdomain.</p>
<p>Likewise the second column (IN) is missing, its reused from above. So you could rewrite that second like this if you wanted.</p>
<pre class="crayon-plain-tag">@ IN NS shana.somedomain.com.
@ IN MX 5 shana.somedomain.com.
@ IN TXT &quot;v=spf1 mx:somedomain.com ~all&quot;
@ IN A 172.16.0.4
shana IN A 172.16.0.4</pre>
<p>One last one &#8211; a CNAME or alias record. Note the trailing dot again. This one will make <em>www.somedomain.com</em> an alias of <em>shana.somedomain.com</em>.</p>
<pre class="crayon-plain-tag">www CNAME shana.somedomain.com.</pre>
<p>Once again, the <a href="https://www.centos.org/docs/2/rhl-rg-en-7.2/s1-bind-configuration.html#S2-BIND-CONFIGURATION-ZONE">CentOS guide</a> has a good step by step and breakdown with more information on the Zone Files beyond my examples.</p>
<h2>Testing our Setup</h2>
<p>That&#8217;s effectively everything you need to setup. Enable <em>named</em> in your <em>/etc/named.conf</em> file and lets test it out.</p>
<pre class="crayon-plain-tag">named_enable=&quot;YES&quot;</pre>
<p>Starting <em>named:</em></p><pre class="crayon-plain-tag">[root@shana /]$ /etc/rc.d/named start
# wrote key file &quot;/var/named/etc/namedb/rndc.key&quot;
# Starting named.</pre><p>Check the logs to see if it was ok:</p><pre class="crayon-plain-tag">[root@ /]$ tail /var/log/messages
# Jul  9 20:29:41 shana named[15165]: starting BIND 9.8.1-P1 -t /var/named -u bind
# Jul  9 20:29:41 shana named[15165]: built with '--prefix=/usr' '--infodir=/usr/share/info' '--mandir=/usr/share/man' '--enable-threads' '--enable-getifaddrs' '--disable-linux-caps' '--with-openssl=/usr' '--with-randomdev=/dev/random' '--without-idn' '--without-libxml2'
# Jul  9 20:29:41 shana named[15165]: command channel listening on 127.0.0.1#953
# Jul  9 20:29:41 shana named[15165]: command channel listening on ::1#953
# Jul  9 20:29:41 shana named[15165]: managed-keys-zone ./IN: loading from master file managed-keys.bind failed: file not found
# Jul  9 20:29:41 shana named[15165]: running</pre><p>And testing our resolution:</p><pre class="crayon-plain-tag">[root@shana /]$ host somedomain.com 127.0.0.1
# Using domain server:
# Name: 127.0.0.1
# Address: 127.0.0.1#53
# Aliases: 
# 
# somedomain.com has address 172.16.0.4
# somedomain.com mail is handled by 5 shana.somedomain.com.

[root@shana /]$ host -t NS somedomain.com 127.0.0.1
# Using domain server:
# Name: 127.0.0.1
# Address: 127.0.0.1#53
# Aliases: 
# 
# somedomain.com name server shana.somedomain.com.

[root@shana /]$ host -t TXT somedomain.com 127.0.0.1
# Using domain server:
# Name: 127.0.0.1
# Address: 127.0.0.1#53
# Aliases: 
# 
# somedomain.com descriptive text &quot;v=spf1 mx:somedomain.com ~sll&quot;

[root@shana /]$ host www.somedomain.com 127.0.0.1
# Using domain server:
# Name: 127.0.0.1
# Address: 127.0.0.1#53
# Aliases: 
# 
# www.somedomain.com is an alias for shana.somedomain.com.
# shana.somedomain.com has address 172.16.0.4</pre><p>All done! A simple post this time.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.odynia.org/2012/07/dns-setup-the-pitfall-of-bind/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Dukan Diet: Week 3</title>
		<link>http://blog.odynia.org/2012/07/dukan-diet-week-3/</link>
		<comments>http://blog.odynia.org/2012/07/dukan-diet-week-3/#comments</comments>
		<pubDate>Thu, 05 Jul 2012 15:17:28 +0000</pubDate>
		<dc:creator>Rob</dc:creator>
				<category><![CDATA[Dukan Diet]]></category>
		<category><![CDATA[cruise]]></category>
		<category><![CDATA[diet]]></category>
		<category><![CDATA[dukan diet]]></category>

		<guid isPermaLink="false">http://blog.odynia.org/?p=449</guid>
		<description><![CDATA[I figured it is about time I updated my progress here on Day 18 (Week 3) as it has been almost 9 days. So, has there been further weight loss? Yes there has! Though I was stuck on a plateau for a while there, it has kicked up again recently. Today&#8217;s Weight 86.4 kg Weight [...]]]></description>
				<content:encoded><![CDATA[<p>I figured it is about time I updated my progress here on Day 18 (Week 3) as it has been almost 9 days. So, has there been further weight loss?<br />
<span id="more-449"></span><br />
<div id="attachment_450" class="wp-caption aligncenter" style="width: 310px"><a href="http://blog.odynia.org/wp-content/uploads/2012/07/WeightLoss-2012-07-06.png" rel="lightbox[449]"><img class="size-medium wp-image-450" title="Weight Loss - 6 July 2012" src="http://blog.odynia.org/wp-content/uploads/2012/07/WeightLoss-2012-07-06-300x154.png" alt="" width="300" height="154" /></a><p class="wp-caption-text">Weight Loss to Date</p></div></p>
<p>Yes there has! Though I was stuck on a plateau for a while there, it has kicked up again recently.</p>
<table class="blogTable" cellspacing="0">
<tbody>
<tr>
<th>Today&#8217;s Weight</th>
<td>86.4 kg</td>
</tr>
<tr>
<th>Weight Loss in last 7 days</th>
<td>1.9 kg</td>
</tr>
<tr>
<th>Weight Loss to Date</th>
<td>7.6 kg</td>
</tr>
</tbody>
</table>
<p>So what happened? I don&#8217;t think too much has actually happened different. It generally helps though to remain patient, and not indulge too much. I mean your Yoghurt might be fat free, but it still contains some carbohydrates, which are more easily converted to energy than protein.</p>
<p>I&#8217;ve tried a whole bunch of recipes since last time, all of which come from <a href="http://mydukandiet.com/recipes/">My Dukan Diet</a>, or <a href="http://www.slimkicker.com/recipes/dukan-diet">Slim Kicker</a>.</p>
<p>I can add a helpful tip or two though, regarding take away.</p>
<h2>Take Away &#8211; It is still possible</h2>
<p>There are a couple of take away food franchises that are still compatible with the Protein and Vegetable phases of your Dukan Diet: Subway, and Sumo Salad. They are compatible because you can pick and choose your ingredients so you know you are getting diet-compatible foods.</p>
<p>Going to subway though doesn&#8217;t mean getting a sub. You still can&#8217;t have any bread, but you can order a salad for $1.50 more. Get the Chicken Strips (or Chicken Pieces, whatever they call it) or Steak, or Ham or whatever meat you feel like (you know by now what meats you&#8217;re allowed to have). No cheese, add in the available salads and a bit of pepper if you like that.</p>
<p>No dressings though! They will kill the whole thing. Your best bet is to bring your own dressing so you know what is in it. You can make a pretty good honey mustard dressing with your Non-fat Yoghurt, Dijon Mustard and a bit of artificial sweetener to taste.</p>
<p>Sumo Salad is the same, but a bit more expensive. You can order a build your own salad, pick items from the list that you know are acceptable and go from there. They do have a Lemon Juice dressing at Sumo Salad which may be acceptable. But I prefer the dressings I make myself anyway.</p>
<p>Carrying on with the diet, only 11.5kgs to go!</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.odynia.org/2012/07/dukan-diet-week-3/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Mail Server Setup: Part 2 &#8211; Dovecot and PostgreSQL</title>
		<link>http://blog.odynia.org/2012/07/mail-server-setup-part-2-dovecot-and-postgresql/</link>
		<comments>http://blog.odynia.org/2012/07/mail-server-setup-part-2-dovecot-and-postgresql/#comments</comments>
		<pubDate>Thu, 05 Jul 2012 14:50:41 +0000</pubDate>
		<dc:creator>Rob</dc:creator>
				<category><![CDATA[Server Build]]></category>
		<category><![CDATA[dovecot]]></category>
		<category><![CDATA[dovecot-lda]]></category>
		<category><![CDATA[freebsd]]></category>
		<category><![CDATA[imap]]></category>
		<category><![CDATA[mail]]></category>
		<category><![CDATA[pop3]]></category>
		<category><![CDATA[postfix]]></category>
		<category><![CDATA[postgresql]]></category>
		<category><![CDATA[server build]]></category>
		<category><![CDATA[shana]]></category>
		<category><![CDATA[sieve]]></category>
		<category><![CDATA[smtp]]></category>
		<category><![CDATA[SPF]]></category>
		<category><![CDATA[ssl]]></category>

		<guid isPermaLink="false">http://blog.odynia.org/?p=437</guid>
		<description><![CDATA[This is the second part in the two part posting about setting up my mail server. In this one we tackle Dovecot and PostgreSQL. This post will be remarkably short compared to the first one. A bit of a refresher on the setup I&#8217;m aiming for: We&#8217;re looking at the red arrows in this one, [...]]]></description>
				<content:encoded><![CDATA[<p>This is the second part in the two part posting about setting up my mail server. In this one we tackle Dovecot and PostgreSQL.</p>
<p>This post will be remarkably short compared to the first one. A bit of a refresher on the setup I&#8217;m aiming for:</p>
<p><a href="http://blog.odynia.org/wp-content/uploads/2012/07/Blog-Mail-setup.png" rel="lightbox[437]"><img class="aligncenter size-full wp-image-424" title="Mail Setup" src="http://blog.odynia.org/wp-content/uploads/2012/07/Blog-Mail-setup.png" alt="" width="539" height="380" /></a></p>
<p>We&#8217;re looking at the red arrows in this one, so Dovecot, as well as setting up the Virtual Mailboxes and Sieve support. Because we&#8217;re using <span style="text-decoration: underline;"><em>dovecot-lda</em></span> to handle delivery of mail into the actual &#8220;mailbox&#8221; on the file system we need to have completed configuring Dovecot before our setup of Postfix from <a title="Mail Server Setup: Part 1 – Postfix and PostgreSQL" href="http://blog.odynia.org/?p=422">Part One</a> will be functional.</p>
<h2>Installation of Dovecot</h2>
<p>Dovecot itself was installed as a dependency of Postfix back in Part One. That was because we selected Dovecot2 SASL Auth option. If you want to install Dovecot manually head on over to ports and run through the usual process, selecting the following options on the config screen:</p>
<ul>
<li>KQUEUE (default)</li>
<li>SSL (default)</li>
<li>PGSQL</li>
</ul>
<p></p><pre class="crayon-plain-tag">[root@shana /]$ cd /usr/ports/mail/postfix
[root@shana /usr/ports/mail/postfix]$ make install clean</pre><p>Under Dovecot2 the Sieve plugin support is provided by <em><a href="http://wiki2.dovecot.org/Pigeonhole">Pigeonhole</a>,</em> which can be easily installed via ports:</p><pre class="crayon-plain-tag">[root@shana /]$ cd /usr/ports/mail/dovecot2-pigeonhole
[root@shana /usr/ports/mail/dovecot2-pigeonhole]$ make install clean</pre><p></p>
<h2>Configuration</h2>
<p>Lets separate our configuration into several bits to make it a bit easier to follow.</p>
<h3>Virtual Mailboxes, Databases and Delivery</h3>
<p>We need to start with the delivery of mail into the virtual mailboxes, so that we can finally test the Postfix setup and delivery of mail into the mailboxes.</p>
<p>From Post One, we setup <em>dovecot-lda</em> using the following line in <em>/usr/local/etc/postfix/master.cf.</em></p>
<pre class="crayon-plain-tag">dovecot unix - n n - - pipe flags=DRhu user=vmail:vmail argv=/usr/local/libexec/dovecot/deliver -f ${sender} -d ${recipient}</pre>
<p>So it calls <em>/usr/local/libexec/dovecot/deliver</em> with the sender&#8217;s email address passed in via the <em>-f</em> option, and the recipient&#8217;s email via <em>-d</em>. We&#8217;re also running it with a user called <em>vmail</em>. Lets setup the user and group first.</p>
<p></p><pre class="crayon-plain-tag">[root@shana /]$ adduser
# Username: vmail
# Full name: Virtual Mailbox User
# Uid (Leave empty for default): 145
# Login group [vmail]:
# Login group is vmail. Invite vmail into other groups? []:
# Login class [default]:
# Shell (sh csh tcsh bash rbash nologin) [sh]: nologin
# Home directory [/home/vmail]: /var/vmail
# Home directory permissions (Leave empty for default):
# Use password-based authentication? [yes]: no
# Lock out the account after creation? [no]: yes
# Username : vmail
# Password :
# Full Name : Virtual Mailbox User
# Uid : 145
# Class :
# Groups : vmail
# Home : /var/vmail
# Home Mode :
# Shell : /usr/sbin/nologin
# Locked : yes
# OK? (yes/no): yes
# adduser: INFO: Successfully added (vmail) to the user database.
# adduser: INFO: Account (vmail) is locked.
# Add another user? (yes/no): no
# Goodbye!</pre><p></p>
<p>Now that that is done, clear out all of the skeleton files that were copied into <em>/var/vmail</em> and we can update the config file for LDA.</p>
<p></p><pre class="crayon-plain-tag">[root@shana /var/vmail]$ rm .*</pre><p></p>
<p>Almost all of Dovecot&#8217;s configuration can be found in <em>/usr/local/etc/dovecot/, </em>including the LDA settings that we&#8217;re after now. If that directory is empty for you then the <em>README</em> file should tell you where to find the example ones, copy the example files we need into the target directory.</p>
<p></p><pre class="crayon-plain-tag">[root@shana /usr/local/etc/dovecot]$ cp /usr/local/share/doc/dovecot/example-config/dovecot.conf .

[root@shana /usr/local/etc/dovecot]$ mkdir conf.d

[root@shana /usr/local/etc/dovecot]$ cp /usr/local/share/doc/dovecot/example-config/conf.d/* conf.d/</pre><p></p>
<p>There are some things we need to setup in order to get the LDA working, including Sieve, the Passdb, Userdb and authentication. Lets go in that order.</p>
<p>To enable sieve, edit <em>/usr/local/etc/dovecot/conf.d/15-lda.conf</em> and set <em>mail_plugins</em> to sieve.</p>
<pre class="crayon-plain-tag">protocol lda {
# Space separated list of plugins to load (default is global mail_plugins).
mail_plugins = sieve
}</pre>
<p>Because we&#8217;re delivering mail as <em>vmail</em>, you may need to adjust the <em>first_valid_uid</em> and <em>first_valid_gid</em> settings in <em>/usr/local/etc/dovecot/conf.d/10-mail.conf.</em></p>
<p>Set the value to whatever UID and GID your <em>vmail</em> user has, unless the ID is greater than 500, in which case the default is fine. Even better, set the <em>last_valid_uid</em> and <em>last_valid_gid</em> to your <em>vmail</em> UID and GID. That means only <em>vmail</em> can deliver mail, no other user.</p>
<pre class="crayon-plain-tag">first_valid_uid = 145
last_valid_uid = 145

first_valid_gid = 145
last_valid_gid = 145</pre>
<p>To setup the authentication properly, open up <em>/usr/local/etc/dovecot/conf.d/10-auth.conf</em>, comment out the existing include for auth-system, and uncomment the <em>auth-sql.conf.ext</em> line, it should look like this:</p>
<pre class="crayon-plain-tag">#!include auth-system.conf.ext
!include auth-sql.conf.ext
#!include auth-ldap.conf.ext
#!include auth-passwdfile.conf.ext
#!include auth-checkpassword.conf.ext
#!include auth-vpopmail.conf.ext
#!include auth-static.conf.ext</pre>
<p>Then we can edit <em>/usr/local/etc/dovecot/conf.d/auth-sql.conf.ext</em> to point to the correct SQL configuration file, this happens under <em>passdb</em> and <em>userdb.</em></p>
<pre class="crayon-plain-tag">passdb {
driver = sql

# Path for SQL configuration file, see example-config/dovecot-sql.conf.ext
args = /usr/local/etc/dovecot/dovecot-sql.conf.ext
}</pre>
<pre class="crayon-plain-tag">userdb {
driver = sql
args = /usr/local/etc/dovecot/dovecot-sql.conf.ext
}</pre>
<p>Then we want to open up <em>/usr/local/etc/dovecot/dovecot-sql.conf.ext</em> and make it look like the following. I&#8217;ll step through it after the paste.</p>
<pre class="crayon-plain-tag"># This file is opened as root, so it should be owned by root and mode 0600.
#

# Database driver: mysql, pgsql, sqlite
driver = pgsql

# Database connection string. This is driver-specific setting.
connect = host=/tmp dbname=mail user=mail password=xxx

# Query to retrieve the password.
password_query = SELECT DISTINCT ON (mbox) mbox as user, password, '/var/vmail/' || mbox || '/home/' as home, 'maildir:/var/vmail/' || mbox || '/' as mail, 145 as uid, 145 as gid FROM COALESCE((SELECT DISTINCT ON (mbox) mbox FROM mailboxes LEFT OUTER JOIN aliases USING (mbox) WHERE (mailboxes.mbox = '%u' AND mailboxes.disabled = false) OR (aliases.alias = '%u' AND mailboxes.disabled = false)), (SELECT DISTINCT ON (mbox) mbox FROM mailboxes LEFT OUTER JOIN aliases USING (mbox) WHERE (aliases.alias = '@%d' AND mailboxes.disabled = false)), (SELECT DISTINCT ON (mbox) mbox FROM mailboxes LEFT OUTER JOIN aliases USING (mbox) WHERE (aliases.alias = '%n@' AND mailboxes.disabled = false))) as mbox JOIN mailboxes USING (mbox);

# Query to retrieve the user information.
user_query = SELECT '/var/vmail/' || mbox || '/home/' as home, 'maildir:/var/vmail/' || mbox || '/' as mail, 145 as uid, 145 as gid FROM COALESCE((SELECT DISTINCT ON (mbox) mbox FROM mailboxes LEFT OUTER JOIN aliases USING (mbox) WHERE mailboxes.mbox = '%u' OR aliases.alias = '%u'), (SELECT DISTINCT ON (mbox) mbox FROM mailboxes LEFT OUTER JOIN aliases USING (mbox) WHERE aliases.alias = '@%d'), (SELECT DISTINCT ON (mbox) mbox FROM mailboxes LEFT OUTER JOIN aliases USING (mbox) WHERE aliases.alias = '%n@')) as mbox;</pre>
<ul>
<li><em>driver = pgsql -</em> Tells Dovecot that we want to connect to a PostgreSQL server</li>
<li><em>connect</em> &#8211; The connection string. Set host to where your UNIX socket lives (usually /tmp), and dbname, user and password to the same credentials you used configuring Postfix in <a title="Mail Server Setup: Part 1 – Postfix and PostgreSQL" href="http://blog.odynia.org/?p=422">Post One</a>. Alternatively, you can use different credentials, make sure you grant the appropriate permissions to the database.</li>
<li>password_query &#8211; This is the query that Dovecot will execute to retrieve the hashed password from the database. It then compares it to the hash it creates of the password given to it by the mail client to see if they match.</li>
<li>user_query &#8211; This query tells Dovecot where to find information on the users and mailboxes as configured.</li>
</ul>
<p>These queries should look similar to the ones from Part One. Lets break them down a bit for better understanding.</p>
<p></p><pre class="crayon-plain-tag">SELECT
DISTINCT ON (mbox) mbox as user,
password,
'/var/vmail/' || mbox || '/home/' as home,
'maildir:/var/vmail/' || mbox || '/' as mail,
143 as uid,
143 as gid
FROM
COALESCE (
(SELECT DISTINCT ON (mbox) mbox FROM mailboxes LEFT OUTER JOIN aliases USING (mbox) WHERE (mailboxes.mbox = '%u' AND mailboxes.disabled = false) OR (aliases.alias = '%u' AND mailboxes.disabled = false)),
(SELECT DISTINCT ON (mbox) mbox FROM mailboxes LEFT OUTER JOIN aliases USING (mbox) WHERE (aliases.alias = '@%d' AND mailboxes.disabled = false)),
(SELECT DISTINCT ON (mbox) mbox FROM mailboxes LEFT OUTER JOIN aliases USING (mbox) WHERE (aliases.alias = '%n@' AND mailboxes.disabled = false))
) as mbox
JOIN mailboxes USING (mbox);</pre><p></p>
<p>So it executes three subqueries that are almost identical to the ones used by Postfix, except the substitutions are different this time around.</p>
<ul>
<li>%u = the full email address being looked up</li>
<li>%d = only the domain (the bit after the @)</li>
<li>%n = only the username (the bit before the @)</li>
</ul>
<p>It returns a lot more information though from the coalesced queries, and it checks if the email address in question is an alias too. Whereas Postfix was only looking for validation before handing it to <em>dovecot-lda</em>, Dovecot needs to know where and how to deliver the message to. The columns returned are as follows.</p>
<table style="border: 1px solid #f7f7f7;" width="100%" cellspacing="0" cellpadding="0">
<thead>
<tr>
<th>Column</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>user</td>
<td>The email address of the user in question. Used as a username of sorts.</td>
</tr>
<tr>
<td>password</td>
<td>The hashed password.</td>
</tr>
<tr>
<td>home</td>
<td>The full path on the filesystem to the user&#8217;s home directory. In this case it is in a subfolder of their virtual mailbox: <em>/var/vmail/<strong>email</strong>/home/</em>. This is where the Sieve files live. The trailing slash is important.</td>
</tr>
<tr>
<td>mail</td>
<td>The full path on the filesystem to the user&#8217;s mailbox. In this case it is in a subfolder of their virtual mailbox: <em>/var/vmail/<strong>email</strong>/</em>. The trailing slash is important.</td>
</tr>
<tr>
<td>kid</td>
<td>The user ID of the local account dovecot should use when accessing the mailbox. This should be the ID <em>vmail</em> user we setup earlier, and you need to make sure it has read and write access to the folders above.</td>
</tr>
<tr>
<td>kid</td>
<td>The group ID of the local group dovecot should use when accessing the mailbox. This should be the ID <em>vmail</em> group we setup earlier.</td>
</tr>
</tbody>
</table>
<p>Now that we have that out of the way, its time to test mail delivery! Oh, but we need a user account.</p>
<h3>Creating User Accounts</h3>
<p>There are two things you need to do to create a user account:</p>
<ol>
<li>Add the user in the mailboxes table in the database.</li>
<li>Create the user&#8217;s mailbox on the filesystem.</li>
</ol>
<p>To add the user, connect to your database using <em>psql</em> and run the following. Change &lt;password&gt; to the password you generated using <em>doveadm pw -s ssha512.</em></p>
<p></p><pre class="crayon-plain-tag">INSERT INTO mailboxes (mbox, password) VALUES ('test@test.com', '{SSHA512}cZm4VMAkPzYdA+pRb0DpmQUyx9HT8JA8AmklE7V2TUK7L2Td+I3Z8P0phNO+i7fAwC82J9IC0rFQUcX2u2toFkJ+0IU=');</pre><p></p>
<p>Then create the directory on the filesystem to match.</p>
<p></p><pre class="crayon-plain-tag">[root@shana /]$ mkdir /var/vmail/test@test.com

[root@shana /]$ chown vmail:vmail /var/vmail/test\@test.com/</pre><p></p>
<p>Then we can test!</p>
<h3>Testing the mail delivery</h3>
<p>If you haven&#8217;t already, we&#8217;ll need to configure Dovecot to start, add this line to your <em>/etc/rc.conf</em> file.</p>
<pre class="crayon-plain-tag">dovecot_enable=&quot;YES&quot;</pre>
<p>Now lets start Postfix first.</p>
<p></p><pre class="crayon-plain-tag">[root@shana /]$ /usr/local/etc/rc.d/postfix start
postfix/postfix-script: starting the Postfix mail system</pre><p></p>
<p>If everything went well there shouldn&#8217;t be any errors there, or any in <em>/var/log/maillog</em>.</p>
<pre class="crayon-plain-tag">Jul 5 22:49:05 shana postfix/postfix-script[86436]: starting the Postfix mail system
Jul 5 22:49:05 shana postfix/master[86437]: daemon started -- version 2.9.3, configuration /usr/local/etc/postfix</pre>
<p>We don&#8217;t need to start Dovecot to test mail delivery as <em>dovecot-lda</em> is called automatically by Postfix. Lets connect and see what happens (the comments are server responses, the rest are commands I&#8217;m typing).</p>
<p></p><pre class="crayon-plain-tag">[bok@tyrande ~]$ telnet 124.168.107.116 25
# Trying 124.168.107.116...
# Connected to 124-168-107-116.dyn.iinet.net.au.
# Escape character is '^]'.
# 220 mail.odynia.org ESMTP Postfix
HELO tyrande.odynia.org
# 250 mail.odynia.org
MAIL FROM:
# 250 2.1.0 Ok
RCPT TO:
# 250 2.1.5 Ok
DATA
# 354 End data with .
test
.
# 250 2.0.0 Ok: queued as 26E051E3
QUIT
# 221 2.0.0 Bye
# Connection closed by foreign host.</pre><p></p>
<p>Accepted! Lets see where that went by checking <em>/var/log/maillog</em>.</p>
<pre class="crayon-plain-tag">Jul 5 23:44:03 shana postfix/smtpd[87478]: connect from tyrande.odynia.org[202.62.159.130]
Jul 5 23:44:23 shana postfix/policy-spf[87495]: : SPF softfail (Mechanism '~all' matched): Envelope-from: test@test.com
Jul 5 23:44:23 shana postfix/policy-spf[87495]: handler sender_policy_framework: is decisive.
Jul 5 23:44:23 shana postfix/policy-spf[87495]: : Policy action=PREPEND Received-SPF: softfail (test.com: Sender is not authorized by default to use 'test@test.com' in 'mfrom' identity, however domain is not currently prepared for false failures (mechanism '~all' matched)) receiver=unknown; identity=mailfrom; envelope-from=&quot;test@test.com&quot;; helo=tyrande.odynia.org; client-ip=202.62.159.130
Jul 5 23:44:23 shana postfix/smtpd[87478]: 26E051E3: client=tyrande.odynia.org[202.62.159.130]
Jul 5 23:44:29 shana postfix/cleanup[87497]: 26E051E3: message-id=&amp;lt;&amp;gt;
Jul 5 23:44:29 shana postfix/qmgr[87474]: 26E051E3: from=, size=519, nrcpt=1 (queue active)
Jul 5 23:44:29 shana dovecot: lda: Error: userdb lookup: connect(/var/run/dovecot/auth-userdb) failed: No such file or directory
Jul 5 23:44:29 shana dovecot: lda: Fatal: Internal error occurred. Refer to server log for more information.
Jul 5 23:44:29 shana postfix/pipe[87498]: 26E051E3: to=, relay=dovecot, delay=10, delays=9.9/0.01/0/0.04, dsn=4.3.0, status=deferred (temporary failure)
Jul 5 23:44:35 shana postfix/smtpd[87478]: disconnect from tyrande.odynia.org[202.62.159.130]</pre>
<p>Hmm, a temporary lookup failure trying to use the wrong <em>userdb</em>. Lets see what we missed.</p>
<p>Oh!</p>
<p>So when you&#8217;re using the SQL <em>userdb</em> and <em>passdb</em> setup you do need to have Dovecot running so it creates the authentication sockets that <em>dovecot-lda</em> needs. Lets start it up now then.</p>
<p></p><pre class="crayon-plain-tag">[root@shana /]$ /usr/local/etc/rc.d/dovecot start
Starting dovecot.
doveconf: Fatal: Error in configuration file /usr/local/etc/dovecot/conf.d/10-ssl.conf line 12: ssl_cert: Can't open file /etc/ssl/certs/dovecot.pem: No such file or directory
/usr/local/etc/rc.d/dovecot: WARNING: failed to start dovecot</pre><p></p>
<p>Uh oh! We missed a step in setting up Dovecot. We forgot to generate the SSL certificate that is configured by default in <em>/usr/local/etc/dovecot/conf.d/10-ssl.conf</em>. You have a few choices here.</p>
<ul>
<li>Go buy a certificate from a trusted vendor and copy your public and private key files (PEM files) into /etc/ssl/certs/dovecot.pem and <em>/etc/ssl/private/dovecot.pem</em> respectively. This is the recommended and most secure option.</li>
<li>Generate a self-signed certificate using the <a href="http://wiki2.dovecot.org/SSL/CertificateCreation">instructions on the Dovecot Wiki</a>. (Note that the files mentioned in doc/ are actually in <em>/usr/local/share/examples/dovecot/</em> under FreeBSD).</li>
<li>Disable SSL (not recommended at all)</li>
</ul>
<p>Once you&#8217;ve done one of those we can start Dovecot again.</p>
<p></p><pre class="crayon-plain-tag">[root@shana /]$ /usr/local/etc/rc.d/dovecot start
Starting dovecot.</pre><p></p>
<p>Better. Nothing in the logs?</p>
<pre class="crayon-plain-tag">Jul 6 00:08:01 shana dovecot: master: Dovecot v2.1.7 starting up</pre>
<p>Right, lets try that delivery again, that previous message was still in the queue, so lets flush it.</p>
<p></p><pre class="crayon-plain-tag">[root@shana /]$ postqueue -f</pre><p></p>
<p>So, was that successful?</p>
<pre class="crayon-plain-tag">Jul 6 00:05:54 shana postfix/qmgr[87474]: 26E051E3: from=, size=519, nrcpt=1 (queue active)
Jul 6 00:05:54 shana dovecot: auth: pgsql(/tmp): Connected to database mail
Jul 6 00:05:54 shana dovecot: lda(test@odynia.org): msgid=unspecified: saved mail to INBOX
Jul 6 00:05:54 shana postfix/pipe[87829]: 26E051E3: to=, relay=dovecot, delay=1295, delays=1295/0.01/0/0.1, dsn=2.0.0, status=sent (delivered via dovecot service)
Jul 6 00:05:54 shana postfix/qmgr[87474]: 26E051E3: removed</pre>
<p>Yay! It was delivered to the folder, lets check the contents.</p>
<p></p><pre class="crayon-plain-tag">[root@shana /]$ cat /var/vmail/test\@odynia.org/new/1341497154.M243352P87831.shana.itransit.com.au\,S\=571\,W\=579
# Return-Path:
# Delivered-To: test@odynia.org
# Received-SPF: softfail (test.com: Sender is not authorized by default to use 'test@test.com' in 'mfrom' identity, however domain is not currently prepared for false failures (mechanism '~all' matched)) receiver=unknown; identity=mailfrom; envelope-from=&quot;test@test.com&quot;; helo=tyrande.odynia.org; client-ip=202.62.159.130
# Received: from tyrande.odynia.org (tyrande.odynia.org [202.62.159.130])
# by mail.odynia.org (Postfix) with SMTP id 26E051E3
# for ; Thu, 5 Jul 2012 23:44:19 +1000 (EST)
#
# test</pre><p></p>
<p>One complete message, and the softfail there shows SPF is working correctly also (test.com&#8217;s SPF record is set to softfail).</p>
<h3>Configuring IMAP and POP3</h3>
<p>All that is left now is configuring IMAP and POP3 access, including accessing both via SSL.</p>
<p>But wait! It is already working. You can configure your favourite mail client to connect via POP3 or IMAP and it will already be configured and working. There is nothing additional you need to do.</p>
<pre class="crayon-plain-tag">Jul 6 00:15:50 shana dovecot: imap-login: Login: user=, method=PLAIN, rip=172.16.0.127, lip=172.16.0.4, mpid=87945, TLS, session=
Jul 6 00:15:50 shana dovecot: imap(test@odynia.org): Connection closed in=17 out=352</pre>
<p>I configured Mail on my Macbook to connect as test@odynia.org, and its already coming in over SSL for IMAP too. But what about sieve?</p>
<h3>Configuring and Testing Sieve</h3>
<p>Lets try a simple test, create a Folder in your Mail client and we&#8217;ll create a sieve file to redirect matching mail to that folder.</p>
<p>We&#8217;ll need to create the home folder inside the mailbox, like so:</p>
<p></p><pre class="crayon-plain-tag">[root@shana /]$ mkdir /var/vmail/test\@odynia.org/home
[root@shana /]$ chown vmail:vmail /var/vmail/test\@odynia.org/home</pre><p></p>
<p>Then we can create a <em>.dovecot.sieve</em> file in there. So in this example it is <em>/var/vmail/test@odynia.org/home/.dovecot.sieve.</em> Make sure it is owned by vmail:vmail also.</p>
<pre class="crayon-plain-tag">require [&quot;fileinto&quot;];
if anyof (header :contains &quot;Subject&quot; &quot;[test]&quot;)
{
fileinto &quot;Test Folder&quot;;
stop;
}</pre>
<p>So if we send an email again with a subject that includes &#8220;[test]&#8221; it should get redirected automatically to that folder.</p>
<p></p><pre class="crayon-plain-tag">[bok@tyrande ~]$ telnet 124.168.107.116 25
# Trying 124.168.107.116...
# Connected to 124-168-107-116.dyn.iinet.net.au.
# Escape character is '^]'.
# 220 mail.odynia.org ESMTP Postfix
HELO tyrande.odynia.org
# 250 mail.odynia.org
MAIL FROM:
# 250 2.1.0 Ok
RCPT TO:
# 250 2.1.5 Ok
DATA
# 354 End data with .
From: Me
To: You
Subject: [test] This is a test

Do you like my test?
.
# 250 2.0.0 Ok: queued as E3F212D0
QUIT
# 221 2.0.0 Bye
# Connection closed by foreign host.</pre><p></p>
<p>Lets check the logs.</p>
<pre class="crayon-plain-tag">Jul 6 00:26:50 shana postfix/smtpd[87988]: connect from tyrande.odynia.org[202.62.159.130]
Jul 6 00:27:01 shana postfix/policy-spf[87994]: : SPF softfail (Mechanism '~all' matched): Envelope-from: test@test.com
Jul 6 00:27:01 shana postfix/policy-spf[87994]: handler sender_policy_framework: is decisive.
Jul 6 00:27:01 shana postfix/policy-spf[87994]: : Policy action=PREPEND Received-SPF: softfail (test.com: Sender is not authorized by default to use 'test@test.com' in 'mfrom' identity, however domain is not currently prepared for false failures (mechanism '~all' matched)) receiver=unknown; identity=mailfrom; envelope-from=&quot;test@test.com&quot;; helo=tyrande.odynia.org; client-ip=202.62.159.130
Jul 6 00:27:01 shana postfix/smtpd[87988]: E3F212D0: client=tyrande.odynia.org[202.62.159.130]
Jul 6 00:27:17 shana postfix/cleanup[87996]: E3F212D0: message-id=&amp;lt;&amp;gt;
Jul 6 00:27:17 shana postfix/qmgr[87474]: E3F212D0: from=, size=586, nrcpt=1 (queue active)
Jul 6 00:27:17 shana dovecot: lda(test@odynia.org): sieve: msgid=unspecified: stored mail into mailbox 'Test Folder'
Jul 6 00:27:17 shana postfix/pipe[88010]: E3F212D0: to=, relay=dovecot, delay=19, delays=19/0.01/0/0.04, dsn=2.0.0, status=sent (delivered via dovecot service)
Jul 6 00:27:17 shana postfix/qmgr[87474]: E3F212D0: removed
Jul 6 00:27:19 shana postfix/smtpd[87988]: disconnect from tyrande.odynia.org[202.62.159.130]</pre>
<p>Yep. Sieve also requires no additional setup.</p>
<div id="attachment_445" class="wp-caption aligncenter" style="width: 266px"><a href="http://blog.odynia.org/wp-content/uploads/2012/07/Screen-Shot-2012-07-06-at-12.48.48-AM.png" rel="lightbox[437]"><img class="size-full wp-image-445" title="Sieve Test" src="http://blog.odynia.org/wp-content/uploads/2012/07/Screen-Shot-2012-07-06-at-12.48.48-AM.png" alt="" width="256" height="179" /></a><p class="wp-caption-text">I sure do like your test.</p></div>
<h3>ManageSieve</h3>
<p>Now, because of the length of this post I&#8217;m going to leave setting up ManageSieve to another day. I only use it for one service anyway, which is RoundCube webmail, so we&#8217;ll setup ManageSieve when we do RoundCube.</p>
<p>That&#8217;s it for another day. I hope this has been helpful.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.odynia.org/2012/07/mail-server-setup-part-2-dovecot-and-postgresql/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Mail Server Setup: Part 1 &#8211; Postfix and PostgreSQL</title>
		<link>http://blog.odynia.org/2012/07/mail-server-setup-part-1-postfix-and-postgresql/</link>
		<comments>http://blog.odynia.org/2012/07/mail-server-setup-part-1-postfix-and-postgresql/#comments</comments>
		<pubDate>Mon, 02 Jul 2012 13:14:58 +0000</pubDate>
		<dc:creator>Rob</dc:creator>
				<category><![CDATA[Server Build]]></category>
		<category><![CDATA[dovecot]]></category>
		<category><![CDATA[freebsd]]></category>
		<category><![CDATA[postfix]]></category>
		<category><![CDATA[postgresql]]></category>
		<category><![CDATA[server build]]></category>
		<category><![CDATA[shana]]></category>
		<category><![CDATA[SPF]]></category>

		<guid isPermaLink="false">http://blog.odynia.org/?p=422</guid>
		<description><![CDATA[I have an uncommon setup for my mail server. In addition to standard Postfix and a bunch of anti-spam tools, I also use PostgreSQL for storing account information, including wildcard matching of aliases. I&#8217;ve split this post into two so as not to write a novel. In this one I will run through installing and [...]]]></description>
				<content:encoded><![CDATA[<p>I have an uncommon setup for my mail server. In addition to standard Postfix and a bunch of anti-spam tools, I also use PostgreSQL for storing account information, including wildcard matching of aliases.</p>
<p>I&#8217;ve split this post into two so as not to write a novel. In this one I will run through installing and configuring Postfix to my liking, as well as hooking it up to PostgreSQL. In the second post I&#8217;ll cover setting Dovecot up in the same way for IMAP/POP3.</p>
<p>WARNING: Despite the split, this is still a very long post. You may need a cup of coffee.</p>
<h2>Overview</h2>
<p>But first, an overview of my setup, for which a picture tells many words.</p>
<p><a href="http://blog.odynia.org/wp-content/uploads/2012/07/Blog-Mail-setup.png" rel="lightbox[422]"><img class="aligncenter size-full wp-image-424" title="Mail Setup" src="http://blog.odynia.org/wp-content/uploads/2012/07/Blog-Mail-setup.png" alt="" width="539" height="380" /></a></p>
<p>This is highly simplified as there are a few extra services in there, such as ManageSieve. In a nutshell though; incoming mail is filtered first through SPF and a few other spam checks. Then the To: address is looked up in the database, in both the mailbox and alias tables, and the delivery mailbox address returned to Postfix. Postfix then delivers that mail into the correct directory. I&#8217;ll handle the rest of that picture in Post Two.</p>
<h3>Aliasing</h3>
<p>The aliasing system I use is slightly complex, but highly worthwhile. It allows me to use a couple of wildcard patterns to direct mail to a specific mailbox.</p>
<ul>
<li>Direct matching: An email address is matched in full.</li>
<li>*@domain.com: A catch-all for a specific domain.</li>
<li>user@*: A specific user across all domains (useful for postmaster@)</li>
</ul>
<p>This can be easily expanded upon by adjusting the SQL query as the need arises.</p>
<h3>Resources</h3>
<p>Before we get too far in it is a good idea to list some of the resources that I used to learn all of this in the first place.</p>
<ul>
<li><a href="http://wiki.dovecot.org/LDA/Postfix">Using the Dovecot LDA with Postfix</a> on the Dovecot Wiki</li>
</ul>
<p>I&#8217;ll add to this list when I do <a title="Mail Server Setup: Part 2 – Dovecot and PostgreSQL" href="http://blog.odynia.org/?p=437">Part Two</a>, as it has been so long since I set this up the first time, and a lot of it I just remember.</p>
<h2>Installing</h2>
<p>I installed PostgreSQL back in <a title="Server Build: PostgreSQL Installation and SSD Benchmarking" href="http://blog.odynia.org/?p=258">this post</a>, so I won&#8217;t cover that again here. You can swap out PostgreSQL for MySQL if you desire, just change the options when we install Postfix.</p>
<p>Installing Postfix is very straightforward, just install the port. We want the following options.</p>
<ul>
<li>PCRE (selected by default)</li>
<li>SASL2</li>
<li>DOVECOT2</li>
<li>TLS</li>
<li>PGSQL</li>
</ul>
<p>For dependencies PCRE and SASL2, leave the default options selected. It will then prompt you to install Dovecot (as required by the Dovecot2 option above). Use the following options for Dovecot (covered in more detail in the next post).</p>
<ul>
<li>KQUEUE (default)</li>
<li>SSL (default)</li>
<li>PGSQL</li>
</ul>
<p>When asked if you want to activate Postfix in <em>/etc/mail/mailer.conf</em>, you say yes!</p><pre class="crayon-plain-tag">[root@shana /]$ cd /usr/ports/mail/postfix

[root@shana /usr/ports/mail/postfix]$ make install clean
# ===&amp;gt; Found saved configuration for postfix-2.9.3,1
# =&amp;gt; postfix-2.9.3.tar.gz doesn't seem to exist in /usr/ports/distfiles/postfix.
# =&amp;gt; Attempting to fetch ftp://ftp.porcupine.org/mirrors/postfix-release/official/postfix-2.9.3.tar.gz
# postfix-2.9.3.tar.gz 100% of 3672 kB 43 kBps 00m00s
# ===&amp;gt; Extracting for postfix-2.9.3,1
# ===&amp;gt; Found saved configuration for postfix-2.9.3,1
# =&amp;gt; SHA256 Checksum OK for postfix/postfix-2.9.3.tar.gz.
# ===&amp;gt; postfix-2.9.3,1 depends on file: /usr/local/bin/perl5.12.4 - found
# ===&amp;gt; Patching for postfix-2.9.3,1
# ===&amp;gt; postfix-2.9.3,1 depends on file: /usr/local/bin/perl5.12.4 - found
# ===&amp;gt; Applying FreeBSD patches for postfix-2.9.3,1
# ===&amp;gt; postfix-2.9.3,1 depends on file: /usr/local/bin/perl5.12.4 - found
# ===&amp;gt; postfix-2.9.3,1 depends on shared library: pcre - not found
# ===&amp;gt; Verifying install for pcre in /usr/ports/devel/pcre
#
# ===&amp;gt; Registering installation for pcre-8.30_2
# ===&amp;gt; Returning to build of postfix-2.9.3,1
# ===&amp;gt; postfix-2.9.3,1 depends on shared library: sasl2.2 - not found
# ===&amp;gt; Verifying install for sasl2.2 in /usr/ports/security/cyrus-sasl2
#
# ===&amp;gt; Registering installation for cyrus-sasl-2.1.25_2
# ===&amp;gt; Returning to build of postfix-2.9.3,1
# ===&amp;gt; postfix-2.9.3,1 depends on shared library: pq.5 - found
# ===&amp;gt; Configuring for postfix-2.9.3,1
#
# ===&amp;gt; Installing rc.d startup script(s)
# Would you like to activate Postfix in /etc/mail/mailer.conf [n]? y
# # Fix compressed man pages
# To enable postfix startup script please add postfix_enable=&quot;YES&quot; in
# your rc.conf
#
# If you not need sendmail anymore, please add in your rc.conf:
#
# sendmail_enable=&quot;NO&quot;
# sendmail_submit_enable=&quot;NO&quot;
# sendmail_outbound_enable=&quot;NO&quot;
# sendmail_msp_queue_enable=&quot;NO&quot;
#
# And you can disable some sendmail specific daily maintenance routines in your
# /etc/periodic.conf file:
#
# daily_clean_hoststat_enable=&quot;NO&quot;
# daily_status_mail_rejects_enable=&quot;NO&quot;
# daily_status_include_submit_mailq=&quot;NO&quot;
# daily_submit_queuerun=&quot;NO&quot;
#
# If /etc/periodic.conf does not exist please create it and add those values.
#
# If you are using SASL, you need to make sure that postfix has access to read
# the sasldb file. This is accomplished by adding postfix to group mail and
# making the /usr/local/etc/sasldb* file(s) readable by group mail (this should
# be the default for new installs).
#
# If you are upgrading from Postfix 2.6 or earlier, review the RELEASE_NOTES to
# familiarize yourself with new features and incompatabilities.
# ===&amp;gt; Correct pkg-plist sequence to create group(s) and user(s)
# ===&amp;gt; Compressing manual pages for postfix-2.9.3,1
# ===&amp;gt; Registering installation for postfix-2.9.3,1
# ===&amp;gt; SECURITY REPORT:
#
# ===&amp;gt; Cleaning for pcre-8.30_2
# ===&amp;gt; Cleaning for cyrus-sasl-2.1.25_2
# ===&amp;gt; Cleaning for dovecot-2.1.7
# ===&amp;gt; Cleaning for postfix-2.9.3,1</pre><p>&nbsp;</p>
<p>The hints and tips in the message at the end of the port install are useful, you should read them. Some of which I&#8217;ll repeat shortly.</p>
<p>Once that is done we should install <em>postfix-policyd-spf</em>, which handles the SPF lookups. I use the Perl client found in ports.</p><pre class="crayon-plain-tag">[root@shana /]$ cd /usr/ports/mail/postfix-policyd-spf-perl

[root@shana /usr/ports/mail/postfix-policyd-spf-perl]$ make install clean
# =&amp;gt; postfix-policyd-spf-perl-2.007.tar.gz doesn't seem to exist in /usr/ports/distfiles/.
# =&amp;gt; Attempting to fetch http://www.openspf.org/blobs/postfix-policyd-spf-perl-2.007.tar.gz
# postfix-policyd-spf-perl-2.007.tar.gz 100% of 13 kB 17 kBps
# ===&amp;gt; Extracting for postfix-policyd-spf-perl-2.007
#
# ===&amp;gt; Checking if mail/postfix-policyd-spf-perl already installed
# The service is not enabled by default. Enable it by doing the following:
#
# 1. Add the following to /etc/postfix/master.cf:
#
# spf-policy unix - n n - 0 spawn
# user=nobody argv=/usr/local/sbin/postfix-policyd-spf-perl
#
# The user nobody is fine if you have no other daemons running as nobody.
# Otherwise, you should use a dedicated user and group for this policy
# service.
#
# 2. Add &quot;spf-policy_time_limit = 3600&quot; to main.cf.
#
# 3. Configure the Postfix policy service in /usr/local/etc/postfix/main.cf:
#
# smtpd_recipient_restrictions =
# ...
# reject_unauth_destination
# ...
# check_policy_service unix:private/spf-policy
# ...
#
# NOTE: Specify check_policy_service AFTER reject_unauth_destination or your
# system may become an open relay.
#
# 4. Restart Postfix.
# ===&amp;gt; Registering installation for postfix-policyd-spf-perl-2.007</pre><p></p>
<h2>Configuration</h2>
<h3>Enabling Postfix / Disabling Sendmail</h3>
<p>To enable Postfix, add the following to your <em>/etc/rc.conf</em> file. It won&#8217;t start though until we tell it to, or you reboot your box.</p>
<pre class="crayon-plain-tag">postfix_enable=&quot;YES&quot;</pre>
<p>We should disable all of the sendmail stuff too that it tells us in <em>/etc/rc.conf</em> as we won&#8217;t need it anymore.</p>
<pre class="crayon-plain-tag">sendmail_enable=&quot;NO&quot;
sendmail_submit_enable=&quot;NO&quot;
sendmail_outbound_enable=&quot;NO&quot;
sendmail_msp_queue_enable=&quot;NO&quot;</pre>
<p>And remove the sendmail maintenance routines from <em>/etc/periodic.conf</em> (create it if it doesn&#8217;t exist).</p>
<pre class="crayon-plain-tag">daily_clean_hoststat_enable=&quot;NO&quot;
daily_status_mail_rejects_enable=&quot;NO&quot;
daily_status_include_submit_mailq=&quot;NO&quot;
daily_submit_queuerun=&quot;NO&quot;</pre>
<h3>General Postfix Configuration</h3>
<p>We want to change some general settings now for Postfix, particularly those that tell it server names, IP Addresses, ports and which domains to receive for. We&#8217;ll step through these.</p>
<p>Note: every setting that is not mentioned should be left with its default values.</p>
<p>Start by turning on <em>soft_bounce,</em> you don&#8217;t want to lose any email while we&#8217;re checking.</p>
<pre class="crayon-plain-tag">soft_bounce = yes</pre>
<p>Set <em>myhostname</em> to what you want your server to appear as in mail logs. I prefer that my server splash her name every where, so as far as other email servers are concerned she is <em>mail.odynia.org.</em></p>
<pre class="crayon-plain-tag">myhostname = mail.odynia.org</pre>
<p>You can leave the <em>mydomain</em> one alone, the default is based on your <em>myhostname</em>. In my case the default <em>mydomain</em> would be <em>odynia.org</em>.</p>
<p>The <em>myorigin</em> option is the domain that is used for outgoing emails from locally posted emails, such as bounce messages and emails from root, etc. The default is to use <em>myhostname,</em> but I feel having mail come from @mail.odynia.org to be a bit off putting. I set it to <em>mydomain</em>.</p>
<pre class="crayon-plain-tag">myorigin = $mydomain</pre>
<p>There is a lot of text there about <em>my destination, </em>but I prefer to set it to <em>myhostname</em>. That makes it the only domain that would receive mail should things go sour, which is perfect. All other domains will be virtual.</p>
<pre class="crayon-plain-tag">mydestination = $myhostname</pre>
<p>Likewise, empty out the <em>local_recipient_maps</em>, recipient maps are stored in PostgreSQL as virtual mailboxes.</p>
<pre class="crayon-plain-tag">local_recipient_maps =</pre>
<p>Set up your <em>mynetworks</em> to be a list of the IP addresses on your machine (localhost, internal and external). This way we don&#8217;t trust any other mail server, or anyone pretending to be a mail server.</p>
<pre class="crayon-plain-tag">mynetworks = 127.0.0.0/8, x.x.x.x/32</pre>
<p>This is an important one. Here&#8217;s a healthy tip from me: don&#8217;t try to be an outgoing email server. Set <em>relayhost</em> to your ISP&#8217;s SMTP server and save yourself the headache. The most time consuming and hardest part is keeping your email server off blacklists and other fun anti-spam measures, despite the fact that you&#8217;re sending legitimate email. It&#8217;s just not worth it.</p>
<pre class="crayon-plain-tag">relayhost = smtp.yourisp.com</pre>
<h3>Virtual Domains and Dovecot</h3>
<p>The <em>mailbox_command</em> option is where we specify Dovecot as the local delivery agent (LDA).</p>
<pre class="crayon-plain-tag">mailbox_command = /usr/local/libexec/dovecot/deliver</pre>
<p>I also set the <em>dovecot_destination_recipient_limit</em> to 1 in order to allow a <em>Delivered-To</em> header to be added to my messages. When you have almost unlimited email addresses and a spammer doesn&#8217;t put you in the <em>To</em> header it is helpful to know which email address it was delivered to.</p>
<pre class="crayon-plain-tag">dovecot_destination_recipient_limit = 1</pre>
<p>Now to configure our virtual domains. First set your <em>virtual_mailbox_domains</em> to a list of domains (comma separated) that you want to receive mail for.</p>
<pre class="crayon-plain-tag">virtual_mailbox_domains = domain.com, somedomain.com, someotherdomain.com</pre>
<p>And set the <em>virtual_mailbox_maps</em> to look in a PostgreSQL configuration file. This is the key bit and the contents of this file is discussed further down in PostgreSQL Configuration. The file will be stored in <em>/usr/local/etc/postfix/pgsql.cf</em>.</p>
<pre class="crayon-plain-tag">virtual_mailbox_maps = proxy:pgsql:$config_directory/pgsql.cf</pre>
<p>Then set your <em>virtual_transport</em> to <em>dovecot.</em></p>
<pre class="crayon-plain-tag">virtual_transport = dovecot</pre>
<p>To actually use the <em>dovecot</em> transport though, you will need to add the following line to your master process configuration file <em>/usr/local/etc/postfix/master.cf</em>.</p>
<pre class="crayon-plain-tag">dovecot unix - n n - - pipe flags=DRhu user=vmail:vmail argv=/usr/local/libexec/dovecot/deliver -f ${sender} -d ${recipient}</pre>
<p>In greater detail:</p>
<ul>
<li><em>flags=DRhu</em>: The flags to pass to dovecot. The <strong>D</strong> flag is for setting the <em>Delivered-To</em> header, but i have no idea what the others are. <strong>Every</strong> resource says you need to set those flags though.</li>
<li><em>user=vmail:vmail</em>: The user and group to run the <em>dovecot-lda</em> as. I use vmail as per the examples, but you will need to create the user account and group manually. This is covered more in <a title="Mail Server Setup: Part 2 – Dovecot and PostgreSQL" href="http://blog.odynia.org/?p=437">Part Two</a>.</li>
<li><em>argv=/usr/local/libexec/dovecot/deliver -f ${sender} -d ${recipient}</em>: The command line to execute <em>dovecot-lda</em>. The <em>${sender} </em>and <em>${recipient}</em> are replaced by the sender and recipient of the email being delivered. The email body is passed to <em>dovecot-lda</em> on STDIN.</li>
</ul>
<p>And so ends this portion of the Dovecot setup. The rest is covered in <a title="Mail Server Setup: Part 2 – Dovecot and PostgreSQL" href="http://blog.odynia.org/?p=437">Part Two</a>. It is important to note that you will not be able to receive email until the Dovecot setup has been completed.</p>
<h3>Security and Anti-Spam</h3>
<p>There are some basic things you should do to beef up your Postfix server&#8217;s security, even just that little bit, back over in <em>/usr/local/etc/postfix/main.cf</em>.</p>
<p>Set your <em>smtpd_helo_required</em> to <em>yes</em>. It is a basic thing but some lazy spammers don&#8217;t implement HELO in their mail clients. All &#8220;real&#8221; mail clients should implement it correctly.</p>
<pre class="crayon-plain-tag">smtpd_helo_required = yes</pre>
<p>And now for the recipient restrictions. You can configure any number of restrictions about who can deliver mail to your server, these are a few of the more common ones, detailed below.</p>
<pre class="crayon-plain-tag">smtpd_recipient_restrictions =
reject_non_fqdn_sender,
reject_non_fqdn_recipient,
reject_unknown_sender_domain,
reject_unknown_recipient_domain,
reject_unauth_destination,
reject_unauth_pipelining,
reject_rbl_client bl.spamcop.net,
reject_rbl_client cbl.abuseat.org,
reject_unauth_destination,
check_client_access hash:$config_directory/proct,
check_policy_service unix:private/policyd</pre>
<ul>
<li><em>reject_non_fqdn_sender:</em> Reject when the sender is not from a fully qualified domain (ie. someuser@fakedomain as opposed to someuser@fakedomain.com)</li>
<li><em>reject_non_fqdn_recipient:</em> Same again but for the recipient</li>
<li><em>reject_unknown_sender_domain:</em> This does a DNS lookup to verify that the domain is a real domain.</li>
<li><em>reject_unknown_recipient_domain:</em> Same again but for the recipient.</li>
<li><em>reject_unauth_destination</em>: Reject emails sent to domains that Postfix is not configured to receive mail for. We make sure this is here to prevent our server becoming an open relay.</li>
<li><em>reject_unauth_pipelining:</em> Pipelining is a way of sending all the SMTP commands to the server without waiting for each response, which speeds up delivery. It is also commonly implemented by bulk senders, so this prevents poorly built mail clients from assuming pipelining is enabled instead of asking first.</li>
<li><em>reject_rbl_client &lt;server&gt;</em>: This rejects emails by looking them up in a Relay Block List (RBL), a common, if antiquated, anti-spam technique.</li>
<li><em>check_policy_service unix:private/policyd</em>: This is the key to our SPF setup. It checks all emails against the SPF Policyd service, which is configured below.</li>
</ul>
<p>Now that we have our SPF setup in the <em>smtpd_recipient_restrictions</em> we need to configure the policy service. To do so you need to add the following to your master process configuration file, or <em>/usr/local/etc/postfix/master.cf</em> for short.</p>
<pre class="crayon-plain-tag">policyd unix - n n - - spawn user=nobody argv=/usr/local/sbin/postfix-policyd-spf-perl</pre>
<p>This will spawn a new instance of the <em>postfix-policyd-spf-perl</em> binary for each SPF lookup, running as the user <em>nobody</em>. And thats all it takes.</p>
<h3>Running as a Backup Mail Exchange</h3>
<p>I also want Shana to operate as a backup mail server for some domains that are hosted on Google Apps or Office 365. To do so you need to add the following to your <em>/usr/local/etc/postfix/main.cf</em>:</p>
<pre class="crayon-plain-tag">transport_maps = hash:$config_directory/transport</pre>
<p>This will check <em>/usr/local/etc/postfix/transport</em> for domains we should use an alternate delivery transport for. To add a domain, we first need to add it to <em>virtual_mailbox_domains</em> or some other list of domains in <em>/usr/local/etc/postfix/main.cf</em>, otherwise Postfix will reject the email.</p>
<p>Then in your <em>/usr/local/etc/postfix/transport</em> file:</p>
<pre class="crayon-plain-tag">somedomain.com relay:mx.server.name
* :</pre>
<p>Make sure you keep the last line, which means all other domains should still be delivered locally. Then run <em>postmap</em> to create the database file that Postfix uses (<em>/usr/local/etc/postfix/transport.db)</em>.</p>
<p></p><pre class="crayon-plain-tag">[root@shana /usr/local/etc/postfix]$ postmap /usr/local/etc/postfix/transport</pre><p></p>
<h2>PostgreSQL Configuration</h2>
<p>Now that we have Postfix all configured, we just need to setup our database and write the query that will look up the recipient in the database. The database design itself is very simple, a simple of mailboxes and a table of aliases.</p>
<p>In this case, we need to create a mail database, and a mail PostgreSQL user (with a password!):</p>
<p></p><pre class="crayon-plain-tag">[root@shana /]$ sudo -u pgsql -s

[pgsql@shana /]$ createdb mail

[pgsql@shana /]$ createuser -P mail
# Enter password for new role:
# Enter it again:
# Shall the new role be a superuser? (y/n) n
# Shall the new role be allowed to create databases? (y/n) n
# Shall the new role be allowed to create more new roles? (y/n) n</pre><p></p>
<h3>Mailboxes Table</h3>
<p>The Mailboxes Table has four columns:</p>
<table style="border: 1px solid #f7f7f7;" width="100%" cellspacing="0" cellpadding="0">
<thead>
<tr>
<th>Column</th>
<th>Type</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>mbox</td>
<td>text</td>
<td>The mailbox name. Typically an email address. A mailbox needs to be created on the the system with this name. Primary Key.</td>
</tr>
<tr>
<td>password</td>
<td>text</td>
<td>The password for this mailbox. Use <em>doveadm pw -s ssha256</em> to generate the passwords. Leaving a password blank will prevent that user from logging in.</td>
</tr>
<tr>
<td>quota</td>
<td>integer</td>
<td>The quota or maximum mailbox size in megabytes.</td>
</tr>
<tr>
<td>disabled</td>
<td>boolean</td>
<td>Whether this mailbox is disabled or not.</td>
</tr>
</tbody>
</table>
<p>You can use the following SQL to create the table:</p>
<p></p><pre class="crayon-plain-tag">CREATE TABLE mailboxes (
&quot;mbox&quot; text not null primary key,
&quot;password&quot; text not null,
&quot;quota&quot; integer default 0,
&quot;disabled&quot; boolean not null default false
);</pre><p></p>
<p>Then populate it with whatever you need to:</p>
<p></p><pre class="crayon-plain-tag">INSERT INTO mailboxes (mbox, password) VALUES ('someuser@somedomain.com', '{SSHA256}tUSmEcHBXAoyLpbwGUMKenMgguavaBS+sDbk2wIL+fdQ7wWj');</pre><p></p>
<h3>Aliases Table</h3>
<p>The Aliases Table is a way of creating an alias for a mailbox. Both Postfix and Dovecot will treat an alias as if it really was the mailbox. That means you can login to Dovecot as an alias, should the need arise.</p>
<p>The Aliases Table has two columns:</p>
<table style="border: 1px solid #f7f7f7;" width="100%" cellspacing="0" cellpadding="0">
<thead>
<tr>
<th>Column</th>
<th>Type</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>alias</td>
<td>text</td>
<td>The alias. Should be an email address or a wildcard in the form of <em>@domain.com</em>, or <em>user@</em>. Primary Key</td>
</tr>
<tr>
<td>mbox</td>
<td>text</td>
<td>The mailbox name. Should reference a row in the Mailboxes table.</td>
</tr>
</tbody>
</table>
<p>You can use the following SQL to create the table:</p>
<p></p><pre class="crayon-plain-tag">CREATE TABLE aliases (
&quot;alias&quot; text not null primary key,
&quot;mbox&quot; text not null references mailboxes (mbox)
);</pre><p></p>
<p>Then populate it with whatever you need to:</p>
<p></p><pre class="crayon-plain-tag">-- Aliasing one email address to another
INSERT INTO aliases (alias, mbox) VALUES ('anotheruser@somedomain.com', 'someuser@somedomain.com');

-- Catch all for a specific domain
INSERT INTO aliases (alias, mbox) VALUES ('@xxxdomain.com', 'someuser@somedomain.com');

-- Catch all for a user at all domains
INSERT INTO aliases (alias, mbox) VALUES ('postmaster@', 'someuser@somedomain.com');</pre><p></p>
<h3>Configuring the Postfix -&gt; PostgreSQL Mapping</h3>
<p>Back up a bit under Virtual Domains and Dovecot we setup our <em>virtual_mailbox_maps</em> to <em>proxy:pgsql:$config_directory/pgsql.cf</em>. This tells Postfix to lookup virtual mailbox maps (mapping an email address to a virtual mailbox) using the PostgreSQL proxy.</p>
<p>Once you&#8217;ve created your database we need to create the <em>pgsql.cf</em> file to match. Open up <em>/usr/local/etc/postfix/pgsql.cf</em> and add the following:</p>
<pre class="crayon-plain-tag">hosts = /tmp
user = mail
dbname = mail
password = somepassword

query = SELECT DISTINCT ON (mbox) mbox as userid FROM COALESCE((SELECT DISTINCT ON (mbox) mbox FROM mailboxes LEFT OUTER JOIN aliases USING (mbox) WHERE (mailboxes.mbox = '%s' OR aliases.alias = '%s') AND mailboxes.disabled = false), (SELECT DISTINCT ON (mbox) mbox FROM mailboxes LEFT OUTER JOIN aliases USING (mbox) WHERE aliases.alias = '@%d' AND mailboxes.disabled = false), (SELECT DISTINCT ON (mbox) mbox FROM mailboxes LEFT OUTER JOIN aliases USING (mbox) WHERE aliases.alias = '%u@' AND mailboxes.disabled = false)) as mbox;</pre>
<p>The <em>hosts</em> option it set to <em>/tmp</em> so that it uses the default PostgreSQL unix socket, as opposed to a TCP socket. Set your <em>dbname, user</em> and <em>password</em> to match the database you created earlier.</p>
<p>The query is the interesting bit of all of this, lets reformat it and break it down.</p>
<p></p><pre class="crayon-plain-tag">SELECT
DISTINCT ON (mbox) mbox as userid
FROM
COALESCE
(
(SELECT DISTINCT ON (mbox) mbox FROM mailboxes LEFT OUTER JOIN aliases USING (mbox) WHERE (mailboxes.mbox = '%s' OR aliases.alias = '%s') AND mailboxes.disabled = false),
(SELECT DISTINCT ON (mbox) mbox FROM mailboxes LEFT OUTER JOIN aliases USING (mbox) WHERE aliases.alias = '@%d' AND mailboxes.disabled = false),
(SELECT DISTINCT ON (mbox) mbox FROM mailboxes LEFT OUTER JOIN aliases USING (mbox) WHERE aliases.alias = '%u@' AND mailboxes.disabled = false)
) as mbox;</pre><p></p>
<p>Hopefully that will make it a little clearer, apologies for the scroll. It basically runs three subqueries for the different types of lookups and returns a unique mbox from the first subquery that returns results.</p>
<h3>Query Details</h3>
<p>Lets look at each of those subqueries in a bit more detail.</p>
<p></p><pre class="crayon-plain-tag">SELECT
DISTINCT ON (mbox) mbox
FROM
mailboxes LEFT OUTER JOIN aliases USING (mbox)
WHERE
(mailboxes.mbox = '%s' OR aliases.alias = '%s') AND mailboxes.disabled = false</pre><p></p>
<p>This will look in the <em>mbox</em> column of the <em>mailboxes</em> table and the <em>alias</em> columns of the <em>aliases</em> table for &#8220;%s&#8221;, which PostgreSQL will expand to be the full email address of the recipient.</p>
<p></p><pre class="crayon-plain-tag">SELECT
DISTINCT ON (mbox) mbox
FROM
mailboxes LEFT OUTER JOIN aliases USING (mbox)
WHERE
aliases.alias = '@%d' AND mailboxes.disabled = false</pre><p></p>
<p>This will look in the <em>alias</em> column of the <em>alias</em> table for &#8220;@%d&#8221;, or the @ symbol followed by the domain name only portion of the recipient&#8217;s email address.</p>
<p></p><pre class="crayon-plain-tag">SELECT
DISTINCT ON (mbox) mbox
FROM
mailboxes LEFT OUTER JOIN aliases USING (mbox)
WHERE
aliases.alias = '%u@' AND mailboxes.disabled = false</pre><p></p>
<p>This will look in the <em>alias</em> column of the <em>alias</em> table for &#8220;%u@&#8221;, or the username only portion of the recipient&#8217;s email address.</p>
<h2>The End For Now</h2>
<p>And thats it! A fully configured Postfix setup with PostgreSQL lookups. If you stayed with me through this absurdly long post, thanks!</p>
<p>It is important to know though before you leave here that you can&#8217;t yet receive email until the Dovecot setup has been completed. For that, you will need to read <a title="Mail Server Setup: Part 2 – Dovecot and PostgreSQL" href="http://blog.odynia.org/?p=437">Part Two</a>, which is coming tomorrow.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.odynia.org/2012/07/mail-server-setup-part-1-postfix-and-postgresql/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Installing MySQL and SSD/ZFS Benchmarks</title>
		<link>http://blog.odynia.org/2012/06/installing-mysql-and-ssdzfs-benchmarks/</link>
		<comments>http://blog.odynia.org/2012/06/installing-mysql-and-ssdzfs-benchmarks/#comments</comments>
		<pubDate>Fri, 29 Jun 2012 08:00:24 +0000</pubDate>
		<dc:creator>Rob</dc:creator>
				<category><![CDATA[Server Build]]></category>
		<category><![CDATA[freebsd]]></category>
		<category><![CDATA[hdd]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[server build]]></category>
		<category><![CDATA[shana]]></category>
		<category><![CDATA[ssd]]></category>
		<category><![CDATA[zfs]]></category>

		<guid isPermaLink="false">http://blog.odynia.org/?p=418</guid>
		<description><![CDATA[Here we go again. This post walks through installing MySQL and running through some benchmarks to discover how best to utilise the SSDs and ZFS. Installing MySQL Naturally, the first thing you must do is install MySQL. There has been a lot of activity with Percona and MariaDB lately but we&#8217;ll stick with vanilla MySQL [...]]]></description>
				<content:encoded><![CDATA[<p>Here we go again. This post walks through installing MySQL and running through some benchmarks to discover how best to utilise the SSDs and ZFS.</p>
<h2>Installing MySQL</h2>
<p>Naturally, the first thing you must do is install MySQL. There has been a lot of activity with Percona and MariaDB lately but we&#8217;ll stick with vanilla MySQL for the moment due to time constraints. We can drop in one of the other two later as required.</p>
<p>Advice for utilising an SSD in your MySQL deployment is pretty scattered and confusing. The best resource I&#8217;ve been able to find is <a href="http://www.slideshare.net/matsunobu/ssd-deployment-strategies-for-mysql">this set of slides</a> from Sun/MySQL.</p>
<p>Installing MySQL is a simple procedure using ports:</p>
<p></p><pre class="crayon-plain-tag">#[root@shana /]$ cd /usr/ports/databases/mysql55-server/

[root@shana /usr/ports/databases/mysql55-server]$ make install clean
# ===&amp;gt; Found saved configuration for mysql-server-5.5.25
# =&amp;gt; mysql-5.5.25.tar.gz doesn't seem to exist in /usr/ports/distfiles/.
#
# ===&amp;gt; Compressing manual pages for mysql-server-5.5.25
# ===&amp;gt; Registering installation for mysql-server-5.5.25
# ===&amp;gt; SECURITY REPORT:
# This port has installed the following files which may act as network
# servers and may therefore pose a remote security risk to the system.
# /usr/local/libexec/mysqld
#
# This port has installed the following startup scripts which may cause
# these network services to be started at boot time.
# /usr/local/etc/rc.d/mysql-server
#
# If there are vulnerabilities in these programs there may be a security
# risk to the system. FreeBSD makes no guarantee about the security of
# ports included in the Ports Collection. Please type 'make deinstall'
# to deinstall the port if this is a concern.
#
# For more information, and contact details about the security
# status of this software, see the following webpage:
# http://www.mysql.com/
# ===&amp;gt; Cleaning for cmake-2.8.8
# ===&amp;gt; Cleaning for mysql-client-5.5.25
# ===&amp;gt; Cleaning for mysql-server-5.5.25</pre><p></p>
<p>Easy as that. You can enable MySQL (and leave the data directory in the default <em>/var/db/mysql</em> location) just by adding the following line to <em>/etc/rc.conf</em>.</p>
<pre class="crayon-plain-tag">mysql_enable=&quot;YES&quot;</pre>
<p>Then start it up:</p>
<p></p><pre class="crayon-plain-tag">[root@shana /]$ /usr/local/etc/rc.d/mysql start</pre><p></p>
<h2>Benchmarking</h2>
<p>For benchmarking MySQL we&#8217;ll use <a href="http://sysbench.sourceforge.net/"><em>sysbench</em></a>. In line with the PostgreSQL testing we did, we&#8217;ll create <em>/mydbtmp</em> and <em>/mylogtmp</em> drives in ZFS as they are required.</p>
<p>We&#8217;ll test the following scenarios, both with <strong>MyISAM</strong> and <strong>InnoDB</strong> (the most common engines).</p>
<ol>
<li>Running everything on zroot (Mirrored HDDs)</li>
<li>Running everything on zflash (Mirrored SSDs)</li>
<li>Running everything on zapps (Mirrored HDDs with SSD ZIL/L2ARC)</li>
</ol>
<ul>
<li>Splitting the data and logs</li>
</ul>
<p>We&#8217;ll look at ZFS optimisations after.</p>
<h3>Setup</h3>
<p>We repeat these steps for each benchmark. For our first three benchmarks we&#8217;ll only need <em>/mydbtmp</em>. Create it using ZFS:</p>
<p></p><pre class="crayon-plain-tag">[root@shana /]$ zfs create -o mountpoint=/mydbtmp/mydbtmp</pre><p></p>
<p>Substituting &lt;pool&gt; for <em>zroot</em>, <em>zapps</em>, and <em>zflash</em> as required.</p>
<p>To tell MySQL to use those data directories, add the following to your <em>/etc/rc.conf</em>:</p>
<pre class="crayon-plain-tag">mysql_datadir=&quot;/mydbtmp&quot;</pre>
<p>We will also need to create the mysql database and username:</p>
<p></p><pre class="crayon-plain-tag">[root@shana /]$ mysqladmin create sbtest

[root@shana /]$ mysql
#
# Welcome to the MySQL monitor. Commands end with ; or \g.
# Your MySQL connection id is 12
# Server version: 5.5.25 Source distribution
#
# Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
#
# Oracle is a registered trademark of Oracle Corporation and/or its
# affiliates. Other names may be trademarks of their respective
# owners.
#
# Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql&amp;gt; create user 'sbtest'@'localhost';
# Query OK, 0 rows affected (0.00 sec)

mysql&amp;gt; grant all privileges on sbtest.* to 'sbtest'@'localhost' with grant option;
# Query OK, 0 rows affected (0.00 sec)</pre><p></p>
<p>Then we tell <em>sysbench</em> to prepare the database for testing.</p>
<p></p><pre class="crayon-plain-tag">[root@shana /]$ sysbench --test=oltp --mysql-table-engine=myisam --oltp-table-size=1000000 --mysql-socket=/tmp/mysql.sock --mysql-user=sbtest prepare
# sysbench 0.4.12: multi-threaded system evaluation benchmark
#
# No DB drivers specified, using mysql
# Creating table 'sbtest'...
# Creating 1000000 records in table 'sbtest'...</pre><p></p>
<p>Here we&#8217;re creating a table <em>sbtest</em> and populating it with a million records. Then we can run the benchmark:</p>
<p></p><pre class="crayon-plain-tag">[root@shana /]$ sysbench --num-threads=16 --max-requests=100000 --test=oltp --oltp-table-size=1000000 --mysql-socket=/tmp/mysql.sock --mysql-user=sbtest run
# sysbench 0.4.12: multi-threaded system evaluation benchmark
#
# No DB drivers specified, using mysql
# Running the test with following options:
# Number of threads: 16
#
# Doing OLTP test.
# Running mixed OLTP test
# Using Special distribution (12 iterations, 1 pct of values are returned in 75 pct cases)
# Using &quot;LOCK TABLES WRITE&quot; for starting transactions
# Using auto_inc on the id column
# Maximum number of requests for OLTP test is limited to 100000
# Threads started!
# Done.
#
# OLTP test statistics:
# queries performed:
# read: 1400000
# write: 500000
# other: 200000
# total: 2100000
# transactions: 100000 (193.98 per sec.)
# deadlocks: 0 (0.00 per sec.)
# read/write requests: 1900000 (3685.55 per sec.)
# other operations: 200000 (387.95 per sec.)
#
# Test execution summary:
# total time: 515.5274s
# total number of events: 100000
# total time taken by event execution: 8247.0597
# per-request statistics:
# min: 6.97ms
# avg: 82.47ms
# max: 785.73ms
# approx. 95 percentile: 79.73ms
#
# Threads fairness:
# events (avg/stddev): 6250.0000/0.00
# execution time (avg/stddev): 515.4412/0.02</pre><p></p>
<p>All done! Jump into MySQL to drop the <em>sbtest</em> table, then we run <em>sysbench</em> again but this time with <em>&#8211;mysql-table-engine=innodb</em>.</p>
<p></p><pre class="crayon-plain-tag">mysql&amp;gt; drop table sbtest;
# Query OK, 0 rows affected (0.05 sec)</pre><p></p>
<p>Then we can destroy the <em>/mydbtmp</em> filesystem and create it again on a different drive ready for the next test.</p>
<h3>Results</h3>
<p>The results here are interesting, mostly because of how they contradict the advice linked above.</p>
<table style="border: 1px solid #f7f7f7;" width="100%" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<th rowspan="2">Volume</th>
<th colspan="2">Transactions Per Second</th>
</tr>
<tr>
<th>MyISAM</th>
<th>InnoDB</th>
</tr>
<tr>
<td>zroot (Mirrored HDDs)</td>
<td style="text-align: right;">193.98</td>
<td style="text-align: right;">884.76</td>
</tr>
<tr>
<td>zapps (Mirrored HDDs with ZIL/L2ARC)</td>
<td style="text-align: right;">199.11</td>
<td style="text-align: right;">804.81</td>
</tr>
<tr>
<td>zflash (Mirrored SSDs)</td>
<td style="text-align: right; background-color: #ccffcc;">199.03</td>
<td style="text-align: right; background-color: #ccffcc;">1007.80</td>
</tr>
<tr>
<td>zroot logs</td>
<td style="text-align: right;">196.44</td>
<td style="text-align: right;">764.76</td>
</tr>
<tr>
<td>zflash logs</td>
<td style="text-align: right;">186.94</td>
<td style="text-align: right;">912.90</td>
</tr>
</tbody>
</table>
<p>Graphically:</p>
<div id="attachment_419" class="wp-caption aligncenter" style="width: 1316px"><a href="http://blog.odynia.org/wp-content/uploads/2012/06/MySQL-Optimisation-Results.png" rel="lightbox[418]"><img class="size-full wp-image-419" title="MySQL Optimisation Results" src="http://blog.odynia.org/wp-content/uploads/2012/06/MySQL-Optimisation-Results.png" alt="" width="1306" height="475" /></a><p class="wp-caption-text">MySQL Benchmark Results</p></div>
<h3>Conclusion</h3>
<p>It seems the simplest way to improve performance with MySQL is to throw everything on to the SSDs. It is noted though that the InnoDB gains much more performance benefit than MyISAM. If you&#8217;re stuck with MyISAM tables it might not be worth investing in a SSD.</p>
<p>For now, I&#8217;ll create <em>/var/mysql/data</em> on <em>zflash</em> and store my databases there.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.odynia.org/2012/06/installing-mysql-and-ssdzfs-benchmarks/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
