<?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>A Collection of Thoughts</title>
	<atom:link href="http://www.paul-norman.co.uk/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.paul-norman.co.uk</link>
	<description>PHP, MySQL, Coding, Javascript, HTML, CSS</description>
	<lastBuildDate>Fri, 13 Jan 2012 17:24:33 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	
		<item>
		<title>EC2 Guide: Backing up and clean up (7 / 7)</title>
		<link>http://www.paul-norman.co.uk/2011/02/backing-up-and-clean-up/</link>
		<comments>http://www.paul-norman.co.uk/2011/02/backing-up-and-clean-up/#comments</comments>
		<pubDate>Mon, 28 Feb 2011 23:53:22 +0000</pubDate>
		<dc:creator>Paul Norman</dc:creator>
				<category><![CDATA[Server]]></category>
		<category><![CDATA[Backing up]]></category>
		<category><![CDATA[Cloud]]></category>
		<category><![CDATA[EBS]]></category>
		<category><![CDATA[EC2]]></category>
		<category><![CDATA[ec2-consistent-snapshot]]></category>
		<category><![CDATA[Logrotate]]></category>
		<category><![CDATA[Snapshotting]]></category>
		<category><![CDATA[Ubuntu 10.04]]></category>

		<guid isPermaLink="false">http://www.paul-norman.co.uk/?p=55</guid>
		<description><![CDATA[The final stage in the guide concerns backing up the EBS volumes nightly so as to avoid disasters! It also covers keeping the number of these generated under control and rotating any moved logs.]]></description>
			<content:encoded><![CDATA[##previous-next-page-7##

<h2>Logs / Log rotation</h2>

<p>Because we changed the paths to our mail logs we need to update our logrotate files. Only update those that have changed:</p>

<pre class="command">
sudo ##editor## /etc/logrotate.d/rsyslog 
</pre>

<pre class="file">
<span style="color: green;">/var/log/postfix/mail.info
/var/log/postfix/mail.warn
/var/log/postfix/mail.err
/var/log/postfix/mail.log
/var/log/dovecot/log
/var/log/dovecot/info
/var/log/dovecot/lda</span>
/var/log/daemon.log
/var/log/kern.log
/var/log/auth.log
/var/log/user.log
/var/log/lpr.log
/var/log/cron.log
/var/log/debug
/var/log/messages
{
        rotate 4
        weekly
        missingok
        notifempty
        compress
        delaycompress
        sharedscripts
        postrotate
                reload rsyslog >/dev/null 2>&#038;1 || true
        endscript
}
</pre>

<p>Clean up after ourselves:</p>

<pre class="command">
sudo rm /etc/logrotate.d/rsyslog~ 
</pre>

<h2>Installing a snapshotting tool (cloud only)</h2>

<p>One of the great features of EC2 is the ability to take a snapshot of an entire EBS volume (irrespective of size) in about 3-10 seconds. Automating these calls gives some excellent backup potential. I recommend a tool called <em>ec2-consistent-snapshot</em> by <a href="http://alestic.com/" title="Visit Alestic" target="_blank">Eric Hammond</a> to assist with backups. This is very easy to get set up:</p>

<pre class="command">
sudo add-apt-repository ppa:alestic 
sudo aptitude update 
sudo aptitude install ec2-consistent-snapshot 
</pre>


<h2>Configure snapshotting (cloud only)</h2>

<p>To make our commands simpler and avoid having config files all over the place we can set some environmental variables about our attached EBS volumes. To do this we need to obtain our attached volume IDs from Elasticfox:</p>

<ul>
<li>Click on the &#8220;Volumes and Snapshots&#8221; tab</li>
<li>Make a note of or copy (right click -&gt; &#8220;Copy Volume ID to clipboard&#8221;) each of the volume IDs</li>
</ul>

<p>Back on the server we will set these values into the environmental variables:</p>

<pre class="command">
sudo ##editor## /etc/bash.bashrc 
</pre>

<pre class="file">
[...]
export VOLUME_ID_CORE=##volume_id_core##
export VOLUME_ID_WEBSERVER=##volume_id_webserver##
export VOLUME_ID_EMAIL=##volume_id_email##
export VOLUME_ID_DATABASE=##volume_id_database##
export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games
</pre>

<pre class="command">
sudo ##editor## /etc/profile 
</pre>

<pre class="file">
[...]
export VOLUME_ID_CORE=##volume_id_core##
export VOLUME_ID_WEBSERVER=##volume_id_webserver##
export VOLUME_ID_EMAIL=##volume_id_email##
export VOLUME_ID_DATABASE=##volume_id_database##
export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games
</pre>

<p>Reload our shell variables:</p>

<pre class="command">
source /etc/bash.bashrc 
source /etc/profile 
source ~/.bashrc 
</pre>

<p>We need to make bash script files to run our commands. Firstly we can backup the database volume, which needs to have the MySQL details passed so the snapshot can be taken safely (without losing data).</p>

<pre class="command">
sudo mkdir /home/ubuntu/snapshotting 
sudo ##editor## /home/ubuntu/snapshotting/database.sh 
</pre>

<pre class="file">
#!/bin/bash -l

ec2-consistent-snapshot --description "Database Backup $(date +'%Y-%m-%d %H:%M:%S')" --region "$EC2_REGION" --mysql --mysql-host "localhost" --mysql-socket "/var/run/mysqld/mysqld.sock" --mysql-username "root" --mysql-password "##root_db_password##" --xfs-filesystem /database $VOLUME_ID_DATABASE
</pre>

<p>The webserver backup is similar, but does not require MySQL to be stopped:</p>

<pre class="command">
sudo ##editor## /home/ubuntu/snapshotting/webserver.sh 
</pre>

<pre class="file">
#!/bin/bash -l

ec2-consistent-snapshot --description "Webserver Backup $(date +'%Y-%m-%d %H:%M:%S')" --region $EC2_REGION --xfs-filesystem /webserver $VOLUME_ID_WEBSERVER
</pre>

<p>The e-mail backup is almost identical to the webserver and does not require MySQL to be stopped:</p>

<pre class="command">
sudo ##editor## /home/ubuntu/snapshotting/email.sh 
</pre>

<pre class="file">
#!/bin/bash -l

ec2-consistent-snapshot --description "E-mail Backup $(date +'%Y-%m-%d %H:%M:%S')" --region $EC2_REGION --xfs-filesystem /email $VOLUME_ID_EMAIL
</pre>

<p>These files need to be executable, and we should clean up any temporary files our editor may have left.</p>

<pre class="command">
sudo chmod +x /home/ubuntu/snapshotting/* 
sudo rm /home/ubuntu/snapshotting/*~ 
</pre>

<p>In order to freeze / unfreeze the XFS file-system the actual commands need to run as root so we will add our commands to root&#8217;s crontab.</p>

<pre class="command">
su root 
</pre>

<pre class="command">
crontab -e 
</pre>

<pre class="file">
0 6 * * * /home/ubuntu/snapshotting/database.sh >> /home/ubuntu/backup.log 2>&#038;1
1 6 * * * /home/ubuntu/snapshotting/webserver.sh >> /home/ubuntu/backup.log 2>&#038;1
2 6 * * * /home/ubuntu/snapshotting/email.sh >> /home/ubuntu/backup.log 2>&#038;1
</pre>

<p>Leave the root user.</p>

<pre class="command">
exit 
</pre>


<h2>Cleaning up old snapshots (cloud only)</h2>

<p>Amazon don&#8217;t seem to have a tool to do this neatly, and with a bit of research I found several built in PHP (a language I know) so I decided to roll my own based on a few of these. It&#8217;s only a rough draft, but meets my current needs.</p>

<pre class="command">
sudo ##editor## /var/www/remove_old_snapshots.php 
</pre>

<div class="codecolorer-container php default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;height:400px;"><div class="php codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">#!/usr/bin/php<br />
<span style="color: #000000; font-weight: bold;">&lt;?php</span><br />
<span style="color: #666666; font-style: italic;"># Options may be hard coded here or passed in at run time<br />
</span><span style="color: #000088;">$ec2_private_key</span>&nbsp; &nbsp; <span style="color: #339933;">=</span> <span style="color: #009900; font-weight: bold;">null</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;"># '/home/ubuntu/pk-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.pem';<br />
</span><span style="color: #000088;">$ec2_cert</span> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #339933;">=</span> <span style="color: #009900; font-weight: bold;">null</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;"># '/home/ubuntu/cert-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.pem';<br />
</span><span style="color: #000088;">$regions</span>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #339933;">=</span> <span style="color: #009900; font-weight: bold;">null</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;"># array('eu-west-1', 'us-east-1'); # OR # 'eu-west-1';<br />
</span><span style="color: #000088;">$volumes</span>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #339933;">=</span> <span style="color: #009900; font-weight: bold;">null</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;"># array('vol-XXXXXXXX', 'vol-XXXXXXXX'); # OR # 'vol-XXXXXXXX';<br />
</span><span style="color: #000088;">$number_to_keep</span> &nbsp; &nbsp; <span style="color: #339933;">=</span> <span style="color: #009900; font-weight: bold;">null</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;"># array(7, 1); # OR # 7;<br />
</span><span style="color: #000088;">$min_number_to_keep</span> <span style="color: #339933;">=</span> <span style="color: #cc66cc;">1</span><span style="color: #339933;">;</span>&nbsp; &nbsp; <span style="color: #666666; font-style: italic;"># Prevent any accidents<br />
</span><br />
<span style="color: #666666; font-style: italic;"># Optional list of snapshot IDs to omit from this purge process<br />
</span><span style="color: #000088;">$omit</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;"># array('snap-XXXXXXXX', 'snap-XXXXXXXX'); # OR # 'snap-XXXXXXXX';<br />
</span><br />
<span style="color: #000088;">$options</span> <span style="color: #339933;">=</span> <span style="color: #990000;">getopt</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'K:C:v:n:r:o:sd:ed:'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
<span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span><span style="color: #990000;">isset</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$options</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'v'</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span> OR <span style="color: #990000;">is_null</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$options</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'v'</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><br />
<span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">is_null</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$volumes</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">echo</span> <span style="color: #0000ff;">&quot;ERROR: Please provide at least one volume to check (-v option)<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #990000;">exit</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">else</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000088;">$options</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'v'</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$volumes</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
<span style="color: #009900;">&#125;</span><br />
<br />
<span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span><span style="color: #990000;">isset</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$options</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'n'</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span> OR <span style="color: #990000;">is_null</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$options</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'n'</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><br />
<span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">is_null</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$number_to_keep</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">echo</span> <span style="color: #0000ff;">&quot;ERROR: Please provide number of snapshots to keep (-n option)<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #990000;">exit</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">else</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000088;">$options</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'n'</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$number_to_keep</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
<span style="color: #009900;">&#125;</span><br />
<br />
<span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span><span style="color: #990000;">isset</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$options</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'r'</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span> OR <span style="color: #990000;">is_null</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$options</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'r'</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><br />
<span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">is_null</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$regions</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">echo</span> <span style="color: #0000ff;">&quot;ERROR: Please provide a region for these volumes (-n option)<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #990000;">exit</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">else</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000088;">$options</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'r'</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$regions</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
<span style="color: #009900;">&#125;</span><br />
<br />
<span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span><span style="color: #990000;">isset</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$options</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'K'</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span> OR <span style="color: #990000;">is_null</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$options</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'K'</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><br />
<span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">is_null</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$ec2_private_key</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">echo</span> <span style="color: #0000ff;">&quot;ERROR: Please provide an EC2 key file location for these volumes (-K option)<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #990000;">exit</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">else</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000088;">$options</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'K'</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$ec2_private_key</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
<span style="color: #009900;">&#125;</span><br />
<br />
<span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span><span style="color: #990000;">isset</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$options</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'C'</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span> OR <span style="color: #990000;">is_null</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$options</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'C'</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><br />
<span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">is_null</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$ec2_cert</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">echo</span> <span style="color: #0000ff;">&quot;ERROR: Please provide an EC2 Cert file location for these volumes (-C option)<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #990000;">exit</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">else</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000088;">$options</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'C'</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$ec2_cert</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
<span style="color: #009900;">&#125;</span><br />
<br />
<span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span><span style="color: #990000;">isset</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$options</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'o'</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span> OR <span style="color: #990000;">is_null</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$options</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'o'</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><br />
<span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #000088;">$options</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'o'</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$omit</span><span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span><br />
<br />
<span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span><span style="color: #990000;">is_array</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$options</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'v'</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><br />
<span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #000088;">$volumes</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$options</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'v'</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span><br />
<span style="color: #b1b100;">else</span><br />
<span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #000088;">$volumes</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$options</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'v'</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span><br />
<br />
<span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span><span style="color: #990000;">is_array</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$options</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'n'</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><br />
<span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #000088;">$number_to_keep</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$options</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'n'</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span><br />
<span style="color: #b1b100;">else</span><br />
<span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #000088;">$number_to_keep</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$options</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'n'</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span><br />
<br />
<span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span><span style="color: #990000;">is_array</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$options</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'r'</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><br />
<span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #000088;">$regions</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$options</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'r'</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span><br />
<span style="color: #b1b100;">else</span><br />
<span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #000088;">$regions</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$options</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'r'</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span><br />
<br />
<span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span><span style="color: #990000;">is_array</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$options</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'K'</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><br />
<span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #000088;">$ec2_private_key</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$options</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'K'</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span><br />
<span style="color: #b1b100;">else</span><br />
<span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">echo</span> <span style="color: #0000ff;">&quot;ERROR: Please provide a SINGLE EC2 key file location for these volumes (-K option)<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #990000;">exit</span><span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span><br />
<br />
<span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span><span style="color: #990000;">is_array</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$options</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'C'</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><br />
<span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #000088;">$ec2_cert</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$options</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'C'</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span><br />
<span style="color: #b1b100;">else</span><br />
<span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">echo</span> <span style="color: #0000ff;">&quot;ERROR: Please provide a SINGLE EC2 Cert file location for these volumes (-C option)<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #990000;">exit</span><span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span><br />
<br />
<span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span><span style="color: #990000;">is_array</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$options</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'o'</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><br />
<span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #000088;">$omit</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$options</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'o'</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span><br />
<span style="color: #b1b100;">else</span><br />
<span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #000088;">$omit</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$options</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'o'</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span><br />
<br />
<span style="color: #b1b100;">foreach</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$number_to_keep</span> <span style="color: #b1b100;">as</span> <span style="color: #000088;">$key</span> <span style="color: #339933;">=&gt;</span> <span style="color: #000088;">$value</span><span style="color: #009900;">&#41;</span><br />
<span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$value</span> <span style="color: #339933;">&lt;</span> <span style="color: #000088;">$min_number_to_keep</span><span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000088;">$number_to_keep</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$key</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$value</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
<span style="color: #009900;">&#125;</span><br />
<br />
<span style="color: #000088;">$total_volumes</span>&nbsp; <span style="color: #339933;">=</span> <span style="color: #990000;">count</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$volumes</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #000088;">$total_kept</span> &nbsp; &nbsp; <span style="color: #339933;">=</span> <span style="color: #990000;">count</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$number_to_keep</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #000088;">$total_regions</span>&nbsp; <span style="color: #339933;">=</span> <span style="color: #990000;">count</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$regions</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
<span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$total_volumes</span> <span style="color: #339933;">!=</span> <span style="color: #000088;">$total_kept</span><span style="color: #009900;">&#41;</span><br />
<span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$total_volumes</span> <span style="color: #339933;">&gt;</span> <span style="color: #000088;">$total_kept</span> AND <span style="color: #000088;">$total_kept</span> <span style="color: #339933;">==</span> <span style="color: #cc66cc;">1</span><span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #666666; font-style: italic;"># Use the number to keep as a global value<br />
</span>&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">foreach</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$volumes</span> <span style="color: #b1b100;">as</span> <span style="color: #000088;">$key</span> <span style="color: #339933;">=&gt;</span> <span style="color: #000088;">$value</span><span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000088;">$number_to_keep</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$key</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$number_to_keep</span><span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">0</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">else</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #666666; font-style: italic;"># An error is likely, we should stop<br />
</span>&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">echo</span> <span style="color: #0000ff;">&quot;ERROR: Please check the values entered, there is an argument mismatch (-v vs. -n)<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #990000;">exit</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
<span style="color: #009900;">&#125;</span><br />
<br />
<span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$total_volumes</span> <span style="color: #339933;">!=</span> <span style="color: #000088;">$total_regions</span><span style="color: #009900;">&#41;</span><br />
<span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$total_volumes</span> <span style="color: #339933;">&gt;</span> <span style="color: #000088;">$total_regions</span> AND <span style="color: #000088;">$total_regions</span> <span style="color: #339933;">==</span> <span style="color: #cc66cc;">1</span><span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #666666; font-style: italic;"># Use the region as a global value<br />
</span>&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">foreach</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$volumes</span> <span style="color: #b1b100;">as</span> <span style="color: #000088;">$key</span> <span style="color: #339933;">=&gt;</span> <span style="color: #000088;">$value</span><span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000088;">$regions</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$key</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$regions</span><span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">0</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">else</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #666666; font-style: italic;"># An error is likely, we should stop<br />
</span>&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">echo</span> <span style="color: #0000ff;">&quot;ERROR: Please check the values entered, there is an argument mismatch (-v vs. -r)<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #990000;">exit</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
<span style="color: #009900;">&#125;</span><br />
<br />
<span style="color: #b1b100;">foreach</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$regions</span> <span style="color: #b1b100;">as</span> <span style="color: #000088;">$key</span> <span style="color: #339933;">=&gt;</span> <span style="color: #000088;">$region</span><span style="color: #009900;">&#41;</span><br />
<span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #000088;">$process</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$region</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$volumes</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$key</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$number_to_keep</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$key</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>&nbsp; <br />
<span style="color: #009900;">&#125;</span><br />
<span style="color: #990000;">unset</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$number_to_keep</span><span style="color: #339933;">,</span> <span style="color: #000088;">$regions</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
<span style="color: #000088;">$raw</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #b1b100;">foreach</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$process</span> <span style="color: #b1b100;">as</span> <span style="color: #000088;">$region</span> <span style="color: #339933;">=&gt;</span> <span style="color: #000088;">$details</span><span style="color: #009900;">&#41;</span><br />
<span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #000088;">$tmp</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #000088;">$cmd</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">'ec2-describe-snapshots -K '</span><span style="color: #339933;">.</span><span style="color: #000088;">$ec2_private_key</span><span style="color: #339933;">.</span><span style="color: #0000ff;">' -C '</span><span style="color: #339933;">.</span><span style="color: #000088;">$ec2_cert</span><span style="color: #339933;">.</span><span style="color: #0000ff;">' --region '</span><span style="color: #339933;">.</span><span style="color: #000088;">$region</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #990000;">exec</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$cmd</span><span style="color: #339933;">,</span> <span style="color: #000088;">$tmp</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">is_array</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$tmp</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">foreach</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$tmp</span> <span style="color: #b1b100;">as</span> <span style="color: #000088;">$key</span> <span style="color: #339933;">=&gt;</span> <span style="color: #000088;">$value</span><span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000088;">$tmp</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$key</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">.=</span> <span style="color: #0000ff;">&quot;<span style="color: #000099; font-weight: bold;">\t</span>&quot;</span><span style="color: #339933;">.</span><span style="color: #000088;">$ec2_private_key</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000088;">$tmp</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$key</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">.=</span> <span style="color: #0000ff;">&quot;<span style="color: #000099; font-weight: bold;">\t</span>&quot;</span><span style="color: #339933;">.</span><span style="color: #000088;">$ec2_cert</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000088;">$tmp</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$key</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">.=</span> <span style="color: #0000ff;">&quot;<span style="color: #000099; font-weight: bold;">\t</span>&quot;</span><span style="color: #339933;">.</span><span style="color: #000088;">$region</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000088;">$raw</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array_merge</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$raw</span><span style="color: #339933;">,</span> <span style="color: #000088;">$tmp</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
<span style="color: #009900;">&#125;</span><br />
<br />
<span style="color: #000088;">$found</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #b1b100;">foreach</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$raw</span> <span style="color: #b1b100;">as</span> <span style="color: #000088;">$snapshot</span><span style="color: #009900;">&#41;</span><br />
<span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #000088;">$tmp</span> <span style="color: #339933;">=</span> <span style="color: #990000;">split</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;<span style="color: #000099; font-weight: bold;">\t</span>&quot;</span><span style="color: #339933;">,</span> <span style="color: #000088;">$snapshot</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">in_array</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$tmp</span><span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">2</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span> <span style="color: #000088;">$volumes</span><span style="color: #009900;">&#41;</span> AND <span style="color: #339933;">!</span><span style="color: #990000;">in_array</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$tmp</span><span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">1</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span> <span style="color: #000088;">$omit</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000088;">$tmp</span><span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$process</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$tmp</span><span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">11</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$tmp</span><span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">2</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000088;">$found</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$tmp</span><span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">2</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #990000;">strtotime</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$tmp</span><span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">4</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$tmp</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
<span style="color: #009900;">&#125;</span><br />
<br />
<span style="color: #b1b100;">foreach</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$found</span> <span style="color: #b1b100;">as</span> <span style="color: #000088;">$volume_id</span> <span style="color: #339933;">=&gt;</span> <span style="color: #000088;">$snapshots</span><span style="color: #009900;">&#41;</span><br />
<span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #990000;">krsort</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$found</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$volume_id</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span><br />
<br />
<span style="color: #990000;">unset</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$volumes</span><span style="color: #339933;">,</span> <span style="color: #000088;">$process</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
<span style="color: #b1b100;">foreach</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$found</span> <span style="color: #b1b100;">as</span> <span style="color: #000088;">$volume_id</span> <span style="color: #339933;">=&gt;</span> <span style="color: #000088;">$snapshots</span><span style="color: #009900;">&#41;</span><br />
<span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #000088;">$total</span> <span style="color: #339933;">=</span> <span style="color: #cc66cc;">0</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">foreach</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$snapshots</span> <span style="color: #b1b100;">as</span> <span style="color: #000088;">$timestamp</span> <span style="color: #339933;">=&gt;</span> <span style="color: #000088;">$details</span><span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$total</span> <span style="color: #339933;">&gt;</span> <span style="color: #000088;">$details</span><span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">12</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">-</span> <span style="color: #cc66cc;">1</span><span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">echo</span> <span style="color: #0000ff;">'Deleting Snapshot: '</span><span style="color: #339933;">.</span><span style="color: #000088;">$details</span><span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">1</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">.</span><span style="color: #0000ff;">&quot;<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000088;">$out</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000088;">$cmd</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">'ec2-delete-snapshot -K '</span><span style="color: #339933;">.</span><span style="color: #000088;">$details</span><span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">9</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">.</span><span style="color: #0000ff;">' -C '</span><span style="color: #339933;">.</span><span style="color: #000088;">$details</span><span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">10</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">.</span><span style="color: #0000ff;">' --region '</span><span style="color: #339933;">.</span><span style="color: #000088;">$details</span><span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">11</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">.</span><span style="color: #0000ff;">' '</span><span style="color: #339933;">.</span><span style="color: #000088;">$details</span><span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">1</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #990000;">exec</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$cmd</span><span style="color: #339933;">,</span> <span style="color: #000088;">$out</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">count</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$out</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">==</span> <span style="color: #cc66cc;">1</span> AND <span style="color: #990000;">strcmp</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$out</span><span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">0</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'SNAPSHOT &nbsp; '</span><span style="color: #339933;">.</span><span style="color: #000088;">$details</span><span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">1</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">==</span> <span style="color: #cc66cc;">0</span><span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">echo</span> <span style="color: #0000ff;">&quot;COMPLETE!<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">else</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">echo</span> <span style="color: #0000ff;">&quot;ERROR:<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">foreach</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$out</span> <span style="color: #b1b100;">as</span> <span style="color: #000088;">$line</span><span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">echo</span> <span style="color: #000088;">$line</span><span style="color: #339933;">.</span><span style="color: #0000ff;">&quot;<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000088;">$total</span><span style="color: #339933;">++;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
<span style="color: #009900;">&#125;</span></div></div>

<p>We need to trigger this as a <acronym title="Command Line Interface">CLI</acronym > process so we will wrap its call in a bash wrapper just like the other scripts.</p>

<pre class="command">
sudo ##editor## /home/ubuntu/snapshotting/remove-old.sh 
</pre>

<pre class="file">
#!/bin/bash -l

php /var/www/remove_old_snapshots.php -v $VOLUME_ID_WEBSERVER -v $VOLUME_ID_EMAIL -v $VOLUME_ID_DATABASE -n 7 -r $EC2_REGION -K $EC2_PRIVATE_KEY -C $EC2_CERT
</pre>

<p>The -n value is the number of snapshots of each volume to keep. If you would like to keep different numbers for each specify -n 3 times (one for each). Again this needs to be executable and our editor may have left a temporary file to clean up:</p>

<pre class="command">
sudo chmod +x /home/ubuntu/snapshotting/* 
sudo rm /home/ubuntu/snapshotting/*~ 
</pre>

<p>To remain consistent we will add our commands to root&#8217;s crontab.</p>

<pre class="command">
su root 
</pre>

<pre class="command">
crontab -e 
</pre>

<pre class="file">
[...]
3 6 * * * /home/ubuntu/snapshotting/remove-old.sh >> /home/ubuntu/backup.log 2>&#038;1
</pre>

<p>Leave the root user.</p>

<pre class="command">
exit 
</pre>

<p>Hopefully that is everything you will <em><strong>need</strong></em> to do to set up a secure server, so I wish you the best of luck with yours! All comments, criticisms and suggestions welcome, but please comment on the relevant pages to make them as useful as possible, thanks!</p>


##previous-next-page-7##

##download##

##contents##

##previous-next-page-7##]]></content:encoded>
			<wfw:commentRss>http://www.paul-norman.co.uk/2011/02/backing-up-and-clean-up/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>EC2 Guide: Software Configuration from existing EBS volumes (6b / 7)</title>
		<link>http://www.paul-norman.co.uk/2011/02/software-configuration-from-existing-ebs-volumes/</link>
		<comments>http://www.paul-norman.co.uk/2011/02/software-configuration-from-existing-ebs-volumes/#comments</comments>
		<pubDate>Mon, 28 Feb 2011 23:52:09 +0000</pubDate>
		<dc:creator>Paul Norman</dc:creator>
				<category><![CDATA[Server]]></category>
		<category><![CDATA[Amavisd-New]]></category>
		<category><![CDATA[ClamAV]]></category>
		<category><![CDATA[Cloud]]></category>
		<category><![CDATA[EBS]]></category>
		<category><![CDATA[Spamassassin]]></category>
		<category><![CDATA[Ubuntu 10.04]]></category>

		<guid isPermaLink="false">http://www.paul-norman.co.uk/?p=54</guid>
		<description><![CDATA[Continuing the upgrade path started earlier this page guides you through the steps required to configure only the software not on the EBS volumes.]]></description>
			<content:encoded><![CDATA[##previous-next-page-6b##

<p>This page is designed for the re-attachment of existing EBS volumes previously created by completing this whole guide. If you do not have these 3 EBS volumes with all data configured on them you are on the wrong page and should use the contents below!</p>

<h2>Configure ClamAV</h2>

<p>ClamAV will be our anti-virus system and is very easy to set-up! We just need to update some permissions:</p>

<pre class="command">
sudo adduser clamav amavis 
sudo adduser amavis clamav 
</pre>


<h2>Configure SpamAssassin</h2>

<p>SpamAssassin&#8217;s function is given away by it&#8217;s name. We will use this for spam filtering our e-mails.</p>

<pre class="command">
sudo ##editor## /etc/default/spamassassin 
</pre>

<pre class="file">
[...]
ENABLED=1
[...]
CRON=1
[...]
</pre>

<p>We need to create a razor config file for it to work:</p>

<pre class="command">
sudo razor-admin -create 
</pre>

<p>Start the service:</p>

<pre class="command">
sudo service spamassassin start 
</pre>


<h2>Configure Amavisd-New</h2>

<p>Amavisd-New will be our interface between our mail transport program (Postfix) and our spam and virus filters (SpamAssassin / ClamAV).</p>

<pre class="command">
sudo ##editor## /etc/amavis/conf.d/15-content_filter_mode 
</pre>

<p>Uncomment the spam and anti-virus lines.</p>

<pre class="file">
use strict;

# You can modify this file to re-enable SPAM checking through spamassassin
# and to re-enable antivirus checking.

#
# Default antivirus checking mode
# Uncomment the two lines below to enable it
#

@bypass_virus_checks_maps = (
   \%bypass_virus_checks, \@bypass_virus_checks_acl, \$bypass_virus_checks_re);

#
# Default SPAM checking mode
# Uncomment the two lines below to enable it
#

@bypass_spam_checks_maps = (
   \%bypass_spam_checks, \@bypass_spam_checks_acl, \$bypass_spam_checks_re);

1;  # insure a defined return
</pre>

<p>Some fairly key definitions are missing because they are not &#8220;free&#8221; &#8211; thanks Ubuntu. Enable / uncomment them!</p>

<pre class="command">
sudo ##editor## /etc/amavis/conf.d/01-debian 
</pre>

<pre class="file">
[...]
$unfreeze   = ['unfreeze', 'freeze -d', 'melt', 'fcat'];
[...]
$lha    = 'lha';
[...]
</pre>

<p>Amavis needs permissions here:</p>

<pre class="command">
sudo chmod -R 775 /var/lib/amavis/tmp 
</pre>

<pre class="command">
sudo service amavis restart 
</pre>


<h2>Configure Mail Logging</h2>

<p>Because we mounted parts of our file system through EBS volumes we need to update the mail log locations.</p>

<pre class="command">
sudo ##editor## /etc/rsyslog.d/50-default.conf 
</pre>

<pre class="file">
[...]
mail.*                          -/var/log/postfix/mail.log
[...]
mail.info                       -/var/log/postfix/mail.info
mail.warn                       -/var/log/postfix/mail.warn
mail.err                        /var/log/postfix/mail.err
[..]
</pre>

<pre class="command">
sudo service rsyslog restart 
</pre>


<h2>Restart Postfix / Dovecot</h2>

<p>Make sure that Amavisd-New is plugged in correctly:</p>

<pre class="command">
sudo service postfix restart 
sudo service dovecot restart 
</pre>


##previous-next-page-6b##

##download##

##contents##

##previous-next-page-6b##]]></content:encoded>
			<wfw:commentRss>http://www.paul-norman.co.uk/2011/02/software-configuration-from-existing-ebs-volumes/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>EC2 Guide: Software Configuration (6a / 7)</title>
		<link>http://www.paul-norman.co.uk/2011/02/software-configuration/</link>
		<comments>http://www.paul-norman.co.uk/2011/02/software-configuration/#comments</comments>
		<pubDate>Mon, 28 Feb 2011 23:51:08 +0000</pubDate>
		<dc:creator>Paul Norman</dc:creator>
				<category><![CDATA[Server]]></category>
		<category><![CDATA[Amavisd-New]]></category>
		<category><![CDATA[Apache]]></category>
		<category><![CDATA[ClamAV]]></category>
		<category><![CDATA[Dovecot]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Postfix]]></category>
		<category><![CDATA[Ubuntu 10.04]]></category>

		<guid isPermaLink="false">http://www.paul-norman.co.uk/?p=53</guid>
		<description><![CDATA[With most of the EBS volume work out of the way we can now configure the server to production standard. This means taming ClamAV, Amavisd-New, Spamassassin, Apache, PHP, MySQL, Dovecot, Postfix and Generating SSL certificates. This is likely the most important page in the guide!]]></description>
			<content:encoded><![CDATA[##previous-next-page-6##

<h2>Configure ClamAV</h2>

<p>ClamAV will be our anti-virus system and is very easy to set-up! We just need to update some permissions:</p>

<pre class="command">
sudo adduser clamav amavis 
sudo adduser amavis clamav 
</pre>


<h2>Configure SpamAssassin</h2>

<p>SpamAssassin&#8217;s function is given away by it&#8217;s name. We will use this for spam filtering our e-mails.</p>

<pre class="command">
sudo ##editor## /etc/default/spamassassin 
</pre>

<pre class="file">
[...]
ENABLED=1
[...]
CRON=1
[...]
</pre>

<p>We need to create a razor config file for it to work:</p>

<pre class="command">
sudo razor-admin -create 
</pre>

<p>Start the service:</p>

<pre class="command">
sudo service spamassassin start 
</pre>


<h2>Configure Amavisd-New</h2>

<p>Amavisd-New will be our interface between our mail transport program (Postfix) and our spam and virus filters (SpamAssassin / ClamAV).</p>

<pre class="command">
sudo ##editor## /etc/amavis/conf.d/15-content_filter_mode 
</pre>

<p>Uncomment the spam and anti-virus lines.</p>

<pre class="file">
use strict;

# You can modify this file to re-enable SPAM checking through spamassassin
# and to re-enable antivirus checking.

#
# Default antivirus checking mode
# Uncomment the two lines below to enable it
#

@bypass_virus_checks_maps = (
   \%bypass_virus_checks, \@bypass_virus_checks_acl, \$bypass_virus_checks_re);

#
# Default SPAM checking mode
# Uncomment the two lines below to enable it
#

@bypass_spam_checks_maps = (
   \%bypass_spam_checks, \@bypass_spam_checks_acl, \$bypass_spam_checks_re);

1;  # insure a defined return
</pre>

<p>Some fairly key definitions are missing because they are not &#8220;free&#8221; &#8211; thanks Ubuntu. Enable / uncomment them!</p>

<pre class="command">
sudo ##editor## /etc/amavis/conf.d/01-debian 
</pre>

<pre class="file">
[...]
$unfreeze   = ['unfreeze', 'freeze -d', 'melt', 'fcat'];
[...]
$lha    = 'lha';
[...]
</pre>

<p>Amavis needs permissions here:</p>

<pre class="command">
sudo chmod -R 775 /var/lib/amavis/tmp 
</pre>

<pre class="command">
sudo service amavis restart 
</pre>


<h2>Configure Mail Logging</h2>

<p>Because we mounted parts of our file system through EBS volumes we need to update the mail log locations.</p>

<pre class="command">
sudo ##editor## /etc/rsyslog.d/50-default.conf 
</pre>

<pre class="file">
[...]
mail.*                          -/var/log/postfix/mail.log
[...]
mail.info                       -/var/log/postfix/mail.info
mail.warn                       -/var/log/postfix/mail.warn
mail.err                        /var/log/postfix/mail.err
[..]
</pre>

<pre class="command">
sudo service rsyslog restart 
</pre>


<h2>Configure MySQL</h2>

<p>MySQL set-up largely depends upon your use case and virtual hardware configuration. Shown here is an example, working config.</p>

<pre class="command">
sudo ##editor## /etc/mysql/my.cnf 
</pre>

<pre class="file">
[client]
port                  = 3306
socket                = /var/run/mysqld/mysqld.sock
default-character-set = utf8

[mysqld_safe]
socket                = /var/run/mysqld/mysqld.sock
nice                  = 0

[mysqld]
user                  = mysql
socket                = /var/run/mysqld/mysqld.sock
port                  = 3306
basedir               = /usr
datadir               = /var/lib/mysql
tmpdir                = /tmp

skip-external-locking
default-character-set = utf8
collation_server      = utf8_general_ci
character_set_server  = utf8
bind-address          = 127.0.0.1

key_buffer            = 512M
max_allowed_packet    = 16M
thread_stack          = 192K
thread_cache_size     = 8
myisam-recover        = BACKUP
max_connections       = 200
table_cache           = 1024
thread_concurrency    = 10

query-cache-type      = 1 
query_cache_limit     = 8M
query_cache_size      = 128M

log_error             = /var/log/mysql/error.log

server-id             = 1
expire_logs_days      = 10
max_binlog_size       = 100M

[mysqldump]
quick
quote-names
max_allowed_packet    = 16M

[mysql]
no-auto-rehash
default-character-set = utf8

[isamchk]
key_buffer            = 64M
sort_buffer           = 64M
read_buffer           = 16M
write_buffer          = 16M

[myisamchk]
key_buffer            = 64M
sort_buffer           = 64M
read_buffer           = 16M
write_buffer          = 16M

!includedir /etc/mysql/conf.d/
</pre>

<p>If you require MySQL to be available from other locations you will need to comment out the &#8220;bind-address = 127.0.0.1&#8243; line.</p>

<pre class="command">
sudo service mysql restart 
</pre>


<h2>Configure PHP</h2>

<p>The default installation of PHP on Ubuntu 10.04 is good. There isn&#8217;t much wrong with it, but there are always changes that need making. Most notably is the session clean up (which should be exclusively by cron jobs due to potential security risks of giving the web user access) and the configuration of either iconv or mb_string. There are 3 php.ini files, one for Apache (which is the only one I will show here), one for <acronym title="Command Line Interface">CLI</acronym> and one for <acronym title="Common Gateway Interface">CGI</acronym>. You should probably make pretty similar changes to all of them.</p>

<pre class="command">
sudo ##editor## /etc/php5/apache2/php.ini 
</pre>

<pre class="file">
engine					= On
short_open_tag				= Off
asp_tags				= Off
precision				= 14
y2k_compliance				= On
output_buffering			= 4096
zlib.output_compression			= Off
implicit_flush				= Off
unserialize_callback_func		=
serialize_precision			= 100
allow_call_time_pass_reference		= Off

safe_mode				= Off
safe_mode_gid				= Off
safe_mode_include_dir			=
safe_mode_exec_dir			=
safe_mode_allowed_env_vars		= PHP_
safe_mode_protected_env_vars		= LD_LIBRARY_PATH

disable_functions			=
disable_classes				=
expose_php				= On
max_execution_time			= 330
max_input_time				= 360
memory_limit				= 128M
error_reporting				= E_ALL &#038; ~E_DEPRECATED
display_errors				= Off
display_startup_errors			= Off
log_errors				= On
log_errors_max_len			= 1024
ignore_repeated_errors			= Off
ignore_repeated_source			= Off
report_memleaks				= On
track_errors				= Off
html_errors				= Off
variables_order				= "GPCS"
request_order				= "GP"
register_globals			= Off
register_long_arrays			= Off
register_argc_argv			= Off
auto_globals_jit			= On
post_max_size				= 18M
magic_quotes_gpc			= Off
magic_quotes_runtime			= Off
magic_quotes_sybase			= Off
auto_prepend_file			=
auto_append_file			=
default_mimetype			= "text/html"
default_charset				= UTF-8
doc_root				=
user_dir				=
enable_dl				= Off
file_uploads				= On
upload_max_filesize			= 12M
max_file_uploads			= 20
allow_url_fopen				= On
allow_url_include			= Off
default_socket_timeout			= 60

pdo_mysql.cache_size			= 2000
pdo_mysql.default_socket		=

define_syslog_variables			= Off

SMTP					= localhost
smtp_port				= 25
mail.add_x_header			= On

sql.safe_mode				= Off

odbc.allow_persistent			= On
odbc.check_persistent			= On
odbc.max_persistent			= -1
odbc.max_links				= -1
odbc.defaultlrl				= 4096
odbc.defaultbinmode			= 1

ibase.allow_persistent			= 1
ibase.max_persistent			= -1
ibase.max_links				= -1
ibase.timestampformat			= "%Y-%m-%d %H:%M:%S"
ibase.dateformat			= "%Y-%m-%d"
ibase.timeformat			= "%H:%M:%S"

mysql.allow_local_infile		= On
mysql.allow_persistent			= On
mysql.cache_size			= 2000
mysql.max_persistent			= -1

mysql.max_links				= -1
mysql.default_port			=
mysql.default_socket			=
mysql.default_host			=
mysql.default_user			=
mysql.default_password			=
mysql.connect_timeout			= 60
mysql.trace_mode			= Off

mysqli.max_persistent			= -1
mysqli.allow_persistent			= On
mysqli.max_links			= -1
mysqli.cache_size			= 2000
mysqli.default_port			= 3306
mysqli.default_socket			=
mysqli.default_host			=
mysqli.default_user			=
mysqli.default_pw			=
mysqli.reconnect			= Off

mysqlnd.collect_statistics		= On
mysqlnd.collect_memory_statistics	= Off

pgsql.allow_persistent			= On
pgsql.auto_reset_persistent		= Off
pgsql.max_persistent			= -1
pgsql.max_links				= -1
pgsql.ignore_notice			= 0
pgsql.log_notice			= 0

sybct.allow_persistent			= On
sybct.max_persistent			= -1
sybct.max_links				= -1
sybct.min_server_severity		= 10
sybct.min_client_severity		= 10

bcmath.scale				= 0

session.save_handler			= files
session.use_cookies			= 1
session.use_only_cookies		= 1
session.name				= PHPSESSID
session.auto_start			= 0
session.cookie_lifetime			= 0
session.cookie_path			= /
session.cookie_domain			=
session.cookie_httponly			=
session.serialize_handler		= php
session.gc_probability			= 0
session.gc_divisor			= 1000
session.gc_maxlifetime			= 2700
session.bug_compat_42			= Off
session.bug_compat_warn			= Off
session.referer_check			=
session.entropy_length			= 0
session.entropy_file			=
session.cache_limiter			= nocache
session.cache_expire			= 180
session.use_trans_sid			= 0
session.hash_function			= 1
session.hash_bits_per_character		= 5

url_rewriter.tags			= "a=href,area=href,frame=src,input=src,form=fakeentry"

mssql.allow_persistent			= On
mssql.max_persistent			= -1
mssql.max_links				= -1
mssql.min_error_severity		= 10
mssql.min_message_severity		= 10
mssql.secure_connection			= Off

mbstring.language			= Neutral
mbstring.internal_encoding		= UTF-8
mbstring.http_input			= auto
mbstring.http_output			= UTF-8
mbstring.encoding_translation		= On
mbstring.detect_order			= auto
mbstring.substitute_character		= none;
mbstring.func_overload			= 0

tidy.clean_output			= Off

soap.wsdl_cache_enabled			= 1
soap.wsdl_cache_dir			= "/tmp"
soap.wsdl_cache_ttl			= 86400
soap.wsdl_cache_limit			= 5

ldap.max_links				= -1
</pre>

<pre class="command">
sudo service apache2 graceful  
</pre>


<h2>Configure Apache and a test site</h2>

<p>Apache / PHP configuration again largely depends upon your use case. The following will set up a working system and configure a site at &#8220;http://www.##domain##&#8221; for you.</p>

<p>Create some directories for vhosts and sites first:</p>

<pre class="command">
sudo mkdir /etc/apache2/vhosts/db-maintenance/ /etc/apache2/vhosts/catch-all/ /etc/apache2/vhosts/redirects/ /var/www/default /var/www/www.##domain## /var/www/db-maintenance.##domain## 
</pre>

<p>Technically you are not supposed to edit the main apache2.conf file file, but I found some parts of it not to my liking.</p>

<pre class="command">
sudo ##editor## /etc/apache2/apache2.conf 
</pre>

<pre class="file">
ServerRoot "/etc/apache2"
LockFile /var/lock/apache2/accept.lock
PidFile ${APACHE_PID_FILE}
Timeout 300
KeepAlive Off
MaxKeepAliveRequests 100
KeepAliveTimeout 15

&lt;IfModule mpm_prefork_module&gt;
    StartServers          8
    MinSpareServers       5
    MaxSpareServers      20
    MaxClients          256
    MaxRequestsPerChild 4000
&lt;/IfModule&gt;

&lt;IfModule mpm_worker_module&gt;
    StartServers          2
    MinSpareThreads      25
    MaxSpareThreads      75
    ThreadLimit          64
    ThreadsPerChild      25
    MaxClients          150
    MaxRequestsPerChild   0
&lt;/IfModule&gt;

&lt;IfModule mpm_event_module&gt;
    StartServers          2
    MaxClients          150
    MinSpareThreads      25
    MaxSpareThreads      75
    ThreadLimit          64
    ThreadsPerChild      25
    MaxRequestsPerChild   0
&lt;/IfModule&gt;

User ${APACHE_RUN_USER}
Group ${APACHE_RUN_GROUP}

AccessFileName .htaccess
&lt;Files ~ "^\.ht"&gt;
    Order allow,deny
    Deny from all
    Satisfy all
&lt;/Files&gt;

DefaultType text/plain
HostnameLookups Off
ErrorLog /var/log/apache2/error.log
LogLevel warn

Include /etc/apache2/mods-enabled/*.load
Include /etc/apache2/mods-enabled/*.conf
Include /etc/apache2/httpd.conf
Include /etc/apache2/ports.conf

LogFormat "%v:%p %h %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\"" vhost_combined
LogFormat "%h %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\"" combined
LogFormat "%h %l %u %t \"%r\" %>s %O" common
LogFormat "%{Referer}i -> %U" referer
LogFormat "%{User-agent}i" agent
CustomLog /var/log/apache2/access.log vhost_combined

Include /etc/apache2/conf.d/

#Include /etc/apache2/vhosts/db-maintenance/*.conf
Include /etc/apache2/vhosts/*.conf
Include /etc/apache2/vhosts/redirects/*.conf
Include /etc/apache2/vhosts/catch-all/*.conf
</pre>

<p>This is the user editable file which we will use to set a couple of options and define a default directory.</p>

<pre class="command">
sudo ##editor## /etc/apache2/httpd.conf 
</pre>

<pre class="file">
DocumentRoot "/var/www/default"

&lt;Directory /&gt;
    Options FollowSymLinks
    AllowOverride None
&lt;/Directory&gt;

&lt;Directory "/var/www/default"&gt;
            Options Includes FollowSymLinks MultiViews -Indexes
            AllowOverride AuthConfig
            Order allow,deny
            Allow from all
&lt;/Directory&gt;

DirectoryIndex index.php index.html index.htm
AddDefaultCharset UTF-8
</pre>

<p>Next we will create some default site pages so you can check everything is working. The main (www) site first:</p>

<pre class="command">
sudo ##editor## /var/www/www.##domain##/index.php 
</pre>

<pre class="file">
&lt;?php phpinfo();
</pre>

<p>Then the database maintenance site:</p>

<pre class="command">
sudo ##editor## /var/www/db-maintenance.##domain##/index.php
</pre>

<pre class="file">
&lt;?php 
echo 'Sorry, this site is currently undergoing scheduled maintenance. 
Please check back soon!';
</pre>

<p>And a default page to catch incorrect sub-domains:</p>

<pre class="command">
sudo ##editor## /var/www/default/index.php
</pre>

<pre class="file">
&lt;?php 
echo 'We think that you may have mis-typed! 
Were you looking for: &lt;a href="http://www.##domain##"&gt;www.##domain##&lt;/a&gt;?';
</pre>

<p>The premise of these files will be that if you visit &#8220;http://www.##domain##&#8221; you will receive a PHP info screen, but if you visit a none-existent sub-domain (e.g. &#8220;http://totally-random.##domain##&#8221;) you will end up at the default location (assuming you have set your DNS to a catch all, *, setting in your zone files). If you were to enable the db-maintenance vhosts in the apache2.conf file the idea will be your users will go there instead of your main site. None of this will work yet because we have not set up any vhost files.</p>

<p>The first vhost will be the default (catch-all):</p>

<pre class="command">
sudo ##editor## /etc/apache2/vhosts/default.conf  
</pre>

<pre class="file">
&lt;VirtualHost *:80>
        DocumentRoot /var/www/default/
        ServerName localhost
        &lt;Directory "/var/www/default/"&gt;
                Options -Indexes
                AllowOverride AuthConfig
                Order allow,deny
                Allow from all
        &lt;/Directory&gt;
&lt;/VirtualHost&gt;
</pre>

<p>The only key points to note are the choice of document root (you may want the trailing slash, you may not), the exclusion of indexing (i.e. you don&#8217;t want anyone able to view all folder contents) and the ability to over-ride the settings using an .htaccess file should you wish to (I prefer to make those changes at this level). The next vhost will be the main site:</p>

<pre class="command">
sudo ##editor## /etc/apache2/vhosts/www.##domain##.conf  
</pre>

<pre class="file">
&lt;VirtualHost *:80&gt;
        ServerAdmin webmaster@##domain##
        DocumentRoot /var/www/www.##domain##
        ServerName www.##domain##
        &lt;Directory "/var/www/www.##domain##/"&gt;
                Options -Indexes FollowSymLinks
                AllowOverride AuthConfig
                Order allow,deny
                Allow from all
        &lt;/Directory&gt;
&lt;/VirtualHost&gt;  
</pre>

<p>Hopefully everything should be fairly obvious and you will note we have used a unique &#8220;ServerName&#8221; value. Lastly we need the database maintenance vhost:</p>

<pre class="command">
sudo ##editor## /etc/apache2/vhosts/db-maintenance/www.##domain##.conf  
</pre>

<pre class="file">
&lt;VirtualHost *:80&gt;
        ServerAdmin webmaster@##domain##
        DocumentRoot /var/www/db-maintenance.##domain##
        ServerName www.##domain##
        &lt;Directory "/var/www/db-maintenance.##domain##/"&gt;
                Options -Indexes FollowSymLinks
                AllowOverride AuthConfig
                Order allow,deny
                Allow from all
        &lt;/Directory&gt;
        &lt;IfModule mod_rewrite.c&gt;
                RewriteEngine On
                RewriteCond %{REQUEST_FILENAME} !-d
                RewriteCond %{REQUEST_FILENAME} !-f
                RewriteRule ^(.*)$ /index.php [L,QSA]
        &lt;/IfModule&gt;
&lt;/VirtualHost&gt;  
</pre>

<p>This time we have also included some re-write rules which mean that every address a user tries when maintenance is being carried out (e.g. http://www.##domain##/one-of-your-pages.php) will be handled by just one file, index.php, so you only need to create a single maintenance file. This technique is commonly used in <acronym title="Model View Controller">MVC</acronym> patterns.</p>

<p>Apache needs a restart / reload before these changes are applied:</p>

<pre class="command">
sudo service apache2 graceful 
</pre>

<p>Now if you test your site using &#8220;http://www.##domain##&#8221; you should receive a PHP info screen, but if you visit a none-existent sub-domain (e.g. &#8220;http://totally-random.##domain##) you should receive the default message. If you enable database maintenance (by un-commenting the relevant line in the apache2.conf and restarting Apache) and visit your site using &#8220;http://www.##domain##/anything.php&#8221; you should see the maintenance message. If at this point you don&#8217;t see these pages you should check your zone settings with your domain registrar or DNS manager.</p>

<p>Obviously it would be better that all incorrectly typed (non-existing) domains were forwarded on to an actual domain of your choosing. This isn&#8217;t hard to achieve with a catch-all vhost:</p>

<pre class="command">
sudo ##editor## /etc/apache2/vhosts/catch-all/##domain##.conf  
</pre>

<pre class="file">
&lt;VirtualHost *:80&gt;
        ServerAdmin webmaster@##domain##
        ServerName unknown.##domain##
        ServerAlias *.##domain##
        KeepAlive Off
        RewriteEngine On
        RewriteRule ^/(.*)$ http://www.##domain##/$1 [R=301,L]
&lt;/VirtualHost&gt;
</pre>

<p>This time we are using a &#8220;ServerAlias&#8221; in addition to an arbitrary &#8220;ServerName&#8221; with a re-write rule to forward everything (including a page name and GET data) to the correct location on the actual site.</p>

<p>It would also be better if the domain without a sub-domain (i.e. http://##domain##) redirected to your main site. Again this isn&#8217;t hard to achieve with another vhost:</p>

<pre class="command">
sudo ##editor## /etc/apache2/vhosts/redirects/##domain##.conf  
</pre>

<pre class="file">
&lt;VirtualHost *:80&gt;
        ServerAdmin webmaster@##domain##
        ServerName ##domain##
        KeepAlive Off
        RewriteEngine On
        RewriteRule ^/(.*)$ http://www.##domain##/$1 [R=301,L]
&lt;/VirtualHost&gt;
</pre>

<p>Nothing new in this one, just another re-write rule. Once again we need to reload our Apche settings:</p>

<pre class="command">
sudo service apache2 graceful 
</pre>

<p>Now if you test your site using a none-existent sub-domain (e.g. &#8220;http://totally-random.##domain##) or the raw domain &#8220;http://##domain##&#8221; you should be 301 redirected to &#8220;http://www.##domain##.&#8221;</p>


<h2>Install PhpMyAdmin (optional)</h2>

<p>While we are configuring sites it is a good idea to install this very convenient tool to manage MySQL databases. It will need its own vhost:</p>

<pre class="command">
sudo ##editor## /etc/apache2/vhosts/database.##domain##.conf 
</pre>

<pre class="file">
&lt;VirtualHost *:80&gt;
        ServerAdmin webmaster@##domain##
        DocumentRoot /var/www/database.##domain##
        ServerName database.##domain##
        &lt;Directory "/var/www/database.##domain##/"&gt;
                Options -Indexes FollowSymLinks
                AllowOverride AuthConfig
                Order allow,deny
                Allow from all
        &lt;/Directory&gt;
&lt;/VirtualHost&gt;
</pre>

<p>Get the actual program, extract it and edit its settings. You will probably need to customise this link I&#8217;m afraid because it changes often!</p>

<pre class="command">
cd /var/www 
sudo wget "http://sourceforge.net/projects/phpmyadmin/files/phpMyAdmin/##php_my_admin_version##/phpMyAdmin-##php_my_admin_version##-english.tar.gz/download" -O /var/www/phpmyadmin.tar.gz 
sudo tar xvfz /var/www/phpmyadmin.tar.gz 
sudo rm /var/www/phpmyadmin.tar.gz 
sudo mv /var/www/phpMyAdmin-##php_my_admin_version##-english /var/www/database.##domain## 
sudo mv /var/www/database.##domain##/config.sample.inc.php /var/www/database.##domain##/config.inc.php 
sudo ##editor## /var/www/database.##domain##/config.inc.php 
</pre>

<pre class="file">
[...]
$cfg['blowfish_secret'] = '<span style="color: red;">choose a suitably random string here</span>';
[...]
$cfg['Servers'][$i]['extension'] = 'mysqli';
[...]
</pre>

<p>Clean up any temporary files left by our editor:</p>

<pre class="command">
sudo rm /var/www/database.##domain##/config.inc.php~ 
</pre>

<p>It&#8217;s also a good idea to password this directory so we&#8217;ll create a general password file for use with our restricted sites:</p>

<pre class="command">
sudo htpasswd -c /var/www/.htpasswd <span style="color: red;">user</span> 
</pre>

<p>And if you want to add another user:</p>

<pre class="command">
sudo htpasswd /var/www/.htpasswd <span style="color: red;">another_user</span> 
</pre>

<p>Now we need to tell the phpMyAdmin directory to use this extra authentication:</p>

<pre class="command">
sudo ##editor## /var/www/database.##domain##/.htaccess 
</pre>

<pre class="file">
AuthUserFile /var/www/.htpasswd
AuthName "Database Management"
AuthType Basic
require valid-user
</pre>

<p>Restart Apache to check that everything is working:</p>

<pre class="command">
sudo service apache2 graceful 
</pre>

<p>If you visit &#8220;http://database.##domain##&#8221; you should be able to log in and then use your MySQL username (root) and password (##root_db_password##) to manage your MySQL databases.</p>


<h2>Install PostfixAdmin</h2>

<p>This is the tool that we will use to manage our e-mail domains / users and it <strong>must be installed at this stage</strong> because it dictates the structure of the database that Postfix and Dovecot will use for e-mail delivery.</p>

<p>We need to create a MySQL database and user for this. This can either be done through phpMyAdmin or via the MySQL command prompt, either way the 4 commands are the same.</p>

<pre class="command">
mysql -uroot -p##root_db_password##
</pre>

<pre class="command">
CREATE USER '##vmail_db_user##'@'%' IDENTIFIED BY '##vmail_db_password##'; 
GRANT USAGE ON * . * TO '##vmail_db_user##'@'%' IDENTIFIED BY '##vmail_db_password##' WITH MAX_QUERIES_PER_HOUR 0 MAX_CONNECTIONS_PER_HOUR 0 MAX_UPDATES_PER_HOUR 0 MAX_USER_CONNECTIONS 0; 
CREATE DATABASE IF NOT EXISTS `##vmail_db##` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci; 
GRANT ALL PRIVILEGES ON `##vmail_db##` . * TO '##vmail_db_user##'@'%'; 
</pre>

<pre class="command">
exit;
</pre>

<p>This new site needs a vhost too:</p>

<pre class="command">
sudo ##editor## /etc/apache2/vhosts/mailadmin.##domain##.conf 
</pre>

<pre class="file">
&lt;VirtualHost *:80&gt;
        ServerAdmin webmaster@##domain##
        DocumentRoot /var/www/mailadmin.##domain##
        ServerName mailadmin.##domain##
        &lt;Directory "/var/www/mailadmin.##domain##/"&gt;
                Options -Indexes FollowSymLinks
                AllowOverride AuthConfig
                Order allow,deny
                Allow from all
        &lt;/Directory&gt;
&lt;/VirtualHost&gt;
</pre>

<p>Get the actual program, extract it and edit its settings. You may need to customise this link I&#8217;m afraid because it changes occasionally!</p>

<pre class="command">
cd /var/www 
sudo wget "http://sourceforge.net/projects/postfixadmin/files/postfixadmin/postfixadmin-##postfix_admin_version##/postfixadmin-##postfix_admin_version##.tar.gz/download" -O /var/www/postfixadmin.tar.gz 
sudo tar xvfz /var/www/postfixadmin.tar.gz 
sudo rm /var/www/postfixadmin.tar.gz 
sudo mv /var/www/postfixadmin-##postfix_admin_version## /var/www/mailadmin.##domain## 
sudo ##editor## /var/www/mailadmin.##domain##/config.inc.php 
</pre>

<pre class="file">
[...]
$CONF['configured'] = true;
[...]
$CONF['database_type'] = 'mysqli';
$CONF['database_host'] = 'localhost';
$CONF['database_user'] = '##vmail_db_user##';
$CONF['database_password'] = '##vmail_db_password##';
$CONF['database_name'] = '##vmail_db##';
$CONF['database_prefix'] = '';
[...]
$CONF['admin_email'] = 'postmaster@##domain##';
[...]
$CONF['default_aliases'] = array (
    'abuse' => 'abuse@##domain##',
    'hostmaster' => 'hostmaster@##domain##',
    'postmaster' => 'postmaster@##domain##',
    'webmaster' => 'webmaster@##domain##'
);
[...]
</pre>

<p>Now we need to tell the PostfixAdmin directory to use our general .htpasswd file:</p>

<pre class="command">
sudo ##editor## /var/www/mailadmin.##domain##/.htaccess 
</pre>

<pre class="file">
AuthUserFile /var/www/.htpasswd
AuthName "E-mail Management"
AuthType Basic
require valid-user
</pre>

<p>Restart Apache to apply the changes:</p>

<pre class="command">
sudo service apache2 graceful 
</pre>

<p>You now need to visit &#8220;http://mailadmin.##domain##/setup.php&#8221; to install the database tables, then enter a password to generate a hash. Please copy this value, but do not proceed with any further prompts. Instead return to the terminal window:</p>

<pre class="command">
sudo ##editor## /var/www/mailadmin.##domain##/config.inc.php 
</pre>

<pre class="file">
[...]
$CONF['setup_password'] = '<span style="color: red;">the password hash</span>';
[...]
</pre>

<p>Clean up any temporary files left by our editor:</p>

<pre class="command">
sudo rm /var/www/database.##domain##/config.inc.php~ 
</pre>

<p>Now return to &#8220;http://mailadmin.##domain##/setup.php&#8221;, but don&#8217;t refresh, and configure a system admin user using the <strong>un-hashed</strong> set-up password and whatever details you wish for the account. Then visit &#8220;http://mailadmin.##domain##/&#8221; and login as your admin user.</p>

<p>Visit the domain list, add ##domain## as a new domain and create any e-mail addresses that you want here (e.g. info@##domain##, your_name@##domain## etc). You should also create the four default accounts (webmaster@##domain##, postmaster@##domain##, abuse@##domain## and hostmaster@##domain##) for it too. These can just be aliases to another account if you wish, but it&#8217;s a good idea to have them set up.</p>


<h2>Create SSL certificates (for Postfix / Dovecot)</h2>

<p>In order to accept secure connections we need to generate some self signed certificates for e-mail use. If you wish you can use official certificates, but that is outside the scope of this guide.</p>

<pre class="command">
cd /home/ubuntu/smtp-certificates 
sudo openssl req -new -outform PEM -out smtpd.cert -newkey rsa:2048 -nodes -keyout smtpd.key -keyform PEM -days 3650 -x509 
</pre>

<pre class="file">
Country Name (2 letter code) [AU]: <em>UK</em>
State or Province Name (full name) [Some-State]: <em>Greater London</em>
Locality Name (eg, city) []: <em>London</em>
Organization Name (eg, company) [Internet Widgits Pty Ltd]: <em>Company Name</em>
Organizational Unit Name (eg, section) []: <em>Trading Name</em>
Common Name (eg, YOUR name) []: <em>##subdomain##.##domain##</em>
Email Address []: <em>postmaster@##domain##</em>
</pre>

<p>Create a self-singed root certificate.</p>

<pre class="command">
sudo openssl req -new -x509 -extensions v3_ca -keyout cakey.pem -out cacert.pem -days 3650 
</pre>

<pre class="command">
sudo chmod 0640 /home/ubuntu/smtp-certificates/smtpd.key 
sudo chmod 0640 /home/ubuntu/smtp-certificates/cakey.pem 
</pre>

<p>For far more detail on this process please visit <a href="https://help.ubuntu.com/10.04/serverguide/C/certificates-and-security.html" title="Ubuntu's SSL certificate guide" target="_blank">Ubuntu&#8217;s own guide</a> on the subject.</p>


<h2>Configure Postfix</h2>

<p>Postfix will be our mail server, replacing the ancient Sendmail. Configuration is fairly short, but getting it right is a bit of a black art. To keep our database configuration files contained we&#8217;ll put them in a single folder that Postfix owns:</p>

<pre class="command">
sudo mkdir /etc/postfix/sql 
sudo chown postfix:postfix /etc/postfix/sql 
sudo chmod 0750 /etc/postfix/sql 
</pre>

<p>What we are essentially doing is using MySQL to determine what happens to the mail. There are 8 different possibilities for this. First up is the relay domains rule, which tells Postfix which domains are to have their mail passed on to another server.</p>

<pre class="command">
sudo ##editor## /etc/postfix/sql/relay_domains.cf 
</pre>

<pre class="file">
user		= ##vmail_db_user##
password	= ##vmail_db_password##
hosts		= localhost
dbname		= ##vmail_db##
query		= SELECT domain FROM domain WHERE domain = '%s' AND backupmx = '1'
</pre>

<p>We then define a rule for domain forwarding catch-all, e.g. anything@my-domain.com -> anything@mydomain.com:</p>

<pre class="command">
sudo ##editor## /etc/postfix/sql/virtual_alias_domain_catchall_maps.cf 
</pre>

<pre class="file">
user		= ##vmail_db_user##
password	= ##vmail_db_password##
hosts		= localhost
dbname		= ##vmail_db##
query		= SELECT goto FROM alias, alias_domain WHERE alias_domain = '%d' AND address = CONCAT('@', target_domain) AND alias.active = '1' AND alias_domain.active = '1'
</pre>

<p>We can also define a rule for account forwarding for certain addresses within a domain, e.g. userX@my-domain.com may be forwarded to userX@mydomain.com, but userY@my-domain.com may or may not be forwarded. This query selects the correct mailbox directory for that scenario:</p>

<pre class="command">
sudo ##editor## /etc/postfix/sql/virtual_alias_domain_mailbox_maps.cf 
</pre>

<pre class="file">
user		= ##vmail_db_user##
password	= ##vmail_db_password##
hosts		= localhost
dbname		= ##vmail_db##
query		= SELECT CONCAT(domain, '/', maildir) FROM mailbox, alias_domain WHERE alias_domain = '%d' AND username = CONCAT('%u', '@', alias_domain.target_domain) AND mailbox.active = '1' AND alias_domain.active = '1'
</pre>

<p>Continuing from the previous rule we also need a query to select the account that a user on an aliased domain will be sent to:</p>

<pre class="command">
sudo ##editor## /etc/postfix/sql/virtual_alias_domain_maps.cf 
</pre>

<pre class="file">
user		= ##vmail_db_user##
password	= ##vmail_db_password##
hosts		= localhost
dbname		= ##vmail_db##
query		= SELECT goto FROM alias, alias_domain WHERE alias_domain = '%d' AND address = CONCAT('%u', '@', target_domain) AND alias.active = '1' AND alias_domain.active = '1'
</pre>

<p>We can also just define simple aliases on a per address basis, e.g. userX@my-domain.com could be forwarded to anything@yahoo.com, or in fact multiple recipients. This query handles those.</p>

<pre class="command">
sudo ##editor## /etc/postfix/sql/virtual_alias_maps.cf 
</pre>

<pre class="file">
user		= ##vmail_db_user##
password	= ##vmail_db_password##
hosts		= localhost
dbname		= ##vmail_db##
query		= SELECT goto FROM alias WHERE address = '%s' AND active = '1'
</pre>

<p>We need a simple query to select the mailbox for a certain domain:</p>

<pre class="command">
sudo ##editor## /etc/postfix/sql/virtual_mailbox_domains.cf 
</pre>

<pre class="file">
user		= ##vmail_db_user##
password	= ##vmail_db_password##
hosts		= localhost
dbname		= ##vmail_db##
query		= SELECT domain FROM domain WHERE domain = '%s' AND active = '1'
</pre>

<p>If the mailboxes are defined with disk space quotas we need to be able to access them:</p>

<pre class="command">
sudo ##editor## /etc/postfix/sql/virtual_mailbox_limit_maps.cf 
</pre>

<pre class="file">
user		= ##vmail_db_user##
password	= ##vmail_db_password##
hosts		= localhost
dbname		= ##vmail_db##
query		= SELECT quota FROM mailbox WHERE username = '%s' AND active = '1'
</pre>

<p>And finally just get a mailbox location for a certain user on a domain:</p>

<pre class="command">
sudo ##editor## /etc/postfix/sql/virtual_mailbox_maps.cf 
</pre>

<pre class="file">
user		= ##vmail_db_user##
password	= ##vmail_db_password##
hosts		= localhost
dbname		= ##vmail_db##
query		= SELECT CONCAT(domain, '/', maildir) FROM mailbox WHERE username = '%s' AND active = '1'
</pre>

<p>We can then configure the two main Postfix files:</p>

<pre class="command">
sudo ##editor## /etc/postfix/main.cf 
</pre>

<pre class="file">
smtpd_banner				= $myhostname ESMTP $mail_name
biff					= no
append_dot_mydomain			= no
myhostname				= ##subdomain##.##domain##
alias_maps				= hash:/etc/aliases
alias_database				= hash:/etc/aliases
myorigin				= /etc/mailname
mydestination				= ##subdomain##.##domain##, localhost.##domain##, localhost
relayhost				=
mynetworks				= 127.0.0.0/8
mailbox_size_limit			= 0
recipient_delimiter			= +
inet_interfaces				= all
message_size_limit			= 50000000

# Virtual mail set-up
virtual_mailbox_base			= /home/##vmail_user##
virtual_uid_maps			= static:5000
virtual_gid_maps			= static:5000
virtual_transport			= dovecot
dovecot_destination_recipient_limit	= 1
virtual_create_maildirsize		= yes
virtual_mailbox_extended		= yes
relay_domains				= proxy:mysql:/etc/postfix/sql/relay_domains.cf
virtual_mailbox_domains			= proxy:mysql:/etc/postfix/sql/virtual_mailbox_domains.cf
virtual_alias_maps			= proxy:mysql:/etc/postfix/sql/virtual_alias_maps.cf,
					  proxy:mysql:/etc/postfix/sql/virtual_alias_domain_maps.cf,
					  proxy:mysql:/etc/postfix/sql/virtual_alias_domain_catchall_maps.cf
virtual_mailbox_maps			= proxy:mysql:/etc/postfix/sql/virtual_mailbox_maps.cf,
					  proxy:mysql:/etc/postfix/sql/virtual_alias_domain_mailbox_maps.cf
virtual_mailbox_limit_maps		= proxy:mysql:/etc/postfix/sql/virtual_mailbox_limit_maps.cf
virtual_mailbox_limit_override		= yes
virtual_maildir_limit_message		= Sorry, that user is over their e-mail quota. Please try again later.
virtual_overquota_bounce		= yes

# SASL Related
smtpd_sasl_type				= dovecot
smtpd_sasl_path				= private/auth
smtpd_sasl_local_domain			=
smtpd_sasl_auth_enable			= yes
smtpd_sasl_security_options		= noanonymous
broken_sasl_auth_clients		= yes
smtpd_sasl2_auth_enable			= yes
smtpd_sasl_authenticated_header		= yes
smtpd_sasl_tls_security_options		= noanonymous
#smtpd_sasl_exceptions_networks		= $mynetworks

# TLS Commands
smtpd_tls_auth_only			= no
smtp_tls_security_level			= may
smtpd_tls_security_level		= may
smtp_tls_note_starttls_offer		= yes
smtpd_tls_cert_file			= /home/ubuntu/smtp-certificates/smtpd.cert
smtpd_tls_key_file			= /home/ubuntu/smtp-certificates/smtpd.key
smtpd_tls_CAfile			= /home/ubuntu/smtp-certificates/cacert.pem
smtpd_tls_loglevel			= 1
smtpd_tls_received_header		= yes
smtpd_tls_session_cache_timeout		= 3600s
tls_random_source			= dev:/dev/urandom

# Include Spam settings
disable_vrfy_command			= yes
smtpd_delay_reject			= yes
smtpd_helo_required			= yes
smtpd_helo_restrictions			= permit_mynetworks,
					  reject_non_fqdn_hostname,
					  reject_invalid_hostname,
					  permit

smtpd_recipient_restrictions		= reject_unauth_pipelining,
					  permit_mynetworks,
					  permit_sasl_authenticated,
					  reject_unauth_destination,
					  reject_invalid_hostname,
					  reject_non_fqdn_hostname,
					  reject_non_fqdn_sender,
					  reject_non_fqdn_recipient,
					  reject_unknown_sender_domain,
					  reject_unknown_recipient_domain,
					  reject_rbl_client zen.spamhaus.org,
					  reject_rbl_client dnsbl.sorbs.net,
					  reject_rbl_client dsn.rfc-ignorant.org,
					  reject_rbl_client bl.spamcop.net,
					  permit

smtpd_error_sleep_time			= 1s
smtpd_soft_error_limit			= 10
smtpd_hard_error_limit			= 20

content_filter				= smtp-amavis:[127.0.0.1]:10024
</pre>

<pre class="command">
sudo ##editor## /etc/postfix/master.cf 
</pre>

<pre class="file">
# ==========================================================================
# service type  private unpriv  chroot  wakeup  maxproc command + args
#               (yes)   (yes)   (yes)   (never) (100)
# ==========================================================================
smtp      inet  n       -       n       -       -       smtpd
smtps     inet  n       -       -       -       -       smtpd
  -o smtpd_tls_wrappermode=yes
  -o smtpd_sasl_auth_enable=yes
  -o smtpd_client_restrictions=permit_sasl_authenticated,reject
  -o broken_sasl_auth_clients=yes
pickup    fifo  n       -       -       60      1       pickup
  -o content_filter=
  -o receive_override_options=no_header_body_checks
cleanup   unix  n       -       -       -       0       cleanup
qmgr      fifo  n       -       n       300     1       qmgr
tlsmgr    unix  -       -       n       1000?   1       tlsmgr
rewrite   unix  -       -       -       -       -       trivial-rewrite
bounce    unix  -       -       -       -       0       bounce
defer     unix  -       -       -       -       0       bounce
trace     unix  -       -       -       -       0       bounce
verify    unix  -       -       -       -       1       verify
flush     unix  n       -       -       1000?   0       flush
proxymap  unix  -       -       n       -       -       proxymap
proxywrite unix -       -       n       -       1       proxymap
smtp      unix  -       -       -       -       -       smtp
relay     unix  -       -       -       -       -       smtp
	-o smtp_fallback_relay=
showq     unix  n       -       -       -       -       showq
error     unix  -       -       -       -       -       error
retry     unix  -       -       -       -       -       error
discard   unix  -       -       -       -       -       discard
local     unix  -       n       n       -       -       local
virtual   unix  -       n       n       -       -       virtual
lmtp      unix  -       -       -       -       -       lmtp
anvil     unix  -       -       -       -       1       anvil
scache    unix  -       -       -       -       1       scache
maildrop  unix  -       n       n       -       -       pipe
  flags=DRhu user=vmail argv=/usr/bin/maildrop -d ${recipient}
uucp      unix  -       n       n       -       -       pipe
  flags=Fqhu user=uucp argv=uux -r -n -z -a$sender - $nexthop!rmail ($recipient)
ifmail    unix  -       n       n       -       -       pipe
  flags=F user=ftn argv=/usr/lib/ifmail/ifmail -r $nexthop ($recipient)
bsmtp     unix  -       n       n       -       -       pipe
  flags=Fq. user=bsmtp argv=/usr/lib/bsmtp/bsmtp -t$nexthop -f$sender $recipient
scalemail-backend unix	-	n	n	-	2	pipe
  flags=R user=scalemail argv=/usr/lib/scalemail/bin/scalemail-store ${nexthop} ${user} ${extension}
mailman   unix  -       n       n       -       -       pipe
  flags=FR user=list argv=/usr/lib/mailman/bin/postfix-to-mailman.py
  ${nexthop} ${user}
dovecot   unix  -       n       n       -       -       pipe
  flags=DRhu user=vmail:vmail argv=/usr/lib/dovecot/deliver -d ${recipient}
smtp-amavis     unix    -       -       -       -       2       smtp
        -o smtp_data_done_timeout=1200
        -o smtp_send_xforward_command=yes
        -o disable_dns_lookups=yes
        -o max_use=20
127.0.0.1:10025 inet    n       -       -       -       -       smtpd
        -o content_filter=
        -o local_recipient_maps=
        -o relay_recipient_maps=
        -o smtpd_restriction_classes=
        -o smtpd_delay_reject=no
        -o smtpd_client_restrictions=permit_mynetworks,reject
        -o smtpd_helo_restrictions=
        -o smtpd_sender_restrictions=
        -o smtpd_recipient_restrictions=permit_mynetworks,reject
        -o smtpd_data_restrictions=reject_unauth_pipelining
        -o smtpd_end_of_data_restrictions=
        -o mynetworks=127.0.0.0/8
        -o smtpd_error_sleep_time=0
        -o smtpd_soft_error_limit=1001
        -o smtpd_hard_error_limit=1000
        -o smtpd_client_connection_count_limit=0
        -o smtpd_client_connection_rate_limit=0
        -o receive_override_options=no_header_body_checks,no_unknown_recipient_checks
</pre>

<p>That is all for Postfix, but before we can use the mail system we need to tweak Dovecot.</p>


<h2>Configure Dovecot</h2>

<p>Dovecot will be our POP3(S) / IMAP(S) server and handle our SASL authentication. Again, there&#8217;s not too much to set up, but if you get a setting or two wrong, it simply won&#8217;t work properly!</p>

<p>We are using Dovecot to handle our authentication, and again we will do this from our MySQL tables to ease management:</p>

<pre class="command">
sudo ##editor## /etc/dovecot/dovecot-sql.conf 
</pre>

<pre class="file">
driver			= mysql
connect			= host=127.0.0.1 dbname=##vmail_db## user=##vmail_db_user## password=##vmail_db_password##
user_query		= SELECT concat('/home/##vmail_user##/', domain, '/', maildir) as home, concat('maildir:/home/##vmail_user##/', domain, '/', maildir) as mail, 5000 AS uid, 5000 AS gid, concat('maildir:storage=', quota) AS quota FROM mailbox WHERE username = '%u' AND active = '1'
default_pass_scheme	= MD5
password_query		= SELECT username as user, password FROM mailbox WHERE username = '%u' AND active = '1'
</pre>

<p>And then we need to configure Dovecot&#8217;s main configuration file:</p>

<pre class="command">
sudo ##editor## /etc/dovecot/dovecot.conf 
</pre>

<pre class="file">
protocols		= pop3 pop3s imap imaps
log_path		= /var/log/dovecot/log
info_log_path		= /var/log/dovecot/info
log_timestamp		= "%Y-%m-%d %H:%M:%S "
ssl			= yes
ssl_cert_file		= /home/ubuntu/smtp-certificates/smtpd.cert
ssl_key_file		= /home/ubuntu/smtp-certificates/smtpd.key
disable_plaintext_auth	= no
login_dir		= /var/run/dovecot/login
login_chroot		= yes
login_user		= dovecot
login_greeting		= Dovecot ready.
mail_location		= maildir:/home/##vmail_user##/%d/%u
mail_debug		= no

auth_executable		= /usr/lib/dovecot/dovecot-auth
auth_verbose		= no
auth_debug		= no
auth_debug_passwords	= no

protocol imap {
  login_executable	= /usr/lib/dovecot/imap-login
  mail_executable	= /usr/lib/dovecot/imap
  imap_max_line_length	= 65536
}

protocol pop3 {
  login_executable	= /usr/lib/dovecot/pop3-login
  mail_executable	= /usr/lib/dovecot/pop3
  pop3_uidl_format	= %08Xu%08Xv
}

protocol lda {
  log_path		= /var/log/dovecot/lda
  auth_socket_path	= /var/run/dovecot/auth-master
  postmaster_address	= postmaster@##domain##
}

auth default {
  mechanisms		= plain login

  passdb sql {
    args		= /etc/dovecot/dovecot-sql.conf
  }

  userdb sql {
    args		= /etc/dovecot/dovecot-sql.conf
  }

  socket listen {
    master {
      path		= /var/run/dovecot/auth-master
      mode		= 0600
      user		= ##vmail_user##
      group		= ##vmail_group##
   }

    client {
       path		= /var/spool/postfix/private/auth
       mode		= 0660
       user		= postfix
       group		= postfix
    }
  }
}
</pre>

<p>There are some files designed to be automatically included. They shouldn&#8217;t be, but just in case:</p>

<pre class="command">
sudo mv /etc/dovecot/conf.d/01-dovecot-postfix.conf 01-dovecot-postfix.conf.bak 
sudo mv /etc/dovecot/auth.d/01-dovecot-postfix.auth 01-dovecot-postfix.auth.bak 
</pre>

<p>Before we can use the mail system the new settings need to be loaded in.</p>

<pre class="command">
sudo service dovecot restart 
sudo service postfix restart 
</pre>


<h2>Configure Squirrelmail (optional)</h2>

<p>Squirrelmail is a convenient web-mail client. It will need a vhost file:</p>

<pre class="command">
sudo ##editor## /etc/apache2/vhosts/mail.##domain##.conf 
</pre>

<pre class="file">
&lt;VirtualHost *:80&gt;
        ServerAdmin webmaster@##domain##
        DocumentRoot /var/www/mail.##domain##
        ServerName mail.##domain##
        &lt;Directory "/var/www/mail.##domain##/"&gt;
                Options -Indexes FollowSymLinks
                AllowOverride AuthConfig
                Order allow,deny
                Allow from all
        &lt;/Directory&gt;
&lt;/VirtualHost&gt;
</pre>

<p>Get the actual program, extract it and edit its settings. You may need to check this link I&#8217;m afraid because it may change.</p>

<pre class="command">
cd /var/www 
sudo wget "http://sourceforge.net/projects/squirrelmail/files/stable/##squirrelmail_version##/squirrelmail-##squirrelmail_version##.tar.gz/download" -O /var/www/squirrelmail.tar.gz 
sudo tar xvfz /var/www/squirrelmail.tar.gz 
sudo rm /var/www/squirrelmail.tar.gz 
sudo mv /var/www/squirrelmail-##squirrelmail_version## /var/www/mail.##domain## 
</pre>

<p>Squirrelmail needs a private folder, so we need to create and secure it:</p>

<pre class="command">
sudo mkdir /var/www/private 
sudo mkdir /var/www/private/mail.##domain## 
sudo mkdir /var/www/private/mail.##domain##/data 
sudo mkdir /var/www/private/mail.##domain##/attachments 
sudo chown -R root:www-data /var/www/private/mail.##domain##  
sudo chmod -R 0730 /var/www/private/mail.##domain## 
</pre>

<p>We can now configure it. There is a Perl script to do this, but I find it faster just to edit the settings manually.</p>

<pre class="command">
sudo mv /var/www/mail.##domain##/config/config_default.php /var/www/mail.##domain##/config/config.php 
sudo ##editor## /var/www/mail.##domain##/config/config.php 
</pre>

<pre class="file">
[...]
$org_name = '##website_name##';
[...]
$domain = '##domain##';
[...]
$smtp_auth_mech = 'plain';
[...]
$data_dir = '/var/www/private/mail.##domain##/data/';
[...]
$attachment_dir = '/var/www/private/mail.##domain##/attachments/';
[...]
$default_charset = 'utf-8';
[...]
</pre>

<p>Clean up any temporary files left by our editor:</p>

<pre class="command">
sudo rm /var/www/mail.##domain##/config/config.php~ 
</pre>

<p>To apply the changes Apache needs to have the data reloaded:</p>

<pre class="command">
sudo service apache2 graceful 
</pre>

<p>If you visit &#8220;http://mail.##domain##&#8221; you will be able to send and receive e-mails. Of course this is no replacement for a mail client, but it&#8217;s useful to have on occasion!</p>


<h2>Configure Subversion (optional)</h2>

<p>We will bring your website (www.##domain##) under version control. This step will create the repositories and set their permissions to allow the web user access.</p>

<p>It&#8217;s unlikely that you&#8217;ll want anyone to be able to access your files so we can generate a password file for SVN access:</p>

<pre class="command">
sudo htpasswd -c /svn-repositories/passwd <span style="color: red;">svn-username</span> 
</pre>

<p>We can then create a folder, a repository within the folder and import our files:</p>

<pre class="command">
sudo mkdir /svn-repositories/www.##domain## 
sudo svnadmin create /svn-repositories/www.##domain## 
sudo svn import /var/www/www.##domain## file:////svn-repositories/www.##domain## 
</pre>

<p>This repository needs to be owned by the web user and be granted certain permissions:</p>

<pre class="command">
sudo chown -R www-data:www-data /svn-repositories/www.##domain## 
sudo chmod -R g+rws /svn-repositories/www.##domain## 
</pre>

<p>We can then remove our existing site directory and recreate it from our repository:</p>

<pre class="command">
cd /var/www 
sudo rm -rf /var/www/www.##domain##/ 
sudo svn co file:///svn-repositories/www.##domain## 
sudo chown -R www-data:www-data /var/www/www.##domain##/ 
</pre>

<p>We can also create a trigger so that every time you commit a change it goes live. This probably wants some modification for production use, i.e. Local -&gt; Staging -&gt; Production with the later step conducted manually.</p>

<pre class="command">
sudo ##editor## /svn-repositories/www.##domain##/hooks/post-commit 
</pre>

<pre class="file">
#!/bin/bash

cd /var/www/www.##domain##
/usr/bin/svn update
</pre>

<p>This also needs the correct permissions to run:</p>

<pre class="command">
sudo chown www-data:www-data /svn-repositories/www.##domain##/hooks/post-commit 
sudo chmod +x /svn-repositories/www.##domain##/hooks/post-commit 
</pre>

<p>We also need to add this repository to a vhost file so that you can check it out. I would suggest a new one for this purpose. Multiple locations can be added, but for now we just have one.</p>

<pre class="command">
sudo ##editor## /etc/apache2/vhosts/svn.##domain##.conf 
</pre>

<pre class="file">
&lt;VirtualHost *:80&gt;
        ServerAdmin webmaster@##domain##
        DocumentRoot /var/www/default/
        ServerName svn.##domain##
        &lt;Directory "/var/www/default/"&gt;
                Options -Indexes FollowSymLinks
                AllowOverride FileInfo
                Order allow,deny
                Allow from all
        &lt;/Directory&gt;
        &lt;Location /svn/www.##domain##&gt;
        	DAV svn
        	SVNPath /svn-repositories/www.##domain##
        	AuthType Basic
        	AuthName "www.##domain## subversion repository"
        	AuthUserFile /svn-repositories/passwd
        	Require valid-user
        &lt;/Location&gt;
&lt;/VirtualHost&gt;
</pre>

<p>Before this can be tested Apache needs to be reloaded:</p>

<pre class="command">
sudo service apache2 graceful 
</pre>

<p>You can now check out the repository from &#8220;http://svn.##domain##/svn/www.##domain##&#8221; using the command line or client (Linux / OSX) or a client such as Tortoise SVN on Windows. You will need to validate using the username / password that you created in this step. If you would rather use the .htpasswd file used for the database and mail admin just update the vhost file with that location.</p>

##previous-next-page-6##

##download##

##contents##

##previous-next-page-6##]]></content:encoded>
			<wfw:commentRss>http://www.paul-norman.co.uk/2011/02/software-configuration/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>EC2 Guide: No attached EBS volumes (5c / 7)</title>
		<link>http://www.paul-norman.co.uk/2011/02/no-attached-ebs-volumes/</link>
		<comments>http://www.paul-norman.co.uk/2011/02/no-attached-ebs-volumes/#comments</comments>
		<pubDate>Mon, 28 Feb 2011 23:50:12 +0000</pubDate>
		<dc:creator>Paul Norman</dc:creator>
				<category><![CDATA[Server]]></category>
		<category><![CDATA[Ubuntu 10.04]]></category>

		<guid isPermaLink="false">http://www.paul-norman.co.uk/?p=52</guid>
		<description><![CDATA[Not to disclude anyone who doesn't want to use EBS volumes, or who is following this guide in a non-cloud environment, this step allows compatability with any further parts of the guide you may wish to follow.]]></description>
			<content:encoded><![CDATA[##previous-next-page-5##

<p>We&#8217;re not going to use any further EBS volumes, but to make this guide compatible a few changes need to happen.</p>


<h2>Required Elements</h2>

<pre class="command">
sudo mkdir /home/ubuntu/smtp-certificates /var/log/dovecot /var/log/postfix /var/spool/##vmail_user## /var/##vmail_user## /svn-repositories 

sudo groupadd -g 5000 ##vmail_group## 
sudo useradd -g ##vmail_group## -u 5000 ##vmail_user##-d /home/##vmail_user## 
sudo chown ##vmail_user##:##vmail_group## /home/##vmail_user## 

sudo chown syslog:##vmail_group## /var/log/dovecot 
sudo chown syslog:##vmail_group## /var/log/postfix 
sudo chown ##vmail_user##:mail /var/spool/##vmail_user##
sudo chmod 0775 /var/spool/##vmail_user## 
</pre>

##previous-next-page-5##

##download##

##contents##

##previous-next-page-5##]]></content:encoded>
			<wfw:commentRss>http://www.paul-norman.co.uk/2011/02/no-attached-ebs-volumes/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>EC2 Guide: Attach existing EBS volumes (5b / 7)</title>
		<link>http://www.paul-norman.co.uk/2011/02/attach-existing-ebs-volumes/</link>
		<comments>http://www.paul-norman.co.uk/2011/02/attach-existing-ebs-volumes/#comments</comments>
		<pubDate>Mon, 28 Feb 2011 23:49:08 +0000</pubDate>
		<dc:creator>Paul Norman</dc:creator>
				<category><![CDATA[Server]]></category>
		<category><![CDATA[Apache]]></category>
		<category><![CDATA[Cloud]]></category>
		<category><![CDATA[Dovecot]]></category>
		<category><![CDATA[EBS]]></category>
		<category><![CDATA[EC2]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Postfix]]></category>
		<category><![CDATA[Ubuntu 10.04]]></category>

		<guid isPermaLink="false">http://www.paul-norman.co.uk/?p=51</guid>
		<description><![CDATA[To make this guide complete I have included an upgrade path should you have previously followed it and wish to re-attach your existing, configured EBS volumes to a new server instance.]]></description>
			<content:encoded><![CDATA[##previous-next-page-5b##

<p>This step assumes that you have already created all the EBS volumes following the exact steps in <a href="/2011/02/create-and-attach-new-ebs-volumes/" title="Creating and attaching EBS volumes">this guide</a>, they just need attaching to the correct points and a few folders need to be removed / re-factored.</p>


<h2>Attach the EBS Volumes</h2>

<p>We are going to use the same configuration as during initial creation. So, in Elasticfox:</p>

<ul>
	<li>Click on the &#8220;Volumes and Snapshots&#8221; tab</li>
	<li>Select each EBS volume individually and click on the green plus button to attach it to your required instance</li>
	<li>Enter a path for each <em>(the range is  sdc to sdp &#8211; sda and sdb are already in use)</em>
	<ul>
		<li>For the web-server: /dev/sd##webserver_letter##</li>
		<li>For the database: /dev/sd##database_letter## &#8211; &#8220;d&#8221; for database may be a good choice</li>
		<li>For the e-mails: /dev/sd##email_letter## &#8211; &#8220;e&#8221; for e-mails may be a good choice</li>
	</ul>
</li>
</ul>

<p>Then back on the server:</p>

<pre class="command">
sudo mkdir -m 000 /##webserver_path## 
sudo mkdir -m 000 /##database_path## 
sudo mkdir -m 000 /##email_path## 

echo "/dev/sd##webserver_letter## /##webserver_path## xfs noatime 0 0" | sudo tee -a /etc/fstab 
echo "/dev/sd##database_letter## /##database_path## xfs noatime 0 0" | sudo tee -a /etc/fstab 
echo "/dev/sd##email_letter## /##email_path## xfs noatime 0 0" | sudo tee -a /etc/fstab 

sudo mount -a 
</pre>


<h2>Make MySQL use the EBS volume data</h2>

<p>This assumes we have an EBS volume with a mount point called &#8220;##database_path##&#8221; attached that contains all necessary data / permissions.</p>

<pre class="command">
sudo service mysql stop 
</pre>

<p>Remove some existing MySQL parts so they can be mounted with those already available on the EBS volume.</p>

<pre class="command">
sudo mv /etc/mysql /etc/mysql.ORIG 
sudo mv /var/lib/mysql /var/lib/mysql.ORIG 
sudo mv /var/log/mysql /var/log/mysql.ORIG 

sudo mkdir /etc/mysql /var/lib/mysql /var/log/mysql 
sudo chown mysql:mysql /var/lib/mysql 
sudo chmod 0700 /var/lib/mysql
sudo chown mysql:adm /var/log/mysql 
sudo chmod 0750 /var/log/mysql 
sudo chmod g+s /var/log/mysql 

echo "/##database_path##/etc/mysql /etc/mysql none bind" | sudo tee -a /etc/fstab 
echo "/##database_path##/data /var/lib/mysql none bind" | sudo tee -a /etc/fstab 
echo "/##database_path##/log /var/log/mysql none bind" | sudo tee -a /etc/fstab 

sudo mount -a 
</pre>

<pre class="command">
sudo service mysql start 
</pre>


<h2>Make Apache / PHP use the EBS volume data</h2>

<p>This assumes we have an EBS volume with a mount point called &#8220;##webserver_path##&#8221; attached that contains all necessary data / permissions.</p>

<pre class="command">
sudo service apache2 stop 
</pre>

<p>Remove some existing Apache parts so they can be mounted with those already available on the EBS volume.</p>

<pre class="command">
sudo mv /etc/apache2 /etc/apache2.ORIG 
sudo mv /var/log/apache2 /var/log/apache2.ORIG  
sudo mv /var/www /var/www.ORIG 
sudo mv /etc/php5 /etc/php5.ORIG 

sudo mkdir /etc/apache2 /etc/apache2/vhosts /var/log/apache2 /var/www /etc/php5 
sudo chown root:adm /var/log/apache2 

echo "/##webserver_path##/apache2 /etc/apache2 none bind" | sudo tee -a /etc/fstab 
echo "/##webserver_path##/vhosts /etc/apache2/vhosts none bind" | sudo tee -a /etc/fstab 
echo "/##webserver_path##/log /var/log/apache2 none bind" | sudo tee -a /etc/fstab 
echo "/##webserver_path##/sites /var/www none bind" | sudo tee -a /etc/fstab 
echo "/##webserver_path##/php5 /etc/php5 none bind" | sudo tee -a /etc/fstab 

sudo mount -a 
</pre>

<pre class="command">
sudo service apache2 start 
</pre>


<h2>Make Postfix / Dovecot use the EBS volume data</h2>

<p>This assumes we have an EBS volume with a mount point called &#8220;##email_path##&#8221; attached that contains all necessary data / permissions.</p>

<pre class="command">
sudo service postfix stop 
sudo service dovecot stop 
</pre>

<p>Remove some existing Postfix / Dovecot parts so they can be mounted with those already available on the EBS volume. Because we are going to use a MySQL controlled, virtual mail setup we also need to create a new user and set some permissions.</p>

<pre class="command">
sudo mkdir /home/ubuntu/smtp-certificates /var/log/dovecot /var/log/postfix /var/spool/##vmail_user## /home/##vmail_user## 

sudo groupadd -g 5000 ##vmail_group## 
sudo useradd -g ##vmail_group## -u 5000 ##vmail_user## -d /home/##vmail_user## 
sudo chown ##vmail_user##:##vmail_group## /home/##vmail_user## 

sudo chown ##vmail_user##:adm /var/log/dovecot 
sudo chown syslog:adm /var/log/postfix 
sudo chown ##vmail_user##:mail /var/spool/##vmail_user## 
sudo chmod 0775 /var/spool/##vmail_user## 

sudo mv /etc/postfix /etc/postfix.ORIG 
sudo mv /etc/dovecot /etc/dovecot.ORIG 
sudo mv /var/spool/postfix /var/spool/postfix.ORIG 

sudo mkdir /etc/postfix /etc/dovecot /var/spool/postfix 

echo "/##email_path##/postfix /etc/postfix none bind" | sudo tee -a /etc/fstab 
echo "/##email_path##/dovecot /etc/dovecot none bind" | sudo tee -a /etc/fstab 
echo "/##email_path##/spool/postfix /var/spool/postfix none bind" | sudo tee -a /etc/fstab 
echo "/##email_path##/spool/##vmail_user## /var/spool/##vmail_user## none bind" | sudo tee -a /etc/fstab 
echo "/##email_path##/##vmail_user## /home/##vmail_user## none bind" | sudo tee -a /etc/fstab 
echo "/##email_path##/smtp-certificates /home/ubuntu/smtp-certificates none bind" | sudo tee -a /etc/fstab 
echo "/##email_path##/log/dovecot /var/log/dovecot none bind" | sudo tee -a /etc/fstab 
echo "/##email_path##/log/postfix /var/log/postfix none bind" | sudo tee -a /etc/fstab 

sudo mount -a 
</pre>

<pre class="command">
sudo service postfix start 
sudo service dovecot start 
</pre>

<h2>Make Subversion use the EBS volume data (optional)</h2>

<pre class="command">
sudo mkdir /svn-repositories 

echo "/##webserver_path##/svn /svn-repositories none bind" | sudo tee -a /etc/fstab 

sudo mount -a 
</pre>

##previous-next-page-5b##

##download##

##contents##

##previous-next-page-5b##]]></content:encoded>
			<wfw:commentRss>http://www.paul-norman.co.uk/2011/02/attach-existing-ebs-volumes/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>EC2 Guide: Create and attach new EBS volumes (5a / 7)</title>
		<link>http://www.paul-norman.co.uk/2011/02/create-and-attach-new-ebs-volumes/</link>
		<comments>http://www.paul-norman.co.uk/2011/02/create-and-attach-new-ebs-volumes/#comments</comments>
		<pubDate>Mon, 28 Feb 2011 23:47:59 +0000</pubDate>
		<dc:creator>Paul Norman</dc:creator>
				<category><![CDATA[Server]]></category>
		<category><![CDATA[Apache]]></category>
		<category><![CDATA[Cloud]]></category>
		<category><![CDATA[Dovecot]]></category>
		<category><![CDATA[EBS]]></category>
		<category><![CDATA[EC2]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Postfix]]></category>
		<category><![CDATA[Ubuntu 10.04]]></category>

		<guid isPermaLink="false">http://www.paul-norman.co.uk/?p=50</guid>
		<description><![CDATA[To allow our server to be upgradable we are going to separate out various parts of our system onto 3 separate EBS volumes so that they could be disconnected and re-attached to another machine very quickly should we want to add other servers.]]></description>
			<content:encoded><![CDATA[##previous-next-page-5##

<p>The EBS volumes that we are about to create will function as external hard drives to our instance. They can only be attached to one instance at a time. If you don&#8217;t want to use these please make the few changes that are needed to keep this guide compatible <a href="/2011/02/no-attached-ebs-volumes/" title="I don't want to use EBS volumes">here</a>. If you already have these volumes with data on them as described below you need to go <a href="/2011/02/attach-existing-ebs-volumes/" title="I already have my EBS volumes configured, but want to re-attach them">here</a>.</p>


<h2>Create the EBS volumes</h2>

<p>Using Elasticfox you will need to create 3 EBS volumes (Database, Web-server and Mail-server):</p>

<ul>
	<li>Click on the &#8220;Volumes and Snapshots&#8221; tab</li>
	<li>Click on the green plus button</li>
	<li>Choose a size and an availability zone for the volume (must be the same as your server instance: ##cloud_region####availability_zone##)</li>
	<li>The size cannot be altered dynamically, but can be changed in the future if required using a snapshot</li>
	<li>Tag each sensibly! (so you can tell which is which)</li>
</ul>


<h2>Attaching the EBS volumes</h2>

<p>Using Elasticfox:</p>

<ul>
	<li>Click on the &#8220;Volumes and Snapshots&#8221; tab</li>
	<li>Select each EBS volume individually and click on the green plus to attach it to your running instance</li>
	<li>Enter a path for each <em>(the range is  sdc to sdp &#8211; sda and sdb are already in use)</em>
	<ul>
		<li>For the web-server: /dev/sd##webserver_letter##</li>
		<li>For the database: /dev/sd##database_letter## &#8211; &#8220;d&#8221; for database may be a good choice</li>
		<li>For the e-mails: /dev/sd##email_letter## &#8211; &#8220;e&#8221; for e-mails may be a good choice</li>
	</ul>
</li>
</ul>

<h2>Formatting the EBS volumes</h2>

<p>Back to the server, where your new volumes are now attached we need to create a file-system on them. XFS is generally used for this:</p>

<pre class="command">
sudo mkfs.xfs /dev/sd##webserver_letter## 
sudo mkfs.xfs /dev/sd##database_letter## 
sudo mkfs.xfs /dev/sd##email_letter## 
</pre>


<h2>Mounting the EBS volumes in useful locations</h2>

<p>Choose descriptive path names for each!</p>

<pre class="command">
echo "/dev/sd##webserver_letter## /##webserver_path## xfs noatime 0 0" | sudo tee -a /etc/fstab 
sudo mkdir -m 000 /##webserver_path## 
sudo mount /##webserver_path## 

echo "/dev/sd##database_letter## /##database_path## xfs noatime 0 0" | sudo tee -a /etc/fstab 
sudo mkdir -m 000 /##database_path## 
sudo mount /##database_path## 

echo "/dev/sd##email_letter## /##email_path## xfs noatime 0 0" | sudo tee -a /etc/fstab 
sudo mkdir -m 000 /##email_path## 
sudo mount /##email_path## 
</pre>


<h2>Move MySQL to an EBS volume</h2>

<p>This assumes we have an EBS volume with a mount point called &#8220;##database_path##&#8221; attached.</p>

<pre class="command">
sudo service mysql stop 
</pre>

<p>Move the existing MySQL parts to run on the EBS volume, but keep their &#8216;place-holders&#8217; populated through mount points.</p>

<pre class="command">
sudo mkdir /##database_path##/etc /##database_path##/log /##database_path##/data 

sudo chown mysql:mysql /##database_path##/data 
sudo chmod 0700 /##database_path##/data 
sudo chown mysql:adm /##database_path##/log
sudo chmod 0750 /##database_path##/log 
sudo chmod g+s /##database_path##/log

sudo cp -R /etc/mysql /etc/mysql.ORIG 
sudo cp -R /var/lib/mysql /var/lib/mysql.ORIG 
sudo cp -R /var/log/mysql /var/log/mysql.ORIG 

sudo mv /etc/mysql /##database_path##/etc/ 
sudo mv /var/lib/mysql/* /##database_path##/data/ 
sudo mv /var/log/mysql/* /##database_path##/log/ 

sudo mkdir /etc/mysql

echo "/##database_path##/etc/mysql /etc/mysql none bind" | sudo tee -a /etc/fstab 
echo "/##database_path##/data /var/lib/mysql none bind" | sudo tee -a /etc/fstab 
echo "/##database_path##/log /var/log/mysql none bind" | sudo tee -a /etc/fstab 

sudo mount -a 
</pre>

<pre class="command">
sudo service mysql start 
</pre>


<h2>Move Apache / PHP / sites to an EBS volume</h2>

<p>This assumes we have an EBS volume with a mount point called &#8220;##webserver_path##&#8221; attached.</p>

<pre class="command">
sudo service apache2 stop 
</pre>

<p>Move some Apache parts to run on the EBS volume, but keep the &#8216;place-holders&#8217; populated through mount points.</p>

<pre class="command">
sudo cp -R /etc/apache2 /etc/apache2.ORIG 
sudo cp -R /var/log/apache2 /var/log/apache2.ORIG 
sudo cp -R /var/www /var/www.ORIG 
sudo cp -R /etc/php5 /etc/php5.ORIG 

sudo mv /etc/apache2 /##webserver_path##/ 
sudo mv /var/log/apache2/ /##webserver_path##/log/ 
sudo mv /var/www/ /##webserver_path##/sites/ 
sudo mv /etc/php5 /##webserver_path##/ 

sudo mkdir /##webserver_path##/vhosts /##webserver_path##/apache2/vhosts /etc/apache2 /etc/apache2/vhosts /var/log/apache2 /var/www /etc/php5 

echo "/##webserver_path##/apache2 /etc/apache2 none bind" | sudo tee -a /etc/fstab 
echo "/##webserver_path##/vhosts /etc/apache2/vhosts none bind" | sudo tee -a /etc/fstab 
echo "/##webserver_path##/log /var/log/apache2 none bind" | sudo tee -a /etc/fstab 
echo "/##webserver_path##/sites /var/www none bind" | sudo tee -a /etc/fstab 
echo "/##webserver_path##/php5 /etc/php5 none bind" | sudo tee -a /etc/fstab 

sudo mount -a 
</pre>

<pre class="command">
sudo service apache2 start 
</pre>


<h2>Move E-mail / Postfix / Dovecot to an EBS volume</h2>

<p>This assumes we have an EBS volume with a mount point called &#8220;##email_path##&#8221; attached.</p>

<pre class="command">
sudo service postfix stop 
sudo service dovecot stop 
</pre>

<p>Move some E-mail related parts to run on the EBS volume, but keep the &#8216;place-holders&#8217; populated through mount points. Because we are going to use a MySQL controlled, virtual mail set-up we also need to create a new user and set some permissions.</p>

<pre class="command">
sudo mkdir /##email_path##/##vmail_user## /##email_path##/log /##email_path##/log/postfix /##email_path##/log/dovecot /##email_path##/spool /##email_path##/spool/postfix/ /##email_path##/spool/##vmail_user##/ /##email_path##/smtp-certificates /home/ubuntu/smtp-certificates /var/log/dovecot /var/log/postfix /var/spool/##vmail_user## /home/##vmail_user##

sudo groupadd -g 5000 ##vmail_group## 
sudo useradd -g ##vmail_group## -u 5000 ##vmail_user## -d /home/##vmail_user## 
sudo chown ##vmail_user##:##vmail_group## /home/##vmail_user## 

sudo chown ##vmail_user##:adm /var/log/dovecot 
sudo chown syslog:adm /var/log/postfix 
sudo chown ##vmail_user##:mail /var/spool/##vmail_user##
sudo chmod 0775 /var/spool/##vmail_user## 

sudo chown ##vmail_user##:adm /##email_path##/log/dovecot 
sudo chown syslog:adm /##email_path##/log/postfix 
sudo chown ##vmail_user##:##vmail_group## /##email_path##/##vmail_user## 
sudo chown ##vmail_user##:##vmail_group## /##email_path##/log 
sudo chown ##vmail_user##:##vmail_group## /email/spool/postfix 
sudo chown ##vmail_user##:mail /##email_path##/spool/##vmail_user## 
sudo chmod 0775 /##email_path##/spool/##vmail_user## 

sudo cp -R /etc/postfix /etc/postfix.ORIG 
sudo cp -R /etc/dovecot /etc/dovecot.ORIG 
sudo cp -R /var/spool/postfix /var/spool/postfix.ORIG 

sudo mv /etc/postfix/ /##email_path##/postfix 
sudo mv /etc/dovecot/ /##email_path##/dovecot 
sudo mv /var/spool/postfix/* /##email_path##/spool/postfix 

sudo mkdir /etc/postfix /etc/dovecot /etc/postfix/virtual

echo "/##email_path##/postfix /etc/postfix none bind" | sudo tee -a /etc/fstab 
echo "/##email_path##/dovecot /etc/dovecot none bind" | sudo tee -a /etc/fstab 
echo "/##email_path##/spool/postfix /var/spool/postfix none bind" | sudo tee -a /etc/fstab 
echo "/##email_path##/spool/##vmail_user## /var/spool/##vmail_user## none bind" | sudo tee -a /etc/fstab 
echo "/##email_path##/##vmail_user## /home/##vmail_user## none bind" | sudo tee -a /etc/fstab 
echo "/##email_path##/smtp-certificates /home/ubuntu/smtp-certificates none bind" | sudo tee -a /etc/fstab 
echo "/##email_path##/log/dovecot /var/log/dovecot none bind" | sudo tee -a /etc/fstab 
echo "/##email_path##/log/postfix /var/log/postfix none bind" | sudo tee -a /etc/fstab 

sudo mount -a 
</pre>

<pre class="command">
sudo service postfix start 
sudo service dovecot start 
</pre>


<h2>Move Subversion to an EBS Volume (optional)</h2>

<p>This assumes we have an EBS volume with a mount point called &#8220;##webserver_path##&#8221; attached.</p>

<p>We have no subversion repository location yet, so we can just create one:</p>

<pre class="command">
sudo mkdir /##webserver_path##/svn /svn-repositories 

echo "/##webserver_path##/svn /svn-repositories none bind" | sudo tee -a /etc/fstab 

sudo mount -a 
</pre>

##previous-next-page-5##

##download##

##contents##

##previous-next-page-5##]]></content:encoded>
			<wfw:commentRss>http://www.paul-norman.co.uk/2011/02/create-and-attach-new-ebs-volumes/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>EC2 Guide: Core Software Installation (4 / 7)</title>
		<link>http://www.paul-norman.co.uk/2011/02/core-software-installation/</link>
		<comments>http://www.paul-norman.co.uk/2011/02/core-software-installation/#comments</comments>
		<pubDate>Mon, 28 Feb 2011 23:46:49 +0000</pubDate>
		<dc:creator>Paul Norman</dc:creator>
				<category><![CDATA[Server]]></category>
		<category><![CDATA[Amavisd-New]]></category>
		<category><![CDATA[Apache]]></category>
		<category><![CDATA[ClamAV]]></category>
		<category><![CDATA[Cloud]]></category>
		<category><![CDATA[Dovecot]]></category>
		<category><![CDATA[EC2]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Postfix]]></category>
		<category><![CDATA[Spamassassin]]></category>
		<category><![CDATA[Ubuntu 10.04]]></category>

		<guid isPermaLink="false">http://www.paul-norman.co.uk/?p=49</guid>
		<description><![CDATA[We should now be ready to install our core software on our Ubuntu 10.04 server and customise a few key things. We are going to add Postfix, Dovecot, Spamassassin, Amavisd-New, ClamAV, Apache, PHP, MySQL and a few other useful things.]]></description>
			<content:encoded><![CDATA[##previous-next-page-4##

<p>The image that we are starting with is extremely minimal, and while it is configured to allow a rapid setup for a certain server type (e.g. a web server / mail server), it is often better to install exactly what you need on a machine and nothing more. This process will install everything needed to create a web-server / database server / e-mail server combo box. Of course you could install only the parts applicable to your server if it is a sole purpose box.</p>


<h2>Install some basic apps/utilities</h2>

<p>We need the following very basic utilities for a multitude of tasks so they go on first.</p>

<pre class="command">
sudo aptitude install ssh openssh-server ##editor## 
</pre>


<h2>Set a Root User Password</h2>

<p>By default the root account has no password, but because it is sometimes advantageous to run as root (not just sudo) it&#8217;s a good idea to set one. Just don&#8217;t forget it! <em>(I use my <a href="https://www.ironkey.com/" title="Get an IronKey">IronKey</a> for this kind of information storage)</em></p>

<pre class="command">
sudo passwd 
</pre>


<h2>Set an Ubuntu User Password</h2>

<p>The default system user is called &#8220;ubuntu&#8221; and has a random password assigned to it. There are arguments for and against changing this, but since I use it as my default user and don&#8217;t always want to count on having my AWS key file handy, I set this. Again, write it down somewhere safe.</p>

<pre class="command">
sudo passwd ubuntu 
</pre>


<h2>Create an FTP / SFTP User</h2>

<p>It&#8217;s often convenient to be able to move data onto a server (especially for a web server), so we&#8217;ll add a user just for this.</p>

<pre class="command">
sudo useradd ##ftp_username## -d /home/##ftp_username## 
sudo passwd ##ftp_username## 
sudo adduser ##ftp_username## www-data 
</pre>


<h2>Disable root SSH / allow SSH/SFTP with a password</h2>

<p>There&#8217;s no reason to allow the root user to log in via SSH (even if it is IP locked). We also want our other users to be able to log in with a password.</p>

<pre class="command">
sudo ##editor## /etc/ssh/sshd_config 
</pre>

<p>Uncomment / update the necessary lines:</p>

<pre class="file">
[...]
PermitRootLogin no
[...]
PasswordAuthentication yes
[...]
</pre>

<p>Apply the changes:</p>

<pre class="command">
sudo /etc/init.d/ssh restart 
</pre>


<h2>Configure aptitude (package manager)</h2>

<p>Remove the CD as a source and enable main, universe and multiverse support.</p>

<pre class="command">
sudo ##editor## /etc/apt/sources.list 
</pre>

<pre class="file">
deb http://##aptitude_update##.archive.ubuntu.com/ubuntu/ lucid main universe multiverse
deb-src http://##aptitude_update##.archive.ubuntu.com/ubuntu/ lucid main universe multiverse
deb http://##aptitude_update##.archive.ubuntu.com/ubuntu/ lucid-updates main universe multiverse
deb-src http://##aptitude_update##.archive.ubuntu.com/ubuntu/ lucid-updates main universe multiverse
deb http://security.ubuntu.com/ubuntu lucid-security main universe multiverse
deb-src http://security.ubuntu.com/ubuntu lucid-security main universe multiverse
deb http://archive.canonical.com/ lucid partner
</pre>

<p>Then update the aptitude database:</p>

<pre class="command">
sudo aptitude update 
</pre>


<h2>Update all installed apps/utilities</h2>

<pre class="command">
sudo aptitude safe-upgrade 
</pre>

<p><strong>IF</strong> a new Kernel has been added a reboot will be required.</p>

<pre class="command">
sudo reboot 
</pre>


<h2>Configure the network</h2>

<p>We need to tell our machine what IP and domain we are using. Update your hosts file to look like this:</p>

<pre class="command">
sudo ##editor## /etc/hosts 
</pre>

<pre class="file">
127.0.0.1       localhost.##domain##   localhost
##ip##   ##subdomain##.##domain##   ##subdomain##

# The following lines are desirable for IPv6 capable hosts
::1     localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
ff02::3 ip6-allhosts
</pre>

<pre class="command">
sudo hostname ##subdomain## 
sudo ##editor## /etc/hostname 
</pre>

<pre class="file">
##subdomain##
</pre>

<p>Restart the service:</p>

<pre class="command">
sudo /etc/init.d/hostname restart 
</pre>

<p>There are some errors with this service on Ubuntu 10.04 so don&#8217;t pay too much attention to any message you receive. To check it has worked run:</p>

<pre class="command">
sudo hostname 
sudo hostname -f 
</pre>

<p>First should read ##subdomain## and the latter ##subdomain##.##domain##.</p>


<h2>Set timezone and synchronize the system clock</h2> 

<p>Always a good idea to set the server to your preferred time zone and have it synchronise itself. There are perhaps neater ways to do this, but this is reliable!</p>

<pre class="command">
sudo rm -f /etc/localtime 
sudo ln -sf /usr/share/zoneinfo/##timezone## /etc/localtime 
</pre>

<p>Make sure our server keeps itself up to date.</p>

<pre class="command">
sudo aptitude install ntp ntpdate 
</pre>


<h2>Disable AppArmor</h2>

<p>This is a security application similar to SELINUX but is often the cause of a lot of painful troubleshooting. It is not required to construct a secure system, anyone who tells you otherwise is wrong!</p>

<pre class="command">
sudo service apparmor stop 
sudo update-rc.d -f apparmor remove 
sudo aptitude remove apparmor apparmor-utils 
</pre>


<h2>Install MySQL</h2>

<pre class="command">
sudo aptitude install mysql-client mysql-server 
</pre>

<pre class="output">
New password for the MySQL "root" user: <em>(choose)</em>
Repeat password for the MySQL "root" user: <em>(repeat)</em>
</pre>

<p>Check that it is working:</p>

<pre class="command">
sudo netstat -tap | grep mysql 
</pre>

<pre class="output">
tcp 0 0 localhost:mysql *:* LISTEN 7753/mysqld
</pre>


<h2>Install Postfix, Dovecot and Saslauthd</h2>

<p>These are all required for our e-mail server (along with MySQL above).</p>

<pre class="command">
sudo aptitude install postfix postfix-mysql postfix-doc dovecot-common dovecot-postfix dovecot-imapd dovecot-pop3d libsasl2-2 libsasl2-modules libsasl2-modules-sql sasl2-bin libpam-mysql openssl telnet mailutils 
</pre>

<p>This should also create the root mysql user and set their password. This is for both Local and external.</p>

<pre class="output">
General type of mail configuration: <em>(internet site)</em>
System mail name: <em>(##domain##)</em>
</pre>


<h2>Install Amavisd-new, SpamAssassin, ClamAv (and related trimmings)</h2>

<p>While not essential for an e-mail server, these anti-spam / anti-virus tools are a very, very good idea!</p>

<pre class="command">
sudo aptitude install amavisd-new spamassassin clamav clamav-daemon zoo unzip bzip2 arj nomarch lzop cabextract apt-listchanges libnet-ldap-perl libauthen-sasl-perl clamav-docs daemon libio-string-perl libio-socket-ssl-perl libnet-ident-perl zip libnet-dns-perl libmail-spf-query-perl pyzor razor arj bzip2 cabextract cpio file gzip lha nomarch pax rar unrar unzip zip zoo rpm2cpio p7zip-full unrar-free ripole
</pre>


<h2>Install PHP / Apache</h2>

<p>These form the basis of most unix based webservers.</p>

<pre class="command">
sudo aptitude install apache2 apache2.2-common apache2-doc apache2-mpm-prefork apache2-utils libexpat1 ssl-cert libapache2-mod-php5 php5 php5-common php5-gd php5-mysql php5-imap php5-cli php5-cgi libapache2-mod-fcgid php-pear php-auth php5-mcrypt mcrypt php5-curl php5-pspell php5-imagick imagemagick flite 
</pre>

<p>There are some errors in the following package comments (the wrong comment identifiers have been used)! Open each and update any comments starting with <strong>#</strong> (hash / pound) to begin with a <strong>;</strong> (semi-colon).</p>

<pre class="command">
sudo ##editor## /etc/php5/cli/conf.d/imagick.ini 
sudo ##editor## /etc/php5/cli/conf.d/imap.ini 
sudo ##editor## /etc/php5/cli/conf.d/mcrypt.ini 
</pre>

<p>Configure the basic mods that Apache will use.</p>

<pre class="command">
sudo a2enmod rewrite ssl actions include dav_fs dav auth_digest headers expires 
sudo a2dismod autoindex 
</pre>

<p>Apply these changes:</p>

<pre class="command">
sudo service apache2 restart 
</pre>


<h2>Install PHP Extensions (from PECL) <span style="color: red">(optional)</span></h2>

<p>If you need to add any PECL extensions there are a few other requirements before installation can take place:</p>

<pre class="command">
sudo aptitude install php5-dev make 
</pre>

<p>Once they are available to the system any PECL extensions can be added as follows (I&#8217;m using Mailparse and Sphinx as my example, you can use any you like!):</p>

<pre class="command">
sudo pecl install mailparse, sphinx 
</pre>

<p>To enable them a new configuration file is required for each.</p>

<pre class="command">
sudo ##editor## /etc/php5/conf.d/mailparse.ini 
</pre>

<pre class="file">
; configuration for php Mailparse module
extension=mailparse.so
</pre>

<pre class="command">
sudo aptitude install sphinxsearch 
sudo ##editor## /etc/php5/conf.d/sphinx.ini 
</pre>

<pre class="file">
; configuration for php Sphinx module
extension=sphinx.so
</pre>

<p>And then restart Apache to apply the changes:</p>

<pre class="command">
sudo service apache2 restart 
</pre>


<h2>Update the locate database</h2>

<p>The locate command  can be extremely useful. <em>(usage example: locate master.cf)</em></p>

<pre class="command">
sudo updatedb
</pre>


<h2>Install the EC2 API command line tools (cloud only)</h2>

<p>In order to control the ec2 instances / volumes from the server itself (e.g. for backup crons) we need to add a few tools. Also if you are going to add any EBS volumes to the main EBS backed instance the tools for creation and management of the XFS filesystem are required.</p>

<pre class="command">
sudo aptitude install sun-java6-jre ec2-api-tools xfslibs-dev xfsdump xfsprogs dmapi 
</pre>

<p>To use these tools the keys that are required must be available to the system. Create a directory to store these X.509 keys. As management will likely be through the ubuntu (default) user we&#8217;ll store the keys in their directory.</p>

<pre class="command">
mkdir /home/ubuntu/ec2-keys 
</pre>

<pre class="command">
##editor## /home/ubuntu/ec2-keys/##ec2_cert_filename## 
</pre>

<p>Add your certificate data (copy / paste) to this file and save it.</p>

<pre class="command">
##editor## /home/ubuntu/ec2-keys/##ec2_pk_filename## 
</pre>

<p>Add your private key data (copy / paste) to this file and save it.</p>

<p>We can also add these keys (and other useful constants) to the global shell configuration files so that they are available to the terminal and login shells (called by crons).</p>

<pre class="command">
sudo ##editor## /etc/bash.bashrc 
</pre>

<pre class="file">
[...]
# Basic convenience
alias ..='cd ..'
alias ...='cd ...'
alias cd..='cd ..'
alias cd-='cd -'
alias ls='ls -lh --color=auto'
alias dir='ls -lh --color=auto'
alias df="df -h"
alias h=history
alias targz="tar cvfz"
alias untargz="tar xvfz"
alias tarbz2="tar cvfj"
alias untarbz2="tar xvfj"
alias unrar="unrar x"
[...]
export EDITOR=##editor##
export EC2_CERT=/home/ubuntu/ec2-keys/##ec2_cert_filename##
export EC2_PRIVATE_KEY=/home/ubuntu/ec2-keys/##ec2_pk_filename##
export JAVA_HOME=/usr/lib/jvm/java-6-openjdk/
export EC2_PRIVATE_IP="`wget -q -O - http://169.254.169.254/latest/meta-data/local-ipv4`"
export EC2_INSTANCE_ID="`wget -q -O - http://169.254.169.254/latest/meta-data/instance-id`"
export EC2_AVAIL_ZONE="`wget -q -O - http://169.254.169.254/latest/meta-data/placement/availability-zone`"
export EC2_REGION="`echo \"$EC2_AVAIL_ZONE\" | sed -e 's:\([0-9][0-9]*\)[a-z]*\$:\\1:'`"
export AWS_ACCESS_KEY_ID=##aws_access_key_id##
export AWS_SECRET_ACCESS_KEY=##aws_secret_access_key##
</pre>

<pre class="command">
sudo ##editor## /etc/profile 
</pre>

<pre class="file">
[...]
# Basic convenience
alias ..='cd ..'
alias ...='cd ...'
alias cd..='cd ..'
alias cd-='cd -'
alias ls='ls -lh --color=auto'
alias dir='ls -lh --color=auto'
alias df="df -h"
alias h=history
alias targz="tar cvfz"
alias untargz="tar xvfz"
alias tarbz2="tar cvfj"
alias untarbz2="tar xvfj"
alias unrar="unrar x"
[...]
export EDITOR=##editor##
export EC2_CERT=/home/ubuntu/ec2-keys/##ec2_cert_filename##
export EC2_PRIVATE_KEY=/home/ubuntu/ec2-keys/##ec2_pk_filename##
export JAVA_HOME=/usr/lib/jvm/java-6-openjdk/
export EC2_PRIVATE_IP="`wget -q -O - http://169.254.169.254/latest/meta-data/local-ipv4`"
export EC2_INSTANCE_ID="`wget -q -O - http://169.254.169.254/latest/meta-data/instance-id`"
export EC2_AVAIL_ZONE="`wget -q -O - http://169.254.169.254/latest/meta-data/placement/availability-zone`"
export EC2_REGION="`echo \"$EC2_AVAIL_ZONE\" | sed -e 's:\([0-9][0-9]*\)[a-z]*\$:\\1:'`"
export AWS_ACCESS_KEY_ID=##aws_access_key_id##
export AWS_SECRET_ACCESS_KEY=##aws_secret_access_key##
</pre>

<p>Apply these changes.</p>

<pre class="command">
rm /home/ubuntu/ec2-keys/*.pem~ 
source /etc/bash.bashrc 
source /etc/profile 
source ~/.bashrc 
</pre>

<p>Update the permissions on these files:</p>

<pre class="command">
sudo chmod 0600 /home/ubuntu/ec2-keys/* 
</pre>

<p>At this point it is likely a good idea to disable your ability to (accidentally) terminate your server!</p>

<pre class="command">
ec2-modify-instance-attribute $EC2_INSTANCE_ID --disable-api-termination true --region $EC2_REGION 
</pre>

<p>It should tell you that this has been actioned. If you wish to terminate your instance in the future you need to update this setting to false.</p>


<h2>Install Subversion <span style="color: red">(optional)</span></h2>

<p>I like to use <a href="http://subversion.tigris.org/" title="Visit the Subversion website">Subversion</a> as my version control system because there&#8217;s just me, but you may prefer <a href="http://git-scm.com/" title="Visit the Git website">Git</a>, <a href="http://mercurial.selenic.com/" title="Visit the Mercurial website">Mercurial</a>, <a href="http://bazaar.canonical.com/" title="Visit the Bazaar website">Bazaar</a> or many of the other alternatives. This is not required for the system to run!</p>

<pre class="command">
sudo aptitude install subversion libapache2-svn 
</pre>

<pre class="command">
sudo service apache2 restart 
</pre>


<h2>Add a Remote Desktop system <span style="color: red">(optional / large)</span></h2>

<p>This isn&#8217;t something that I would bother with, but if it is absolutely required then FreeNX is excellent.</p>

<pre class="command">
export DEBIAN_FRONTEND=noninteractive 
sudo aptitude install ubuntu-desktop 
</pre>

<pre class="command">
sudo add-apt-repository ppa:freenx-team 
sudo aptitude update 
sudo aptitude install freenx 
</pre>

<pre class="command">
cd /usr/lib/nx 
sudo wget http://launchpadlibrarian.net/47959420/nxsetup.tar.gz 
sudo tar xzvf nxsetup.tar.gz 
sudo ./nxsetup --install 
</pre>

<p><a href="http://www.nomachine.com/select-package-client.php">Download</a> and launch the NX client and connect to the server via SSH using a user with a password login.</p>

##previous-next-page-4##

##download##

##contents##

##previous-next-page-4##]]></content:encoded>
			<wfw:commentRss>http://www.paul-norman.co.uk/2011/02/core-software-installation/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>EC2 Guide: Customise this guide (3 / 7)</title>
		<link>http://www.paul-norman.co.uk/2011/02/customise-this-guide/</link>
		<comments>http://www.paul-norman.co.uk/2011/02/customise-this-guide/#comments</comments>
		<pubDate>Mon, 28 Feb 2011 23:45:48 +0000</pubDate>
		<dc:creator>Paul Norman</dc:creator>
				<category><![CDATA[Server]]></category>
		<category><![CDATA[Cloud]]></category>
		<category><![CDATA[EC2]]></category>
		<category><![CDATA[Ubuntu 10.04]]></category>

		<guid isPermaLink="false">http://www.paul-norman.co.uk/?p=48</guid>
		<description><![CDATA[To make this guide more useful many aspects of it can be customised to show your values. Who really wants to read a guide only to have to change half of it to fit their needs anyway?]]></description>
			<content:encoded><![CDATA[##previous-next-page-3##

<p>To attempt to make this guide more useful I have a created a number of <strong>optional</strong> variables that you can use to customise its content. <span style="color: red;">Red</span> shows things you should change, <span style="color: green;">green</span> shows values that are acceptable (but you <strong>may</strong> wish to update) and <span style="color: blue;">blue</span> represents variables customised to you. All you need to do is update the values of any field you wish to change and press &#8220;Update&#8221; <em>(nothing is logged or stored, only sessions are used)</em>. You may need to visit this page again from later steps as and when you have new information.</p>

<form method="post" action="/2011/02/customise-this-guide/">

<fieldset class="standard">
<legend>Things you should change!</legend>
<ul>

<li><label for="r_website_name">Your site name:</label>
<input type="text" id="r_website_name" name="_replacements[server_post][website_name]" />
&nbsp; <em>##website_name##</em></li>

<li><label for="r_domain">Domain:</label>
<input type="text" id="r_domain" name="_replacements[server_post][domain]" />
&nbsp; <em>##domain##</em></li>

<li><label for="r_subdomain">Sub-domain:</label>
<input type="text" id="r_subdomain" name="_replacements[server_post][subdomain]" />
&nbsp; <em>##subdomain##</em></li>

<li><label for="r_ip">Server IP:</label>
<input type="text" id="r_ip" name="_replacements[server_post][ip]" />
&nbsp; <em>##ip##</em></li>

<li><label for="r_current_ip">Management IP:</label>
<input type="text" id="r_current_ip" name="_replacements[server_post][current_ip]" />
&nbsp; <em>##current_ip##</em></li>

<li><label for="r_ec2_key_path">Your EC2 Key Path <small>(Linux)</small>:</label>
<input type="text" id="r_ec2_key_path" name="_replacements[server_post][ec2_key_path]" />
&nbsp; <em>##ec2_key_path##</em></li>

<li><label for="r_ec2_key_path_ms">Your EC2 Key Path <small>(Windows)</small>:</label>
<input type="text" id="r_ec2_key_path_ms" name="_replacements[server_post][ec2_key_path_ms]" />
&nbsp; <em>##ec2_key_path_ms##</em></li>

<li><label for="r_ec2_putty_path">PuTTY path <small>(Windows)</small>:</label>
<input type="text" id="r_ec2_putty_path" name="_replacements[server_post][ec2_putty_path]" />
&nbsp; <em>##ec2_putty_path##</em></li>

<li><label for="r_ec2_keypair_name">EC2 Key Pair name:</label>
<input type="text" id="r_ec2_keypair_name" name="_replacements[server_post][ec2_keypair_name]" />
&nbsp; <em>##ec2_keypair_name##</em></li>

<li><label for="r_ec2_cert_filename">EC2 Certificate File name:</label>
<input type="text" id="r_ec2_cert_filename" name="_replacements[server_post][ec2_cert_filename]" />
&nbsp; <em><small>##ec2_cert_filename##</small></em></li>

<li><label for="r_ec2_pk_filename">EC2 Private Key File name:</label>
<input type="text" id="r_ec2_pk_filename" name="_replacements[server_post][ec2_pk_filename]" />
&nbsp; <em><small>##ec2_pk_filename##</small></em></li>

<li><label for="r_aws_access_key_id">AWS Access Key ID:</label>
<input type="text" id="r_aws_access_key_id" name="_replacements[server_post][aws_access_key_id]" />
&nbsp; <em><small>##aws_access_key_id##</small></em></li>

<li><label for="r_aws_secret_access_key">AWS Secret Access Key:</label>
<input type="text" id="r_aws_secret_access_key" name="_replacements[server_post][aws_secret_access_key]" />
&nbsp; <em><small>##aws_secret_access_key##</small></em></li>

<li><label for="r_volume_id_core">Core volume ID:</label>
<input type="text" id="r_volume_id_core" name="_replacements[server_post][volume_id_core]" />
&nbsp; <em>##volume_id_core##</em></li>

<li><label for="r_volume_id_webserver">Web-server volume ID:</label>
<input type="text" id="r_volume_id_webserver" name="_replacements[server_post][volume_id_webserver]" />
&nbsp; <em>##volume_id_webserver##</em></li>

<li><label for="r_volume_id_email">E-mail volume ID:</label>
<input type="text" id="r_volume_id_email" name="_replacements[server_post][volume_id_email]" />
&nbsp; <em>##volume_id_email##</em></li>

<li><label for="r_volume_id_database">Database volume ID:</label>
<input type="text" id="r_volume_id_database" name="_replacements[server_post][volume_id_database]" />
&nbsp; <em>##volume_id_database##</em></li>

<li><label for="r_root_db_password">MySQL root password:</label>
<input type="text" id="r_root_db_password" name="_replacements[server_post][root_db_password]" />
&nbsp; <em>##root_db_password##</em></li>

<li><label for="r_vmail_db_password">MySQL Vmail password:</label>
<input type="text" id="r_vmail_db_password" name="_replacements[server_post][vmail_db_password]" />
&nbsp; <em>##vmail_db_password##</em></li>

<li><label>&nbsp;</label>
<input type="submit" name="_replacements[server_post][submit]" class="button" style="float: left; margin-right: 5px;" value="Update" /> <input type="submit" name="_replacements[server_post][reset_placeholders]" class="button" style="float: left; margin-right: 5px;" value="Reset" /> <input type="submit" name="_replacements[server_post][reset_all]" class="button" style="float: left" value="Reset All" /></li>

</fieldset>

<fieldset class="standard">
<legend>Things where the default values <em>MAY</em> suit you</legend>
<ul>
<li><label for="r_editor">Preferred CLI editor:</label>
<select id="r_editor" name="_replacements[server_post][editor]">
<option value=""></option>
<option value="nano">nano</option>
<option value="vim">vim</option>
<option value="emacs">emacs</option>
</select>
&nbsp; <em>##editor##</em></li>

<li><label for="r_cloud_region">EC2 Region:</label>
<select id="r_cloud_region" name="_replacements[server_post][cloud_region]">
<option value=""></option>
<option value="us-east-1">us-east-1</option>
<option value="us-west-1">us-west-1</option>
<option value="eu-west-1">eu-west-1</option>
<option value="ap-southeast-1">ap-southeast-1</option>
<option value="ap-northeast-1">ap-northeast-1</option>
</select>
&nbsp; <em>##cloud_region##</em></li>

<li><label for="r_availability_zone">Availability Zone:</label>
<select id="r_availability_zone" name="_replacements[server_post][availability_zone]">
<option value=""></option>
<option value="a">a</option>
<option value="b">b</option>
<option value="c">c</option>
<option value="d">d</option>
</select>
&nbsp; <em>##availability_zone##</em></li>

<li><label for="r_aptitude_update">Aptitude Update Region:</label>
<input type="text" id="r_aptitude_update" name="_replacements[server_post][aptitude_update]" />
&nbsp; <em>##aptitude_update##</em> <small>(2 letter country code for non-cloud set-up)</small></li>

<li><label for="r_ftp_username">FTP Username:</label>
<input type="text" id="r_ftp_username" name="_replacements[server_post][ftp_username]" />
&nbsp; <em>##ftp_username##</em></li>

<li><label for="r_timezone">Timezone:</label>
<input type="text" id="r_timezone" name="_replacements[server_post][timezone]" />
&nbsp; <em>##timezone##</em></li>

<li><label for="r_php_my_admin_version">phpMyAdmin version:</label>
<input type="text" id="r_php_my_admin_version" name="_replacements[server_post][php_my_admin_version]" />
&nbsp; <em>##php_my_admin_version##</em></li>

<li><label for="r_postfix_admin_version">Postfix Admin version:</label>
<input type="text" id="r_postfix_admin_version" name="_replacements[server_post][postfix_admin_version]" />
&nbsp; <em>##postfix_admin_version##</em></li>

<li><label for="r_squirrelmail_version">Squirrelmail version:</label>
<input type="text" id="r_squirrelmail_version" name="_replacements[server_post][squirrelmail_version]" />
&nbsp; <em>##squirrelmail_version##</em></li>

<li><label for="r_webserver_path">Web-server mount point:</label>
<input type="text" id="r_webserver_path" name="_replacements[server_post][webserver_path]" />
&nbsp; <em>##webserver_path##</em></li>

<li><label for="r_database_path">Database mount point:</label>
<input type="text" id="r_database_path" name="_replacements[server_post][database_path]" />
&nbsp; <em>##database_path##</em></li>

<li><label for="r_email_path">E-mail mount point:</label>
<input type="text" id="r_email_path" name="_replacements[server_post][email_path]" />
&nbsp; <em>##email_path##</em></li>

<li><label for="r_webserver_letter">Webserver volume letter:</label>
<select id="r_webserver_letter" name="_replacements[server_post][webserver_letter]">
<option value=""></option>
<option value="c">c</option>
<option value="d">d</option>
<option value="e">e</option>
<option value="f">f</option>
<option value="g">g</option>
<option value="h">h</option>
<option value="i">i</option>
<option value="j">j</option>
<option value="k">k</option>
<option value="l">l</option>
<option value="m">m</option>
<option value="n">n</option>
<option value="o">o</option>
<option value="p">p</option>
</select>
&nbsp; <em>##webserver_letter##</em></li>

<li><label for="r_database_letter">Database volume letter:</label>
<select id="r_database_letter" name="_replacements[server_post][database_letter]">
<option value=""></option>
<option value="c">c</option>
<option value="d">d</option>
<option value="e">e</option>
<option value="f">f</option>
<option value="g">g</option>
<option value="h">h</option>
<option value="i">i</option>
<option value="j">j</option>
<option value="k">k</option>
<option value="l">l</option>
<option value="m">m</option>
<option value="n">n</option>
<option value="o">o</option>
<option value="p">p</option>
</select>
&nbsp; <em>##database_letter##</em></li>

<li><label for="r_email_letter">E-mail volume letter:</label>
<select id="r_email_letter" name="_replacements[server_post][email_letter]">
<option value=""></option>
<option value="c">c</option>
<option value="d">d</option>
<option value="e">e</option>
<option value="f">f</option>
<option value="g">g</option>
<option value="h">h</option>
<option value="i">i</option>
<option value="j">j</option>
<option value="k">k</option>
<option value="l">l</option>
<option value="m">m</option>
<option value="n">n</option>
<option value="o">o</option>
<option value="p">p</option>
</select>
&nbsp; <em>##email_letter##</em></li>

<li><label for="r_vmail_user">Vmail user:</label>
<input type="text" id="r_vmail_user" name="_replacements[server_post][vmail_user]" />
&nbsp; <em>##vmail_user##</em></li>

<li><label for="r_vmail_group">Vmail group:</label>
<input type="text" id="r_vmail_group" name="_replacements[server_post][vmail_group]" />
&nbsp; <em>##vmail_group##</em></li>

<li><label for="r_vmail_db">Vmail database:</label>
<input type="text" id="r_vmail_db" name="_replacements[server_post][vmail_db]" />
&nbsp; <em>##vmail_db##</em></li>

<li><label for="r_vmail_db_user">Vmail database user:</label>
<input type="text" id="r_vmail_db_user" name="_replacements[server_post][vmail_db_user]" />
&nbsp; <em>##vmail_db_user##</em></li>

<li><label for="r_ec2_keypair_ext">EC2 Key Pair ext:</label>
<input type="text" id="r_ec2_keypair_ext" name="_replacements[server_post][ec2_keypair_ext]" />
&nbsp; <em>##ec2_keypair_ext##</em></li>

<li><label for="r_ec2_keypair_ext_ms">EC2 Key Pair ext (Windows):</label>
<input type="text" id="r_ec2_keypair_ext_ms" name="_replacements[server_post][ec2_keypair_ext_ms]" />
&nbsp; <em>##ec2_keypair_ext_ms##</em></li>

<li><label>&nbsp;</label>
<input type="submit" name="_replacements[server_post][submit]" class="button" style="float: left; margin-right: 5px;" value="Update" /> <input type="submit" name="_replacements[server_post][reset_guess]" class="button" style="float: left; margin-right: 5px;" value="Reset" /> <input type="submit" name="_replacements[server_post][reset_all]" class="button" style="float: left" value="Reset All" /></li>

</fieldset>

</form>

##previous-next-page-3##

##contents##

##previous-next-page-3##]]></content:encoded>
			<wfw:commentRss>http://www.paul-norman.co.uk/2011/02/customise-this-guide/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>EC2 Guide: Preparing required tools (2 / 7)</title>
		<link>http://www.paul-norman.co.uk/2011/02/preparing-required-tools/</link>
		<comments>http://www.paul-norman.co.uk/2011/02/preparing-required-tools/#comments</comments>
		<pubDate>Mon, 28 Feb 2011 23:43:57 +0000</pubDate>
		<dc:creator>Paul Norman</dc:creator>
				<category><![CDATA[Server]]></category>
		<category><![CDATA[Amazon AWS]]></category>
		<category><![CDATA[Cloud]]></category>
		<category><![CDATA[EBS]]></category>
		<category><![CDATA[EC2]]></category>
		<category><![CDATA[Elasticfox]]></category>
		<category><![CDATA[Ubuntu 10.04]]></category>

		<guid isPermaLink="false">http://www.paul-norman.co.uk/?p=47</guid>
		<description><![CDATA[This guide will hopefully allow you to prepare all the tools you will need to create and Amazon EC2 EBS backed Ubuntu 10.04 instance using Elasticfox.]]></description>
			<content:encoded><![CDATA[##previous-next-page-2##

<p>If you are using Amazon EC2 the following steps are necessary, but if not (i.e. you are just following this guide to set up a server) please skip this page and install Ubuntu 10.04 Lucid Lynx (LTS) from a DVD.</p>

<h2>Register with Amazon AWS</h2>

<p>I&#8217;m not going to go into detail for the actual registration of services, but you need a credit / debit card, a valid e-mail address and a phone(!). It takes a while to get all of it done / activated, and there are several services you can use, but for now only EC2 <em>needs</em> configuring.</p>

<p>There are several pieces of information that are required to manage your instances and they are configured / obtained in the <a href="https://aws-portal.amazon.com/gp/aws/developer/account/index.html?ie=UTF8&#038;action=access-key" title="AWS Security Credentials" target="_blank">Security Credentials</a> section of your Amazon account. You will need to create and write down / save:</p>

<ul>
<li>Your Access Key ID (under Access Keys e.g. ##aws_access_key_id##)</li>
<li>Your Secret Access Key (under Access Keys  e.g. ##aws_secret_access_key##)</li>
<li>Your X.509 Certificate (under X.509 Certificates  e.g. ##ec2_cert_filename##)</li>
<li>Your Private Key (under X.509 Certificates  e.g. ##ec2_pk_filename##)</li>
</ul>

<h2>Install Firefox / Elasticfox</h2>

<p>If you don&#8217;t use Firefox then please <a href="http://www.mozilla.com/en-US/firefox/" title="Get Firefox" target="_blank">download</a> the latest version. Because Amazon haven&#8217;t maintained Elasticfox for quite some time I no longer use the <a href="http://aws.amazon.com/developertools/609?_encoding=UTF8&#038;jiveRedirect=1" title="Get Elasticfox" target="_blank">official one</a>, instead I recommend you install this <a href="http://www.eaglegenomics.com/2011/05/elasticfox-aws-ec2-add-on-for-firefox-4-with-t1-micro-instance-support/" title="Get Elasticfox" target="_blank">enhancement of Elasticfox</a> which is a simple and bug free tool to manage all things <acronym title="Amazon Web Services">AWS</acronym>. To add it to Firefox:</p>

<ul>
<li>Open Firefox</li>
<li>Select File -&gt; Open File (Ctrl + O or Cmd + O)</li>
<li>Browse to the extension and select Open</li>
<li>Choose Install Now</li>
</ul>

<h2>Configure Elastic Fox</h2>

<p>Launch Elasticfox by opening Firefox and selecting Tools -&gt; Elasticfox &#8211; N.B. it is not under the Ad-ons section, it has it&#8217;s own button. You should be prompted to enter your AWS credentials. You can enter new details or modify existing ones by clicking on the
&#8220;Credentials&#8221; button in the top centre of the Elasticfox window:</p>

<ul>
<li>Enter your Account Name, this can be anything you want</li>
<li>Enter your Access Key (##aws_access_key_id##) and Secret Key (##aws_secret_access_key##)</li>
<li>Press Add</li>
<li>Press Close</li>
</ul>

<p>You now need to create a Key Pair:</p>

<ul>
<li>Click on the &#8220;KeyPairs&#8221; tab in Elasticfox</li>
<li>Click on the green Key icon at the top of the tab</li>
<li>Give your Key Pair a name (##ec2_keypair_name##)</li>
<li>Press Ok</li>
<li>You will be prompted for a location to save the .pem file</li>
<li>Press Save</li>
</ul>

<h2>Download PuTTY / PuTTYgen (Windows only)</h2>

<p>To manage your instance you will need and SSH tool and for Windows systems that basically means <a href="http://the.earth.li/~sgtatham/putty/latest/x86/putty.exe" title="Download PuTTY" target="_blank">PuTTY</a>, so please grab a copy, it&#8217;s free (and legal in most countries &#8211; please check yours!).</p>

<p>The Key Pair file that you created earlier (##ec2_keypair_name####ec2_keypair_ext##) is sadly not compatible with PuTTY, but it does have a tool to convert it into a usable format called <a href="http://the.earth.li/~sgtatham/putty/latest/x86/puttygen.exe" title="Download PuTTYgen" target="_blank">PuTTYgen</a>. Download this too, run it, load in your key file (you might need to select &#8220;All Files&#8221; under the &#8220;Files of Type&#8221; dropdown) and press Generate. Save this new key (##ec2_keypair_name####ec2_keypair_ext_ms##) with your original (##ec2_keypair_name####ec2_keypair_ext##) &#8211; don&#8217;t delete either!</p>


<h2>Configure Elasticfox SSH</h2>

<p>Launch Elasticfox and visit the Tools panel in the top right of the Elasticfox window.</p>

<h3>Windows</h3>

<p>Update the following:</p>

<ul>
<li>SSH Command: ##ec2_putty_path##putty.exe</li>
<li>SSH Key Template: ##ec2_key_path_ms####ec2_keypair_name####ec2_keypair_ext_ms##</li>
<li>EC2 Private Key Template: ##ec2_key_path_ms####ec2_keypair_name####ec2_keypair_ext_ms##</li>
<li>SSH User: ubuntu</li>
</ul>

<h3>Linux / OSX</h3>

<p>Update the following:</p>

<ul>
<li>SSH Key Template: ##ec2_key_path####ec2_keypair_name####ec2_keypair_ext##</li>
<li>EC2 Private Key Template: ##ec2_key_path####ec2_keypair_name####ec2_keypair_ext##</li>
<li>SSH User: ubuntu</li>
</ul>

<h2>Choose a Region and Availability Zone</h2>

<p>These should be a reasonably easy choice, but still one that needs making. There are at the time of writing 5 main regions each with several availability zones:</p>

<ul>
<li>US East (Northern Virginia): <strong>us-east-1</strong>, with zones: <em>us-east-1a, us-east-1b, us-east-1c, us-east-1d</em></li>
<li>US West (Northern California): <strong>us-west-1</strong>, with zones: <em>us-west-1a, us-west-1b, us-west-1c</em></li>
<li>EU (Ireland): <strong>eu-west-1</strong>, with zones: <em>eu-west-1a, eu-west-1b, eu-west-1c</em></li>
<li>Asia Pacific (Singapore): <strong>ap-southeast-1</strong>, with zones: <em>ap-southeast-1a, ap-southeast-1b</em></li>
<li>Asia Pacific (Japan): <strong>ap-northeast-1</strong>, with zones: <em>ap-northeast-1a, ap-northeast-1b</em></li>
</ul>

<p>Now, if you were using this in an enterprise environment you would probably want multiple servers in at least two of these regions so that if one malfunctioned the other could take over sole operation. However, given we are interested in a single server set up for now, it&#8217;s best just to choose a region / zone nearest to you / your audience and stick with it. In Elasticfox just choose your option from the top left drop down menu.</p> 

<h2>Define Security Group(s)</h2>

<p>A Security Group is a set of rules applied to an instance defining what ports are available to who. In general this boils down to 5 options per port, it is either: <em>closed, open to the internal Amazon network, open to an IP of your choice, open to everyone or open to a combination of the last 3 options</em>. It is easiest to understand with a couple of examples:</p>

<ol>
<li>Apache (the web-server) allows people to view web pages on port 80 (http://) or port 443 (https://) by default. It is likely that you want both of these options available to everybody, so you would set unrestricted access (0.0.0.0/0) to these two ports.</li>
<li>SSH (the secure shell) allows you to connect to your server to manage it directly on port 22 by default. It is likely that you want this option only available to you on your IP only, so you would restrict access to only your IP address (##current_ip##/32) on this port</li>
<li>If you had a separate MySQL database server it would accept requests on port 3306 by default. You would need to let your web-server connect to it, but in this instance it would be wise to restrict access to only internal cloud machines (10.0.0.0/8). You could also allow your IP (##current_ip##/32) direct access or of course allow everyone (0.0.0.0/0) if you had a non-cloud based server requiring access.</li>
</ol>

<p>You only need one security group, but as mentioned previously there may come a time when you would like to separate your server into different parts. So I created 5 security groups which would allow a combo server set up (add all 5 groups) or individualised servers (with only the necessary groups added). My groups were:</p>

<h3>Web-server</h3>

<table>
<thead>
<tr>
<th>Protocol</th>
<th>From Port / ICMP Type</th>
<th>To Port / ICMP Code</th>
<th>Source User: Group</th>
<th>Source CIDR</th>
</tr>
</thead>
<tbody>
<tr>
<td>tcp</td>
<td>80</td>
<td>80</td>
<td></td>
<td>0.0.0.0/0</td>
</tr>
<tr>
<td>tcp</td>
<td>443</td>
<td>443</td>
<td></td>
<td>0.0.0.0/0</td>
</tr>
</tbody>
</table>

<h3>Database Server</h3>

<table>
<thead>
<tr>
<th>Protocol</th>
<th>From Port / ICMP Type</th>
<th>To Port / ICMP Code</th>
<th>Source User: Group</th>
<th>Source CIDR</th>
</tr>
</thead>
<tbody>
<tr>
<td>tcp</td>
<td>3306</td>
<td>3306</td>
<td></td>
<td>10.0.0.0/8</td>
</tr>
</tbody>
</table>

<h3>E-mail Server</h3>

<table>
<thead>
<tr>
<th>Protocol</th>
<th>From Port / ICMP Type</th>
<th>To Port / ICMP Code</th>
<th>Source User: Group</th>
<th>Source CIDR</th>
</tr>
</thead>
<tbody>
<tr>
<td>tcp</td>
<td>25</td>
<td>25</td>
<td></td>
<td>0.0.0.0/0</td>
</tr>
<tr>
<td>tcp</td>
<td>110</td>
<td>110</td>
<td></td>
<td>0.0.0.0/0</td>
</tr>
<tr>
<td>tcp</td>
<td>143</td>
<td>143</td>
<td></td>
<td>0.0.0.0/0</td>
</tr>
<tr>
<td>tcp</td>
<td>465</td>
<td>465</td>
<td></td>
<td>0.0.0.0/0</td>
</tr>
<tr>
<td>tcp</td>
<td>993</td>
<td>993</td>
<td></td>
<td>0.0.0.0/0</td>
</tr>
<tr>
<td>tcp</td>
<td>995</td>
<td>995</td>
<td></td>
<td>0.0.0.0/0</td>
</tr>
</tbody>
</table>

<h3>SSH / SFTP / RDP</h3>

<table>
<thead>
<tr>
<th>Protocol</th>
<th>From Port / ICMP Type</th>
<th>To Port / ICMP Code</th>
<th>Source User: Group</th>
<th>Source CIDR</th>
</tr>
</thead>
<tbody>
<tr>
<td>tcp</td>
<td>22</td>
<td>22</td>
<td></td>
<td>##current_ip##/32</td>
</tr>
<tr>
<td>tcp</td>
<td>3389</td>
<td>3389</td>
<td></td>
<td>##current_ip##/32</td>
</tr>
</tbody>
</table>

<h3>FTP (optional)</h3>

<table>
<thead>
<tr>
<th>Protocol</th>
<th>From Port / ICMP Type</th>
<th>To Port / ICMP Code</th>
<th>Source User: Group</th>
<th>Source CIDR</th>
</tr>
</thead>
<tbody>
<tr>
<td>tcp</td>
<td>21</td>
<td>22</td>
<td></td>
<td>##current_ip##/32</td>
</tr>
</tbody>
</table>

<p>You can then load these in any combination you like to create servers fit for most purposes.</p>


<h2>Assign and Whitelist an Elastic IP</h2>

<p>Your machine will need an ip address (##ip##) so that you can configure your zone files and point your domain to it. This is very easy to do in Elasticfox:</p>

<ul>
<li>Visit the &#8220;Elastic IPs&#8221; tab</li>
<li>Click the green plus button to allocate a new IP address</li>
<li>When the IP address appears right click it and choose &#8220;Copy Elastic IP to Clipboard&#8221;</li>
</ul>

<p>Until relatively recently Amazon had real trouble with ip blacklisting (especially bad for e-mails), but they now have a process in place which whitelists a new IP for you within a few days. For this to happen you need to fill out a <a href="https://aws-portal.amazon.com/gp/aws/html-forms-controller/contactus/ec2-email-limit-rdns-request" title="Request to Remove Email Sending Limitations" target="_blank">use case request form</a> to remove sending restrictions. It only takes a minute or two to inform them of your intentions and get your IP whitelisted.</p> 


<h2>Choose an Instance Size and AMI file</h2>

<p>Before you can launch an instance you must first decide <a href="http://aws.amazon.com/ec2/instance-types/" title="Choose your instance type" target="_blank">which type you need</a>, there are many available and all have <a href="http://aws.amazon.com/ec2/pricing/" title="Instance pricing" target="_blank">different costs</a> associated with them so it&#8217;s best not to be greedy! One key matter to consider is that some are 32 bit and some are 64 bit. This will dictate which AMI you choose to run.</p>

<p>Once you have made your choice you can visit Ubuntu&#8217;s AMI list and choose the right one for you. Choose the correct (either 64 bit or 32 bit) EBS backed version for your chosen region and copy the AMI reference down.</p>


<h2>Launch an AMI</h2>

<p>Launching an AMI file is quite straightforward. In Elasticfox:</p>

<ul>
<li>Select the &#8220;Images&#8221; tab</li>
<li>Type (or paste) your chosen Ubuntu AMI reference into the search box</li>
<li>Right click the one remaining file and choose &#8220;Launch Instance(s) of this AMI&#8221;</li>
<li>A popup box will appear</li>
<li>In the KeyPair field, select the KeyPair you created earlier (##ec2_keypair_name##)</li>
<li>In the Security Groups section, select the appropriate group and click on the right arrow to move it into the Launch in box. <strong>Do this from bottom to top because Elasticfox has a bug here where groups appear as undefined!</strong></li>
<li>Press Launch</li>
</ul>

<h3>Associate your Elastic IP</h3>

<ul>
<li>Select the &#8220;Instances&#8221; tab (your new instance should appear there)</li>
<li>Wait for the status to update to &#8220;running&#8221;</li>
<li>Right click the instance row</li>
<li>Select &#8220;Associate Elastic IP with Instance&#8221;</li>
<li>Select your IP from the dropdown</li>
<li>Press &#8220;Associate&#8221;</li>
<li>Wait for 30 seconds or so</li>
</ul>


<h3>Connect to your Instance</h3>

<ul>
<li>Right click the instance row again</li>
<li>Select &#8220;Connect to Instance&#8221;</li>
<li>You may need to point to your key file (Windows: ##ec2_key_path_ms####ec2_keypair_name####ec2_keypair_ext_ms##, Linux: ##ec2_key_path####ec2_keypair_name####ec2_keypair_ext##)</li>
</ul>

<p>You should now see a terminal window open and be logged in to your server!</p>

##previous-next-page-2##

##download##

##contents##

##previous-next-page-2##]]></content:encoded>
			<wfw:commentRss>http://www.paul-norman.co.uk/2011/02/preparing-required-tools/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>EC2 Guide: Hosting a website on Amazon EC2 (1 / 7)</title>
		<link>http://www.paul-norman.co.uk/2011/02/hosting-a-website-on-amazon-ec2/</link>
		<comments>http://www.paul-norman.co.uk/2011/02/hosting-a-website-on-amazon-ec2/#comments</comments>
		<pubDate>Mon, 28 Feb 2011 23:42:28 +0000</pubDate>
		<dc:creator>Paul Norman</dc:creator>
				<category><![CDATA[Server]]></category>
		<category><![CDATA[Cloud]]></category>
		<category><![CDATA[EBS]]></category>
		<category><![CDATA[EC2]]></category>
		<category><![CDATA[Ubuntu 10.04]]></category>

		<guid isPermaLink="false">http://www.paul-norman.co.uk/?p=46</guid>
		<description><![CDATA[This guide will hopefully allow anyone to create an Ubuntu 10.04 EBS backed Amazon EC2 instance and guide a relative novice through all the steps required to configure a production server running in the cloud environment.]]></description>
			<content:encoded><![CDATA[##previous-next-page-1##

<p>The <a href="http://aws.amazon.com/ec2/" title="More information on Amazon EC2" target="_blank">Amazon Elastic Compute Cloud</a> (Amazon EC2) is a web-service allowing companies or individuals to create / run / manage virtual servers (called instances) on their hardware infrastructure. It allows a choice of most operating systems and a range of <a href="http://aws.amazon.com/ec2/instance-types/" title="EC2 instance types" target="_blank">virtual hardware configurations</a>, so if you wanted lots of processing power you could choose a High CPU instance or for a database server you may choose a High Memory instance. You can of course change instance type with ease. To make this better it allows you to <a href="http://aws.amazon.com/ec2/pricing/" title="EC2 pricing" target="_blank">only pay for what you use</a> by the hour and allows creation / destruction of new instances in seconds. It also offers extreme scalability, data storage and fault tolerance. In short it&#8217;s a pretty good service!</p>

<p>Until relatively recently (Dec 2009) the instances were not persistent, that is any data you required on a server had to be (re-)created (by scripts) each time a machine was created / rebooted or crashed. This was, and still is, fine for compute intensive batch jobs such as photo processing or number crunching where you create a machine instance, pass it some data and it will give you back the output. That was (essentially) the end of the server&#8217;s life. Obviously for a website this kind of arrangement is far from ideal. Thankfully Amazon addressed this issue and created a product called <a href="http://aws.amazon.com/ebs/" title="More information on EBS" target="_blank">Elastic Block Store</a> (EBS) for this task. A year on and many gremlins have been ironed out and this is now suitable for production website deployment.</p>

<h2>Aims of this guide</h2>

<p>This guide is <strong>not</strong> solely dedicated to creating an EBS backed Amazon EC2 instance, that would take a few seconds and wouldn&#8217;t really help many people. It is instead designed to guide a relative novice through all the steps required to configure a production <strong>Ubuntu 10.04 Lucid Lynx (LTS)</strong> server running in the cloud environment. Much of this guide will work on other Linux flavours with certain changes, but I have only tested it on Ubuntu 10.04. Debian based systems will require relatively minor tweaks while RPM / Gentoo / Slackware based distros would require significant code updates (although conceptually it is similar). Likewise it is not required that your server is running in the cloud, but there is some cloud specific content in the guide.</p>

<h2>Server Configuration and Scalability</h2>

<p>With a small website it is likely that you will only need one server and the size of that will be dictated by your site traffic / server load. As a site grows and more demand is put on the server there eventually becomes a point where you have to make a change. There are a couple of options here:</p>

<ul>
<li>Increase the power of the single server</li>
<li>Separate the server parts i.e. have multiple servers, most commonly mail-server(s), web-server(s), database server(s)</li>
</ul>

<p>Even if you have a site with low traffic it&#8217;s always prudent to plan for the best and have an idea of what to do when the day comes where your server can no longer cope. Amazon EC2 allows an upgrade to a larger instance very quickly, but ultimately you run out of larger instances to use when you hit their <em>Extra Large Instance</em> and become stuck with migration difficulties.</p>

<p>Again Amazon EC2 offers a unique solution to this issue, their EBS storage. It doesn&#8217;t just have to be for machine images, EBS volumes can be used essentially as detachable hard disks. This means that you can separate all core (config and data) files for the web-server (e.g. Apache / PHP, site data, vhosts etc), mail-server (e.g. Postfix / Dovecot, e-mails etc) and a database server (e.g. config and data) onto separate &#8220;drives&#8221; and if the situation ever arises where the server cannot cope you simply detach the required EBS volume from one instance and attach it to another making minimal configuration changes. You can of course copy EBS volumes quickly too and Amazon offers a load balancer if multiple web-servers are used.</p>

<p>Obviously I don&#8217;t want to force this choice on anyone (because it does cost a few dollars a month extra) so I have set this up in such a way as it is <strong>completely optional</strong> to to this. Just follow the relevant section of the guide to your needs.</p>

<h2>Requirements</h2>

<ul>
<li>You use either <a href="http://releases.ubuntu.com/lucid/">Ubuntu 10.04 Lucid Lynx (LTS)</a> (non-cloud) or an EBS backed <a href="http://uec-images.ubuntu.com/releases/10.04/release/" title="Visit the Ubuntu AMIs page" target="blank">Ubuntu 10.04 Lucid Lynx (LTS) AMI</a></li>
<li>You have a basic knowledge of <a href="http://www.debianhelp.co.uk/commands.htm" title="Basic Linux commands" target="_blank">Linux commands</a> (i.e. you can use a terminal and an editor of your choice)</li>
<li>You are aware of <a href="http://www.zzee.com/solutions/linux-permissions.shtml" title="File permissions in Linux" target="_blank">file permissions in Linux</a></li>
<li>You have a domain (##domain##) to use</li>
<li>You understand the difference between a <a href="http://en.wikipedia.org/wiki/Domain_name" title="What is a domain?" target="_blank">domain</a> (##domain##) and a <a href="http://en.wikipedia.org/wiki/Subdomain" title="What is a sub-domain?" target="_blank">sub-domain</a> (e.g. www)</li>
<li>You have your own <a href="http://en.wikipedia.org/wiki/Nameserver" title="What is a nameserver?" target="_blank">nameservers</a> (most registrars provide them)</li>
<li>You understand what <a href="http://en.wikipedia.org/wiki/Domain_Name_System" title="What is DNS?" target="_blank">DNS</a> is and how to configure your <a href="http://en.wikipedia.org/wiki/Zone_file" title="What is a zone file?" target="_blank">zone file</a> to point to your new server for testing (most registrars offer a <acronym title="Graphical User Interface">GUI</acronym> tool for this)</li>
</ul>

##contents##

##download##

##previous-next-page-1##]]></content:encoded>
			<wfw:commentRss>http://www.paul-norman.co.uk/2011/02/hosting-a-website-on-amazon-ec2/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Regex &#8211; match anything but a string</title>
		<link>http://www.paul-norman.co.uk/2010/09/regex-match-anything-but-a-string/</link>
		<comments>http://www.paul-norman.co.uk/2010/09/regex-match-anything-but-a-string/#comments</comments>
		<pubDate>Wed, 22 Sep 2010 15:26:40 +0000</pubDate>
		<dc:creator>Paul Norman</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Negative lookahead]]></category>
		<category><![CDATA[Regex]]></category>

		<guid isPermaLink="false">http://www.paul-norman.co.uk/2010/09/regex-match-anything-but-a-string/</guid>
		<description><![CDATA[Regular expressions are something of a black art for programmers, and many get by without ever really learning them properly. Sure, most people will be able to use them to some level, but if you don&#8217;t use them for complex tasks in your day to day work you&#8217;ll never really need their advanced functionality. I]]></description>
			<content:encoded><![CDATA[<p>Regular expressions are something of a black art for programmers, and many get by without ever <strong>really</strong> learning them properly. Sure, most people will be able to use them to some level, but if you don&#8217;t use them for complex tasks in your day to day work you&#8217;ll never really need their advanced functionality. I sadly fell into this camp the other day when I needed to say &#8216;match everything except a whole word.&#8217; This sounds easy doesn&#8217;t it, but actually it&#8217;s less obvious than it seems&#8230;</p>

<p>If I want to exclude an individual letter or number it&#8217;s an easy task, let&#8217;s say I wanted to match everything from the start of a string up until either a &#8216;z&#8217; or a &#8217;7&#8242;:</p>

<div class="codecolorer-container php default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="php codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000088;">$text</span><span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">'The quick brown fox jumped over the lazy dog'</span><span style="color: #339933;">;</span><br />
<span style="color: #000088;">$text</span><span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">'0 seven 3 four 9 six 7 four 2'</span><span style="color: #339933;">;</span><br />
<br />
<span style="color: #b1b100;">foreach</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$text</span> <span style="color: #b1b100;">as</span> <span style="color: #000088;">$value</span><span style="color: #009900;">&#41;</span><br />
<span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">echo</span> <span style="color: #0000ff;">'&lt;p&gt;Considering: '</span><span style="color: #339933;">.</span><span style="color: #000088;">$value</span><span style="color: #339933;">.</span><span style="color: #0000ff;">'&lt;br /&gt;'</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">preg_match</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'~^([^z7]*)~s'</span><span style="color: #339933;">,</span> <span style="color: #000088;">$value</span><span style="color: #339933;">,</span> <span style="color: #000088;">$matches</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">echo</span> <span style="color: #0000ff;">'Found: '</span><span style="color: #339933;">.</span><span style="color: #000088;">$matches</span><span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">1</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">echo</span> <span style="color: #0000ff;">'&lt;/p&gt;'</span><span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span></div></div>

<p>Produces:</p>

<p><i>Considering: The quick brown fox jumped over the lazy dog<br />
Found: The quick brown fox jumped over the la</i></p>

<p><i>Considering: 0 seven 3 four 9 six 7 four 2<br />
Found: 0 seven 3 four 9 six </i></p>

<p>Now what if I wanted to do the same for the word &#8216;lazy&#8217; or &#8216;six&#8217; in the same phrases? It&#8217;s not hard either, but it&#8217;s not obvious:</p>

<div class="codecolorer-container php default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="php codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000088;">$text</span><span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">'The quick brown fox jumped over the lazy dog'</span><span style="color: #339933;">;</span><br />
<span style="color: #000088;">$text</span><span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">'0 seven 3 four 9 six 7 four 2'</span><span style="color: #339933;">;</span><br />
<br />
<span style="color: #b1b100;">foreach</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$text</span> <span style="color: #b1b100;">as</span> <span style="color: #000088;">$value</span><span style="color: #009900;">&#41;</span><br />
<span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">echo</span> <span style="color: #0000ff;">'&lt;p&gt;Considering: '</span><span style="color: #339933;">.</span><span style="color: #000088;">$value</span><span style="color: #339933;">.</span><span style="color: #0000ff;">'&lt;br /&gt;'</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">preg_match</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'~^((?:(?!lazy|six).)*)~s'</span><span style="color: #339933;">,</span> <span style="color: #000088;">$value</span><span style="color: #339933;">,</span> <span style="color: #000088;">$matches</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">echo</span> <span style="color: #0000ff;">'Found: '</span><span style="color: #339933;">.</span><span style="color: #000088;">$matches</span><span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">1</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">echo</span> <span style="color: #0000ff;">'&lt;/p&gt;'</span><span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span></div></div>

<p>Produces:</p>

<p><i>Considering: The quick brown fox jumped over the lazy dog<br />
Found: The quick brown fox jumped over the</i></p>

<p><i>Considering: 0 seven 3 four 9 six 7 four 2<br />
Found: 0 seven 3 four 9 </i></p>

<p>This uses something called a <a href="http://www.regular-expressions.info/lookaround.html" title="Learn about positive and negative lookaheads">negative lookahead</a> (?!) preceeding the dot (any character) which I&#8217;ve told not to be included in a match (?:). Simples.</p>

<p>Hope this saves someone the time it took me to read up on!</p>]]></content:encoded>
			<wfw:commentRss>http://www.paul-norman.co.uk/2010/09/regex-match-anything-but-a-string/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>PHP Spinner Updated &#8211; Spin articles for SEO</title>
		<link>http://www.paul-norman.co.uk/2010/09/php-spinner-updated-spin-articles-for-seo/</link>
		<comments>http://www.paul-norman.co.uk/2010/09/php-spinner-updated-spin-articles-for-seo/#comments</comments>
		<pubDate>Wed, 22 Sep 2010 13:53:14 +0000</pubDate>
		<dc:creator>Paul Norman</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[SEO]]></category>
		<category><![CDATA[Article spinner]]></category>
		<category><![CDATA[Nested Spinner]]></category>
		<category><![CDATA[SEO spinner]]></category>
		<category><![CDATA[Spinner]]></category>

		<guid isPermaLink="false">http://www.paul-norman.co.uk/2010/09/php-spinner-updated-spin-articles-for-seo/</guid>
		<description><![CDATA[Quite a while ago I wrote a post on spinning text using PHP to create lots of fresh content from one single block of marked up text. I actually had use for a nested version of this spinning code the other day so set about creating a more efficient version of my previous nested spin]]></description>
			<content:encoded><![CDATA[<p>Quite a while ago I wrote a <a href="http://www.paul-norman.co.uk/2009/06/spin-text-for-seo/" title="View the original post">post on spinning text using PHP</a> to create lots of fresh content from one single block of marked up text. I actually had use for a nested version of this spinning code the other day so set about creating a more efficient version of my previous nested spin code and packed it up in a class wrapper so it would choose whether to use the nested spinner or the flat version dynamically.</p>

<p>Without further ado here is the new PHP Spinner code.</p>

<div class="codecolorer-container php default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;height:400px;"><div class="php codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">class</span> Spinner<br />
<span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #666666; font-style: italic;"># Detects whether to use the nested or flat version of the spinner (costs some speed)<br />
</span>&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> static <span style="color: #000000; font-weight: bold;">function</span> detect<span style="color: #009900;">&#40;</span><span style="color: #000088;">$text</span><span style="color: #339933;">,</span> <span style="color: #000088;">$seedPageName</span> <span style="color: #339933;">=</span> <span style="color: #009900; font-weight: bold;">true</span><span style="color: #339933;">,</span> <span style="color: #000088;">$openingConstruct</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">'{{'</span><span style="color: #339933;">,</span> <span style="color: #000088;">$closingConstruct</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">'}}'</span><span style="color: #339933;">,</span> <span style="color: #000088;">$separator</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">'|'</span><span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">preg_match</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'~'</span><span style="color: #339933;">.</span><span style="color: #000088;">$openingConstruct</span><span style="color: #339933;">.</span><span style="color: #0000ff;">'(?:(?!'</span><span style="color: #339933;">.</span><span style="color: #000088;">$closingConstruct</span><span style="color: #339933;">.</span><span style="color: #0000ff;">').)*'</span><span style="color: #339933;">.</span><span style="color: #000088;">$openingConstruct</span><span style="color: #339933;">.</span><span style="color: #0000ff;">'~s'</span><span style="color: #339933;">,</span> <span style="color: #000088;">$text</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">return</span> <span style="color: #000000; font-weight: bold;">self</span><span style="color: #339933;">::</span><span style="color: #004000;">nested</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$text</span><span style="color: #339933;">,</span> <span style="color: #000088;">$seedPageName</span><span style="color: #339933;">,</span> <span style="color: #000088;">$openingConstruct</span><span style="color: #339933;">,</span> <span style="color: #000088;">$closingConstruct</span><span style="color: #339933;">,</span> <span style="color: #000088;">$separator</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">else</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">return</span> <span style="color: #000000; font-weight: bold;">self</span><span style="color: #339933;">::</span><span style="color: #004000;">flat</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$text</span><span style="color: #339933;">,</span> <span style="color: #000088;">$seedPageName</span><span style="color: #339933;">,</span> <span style="color: #009900; font-weight: bold;">false</span><span style="color: #339933;">,</span> <span style="color: #000088;">$openingConstruct</span><span style="color: #339933;">,</span> <span style="color: #000088;">$closingConstruct</span><span style="color: #339933;">,</span> <span style="color: #000088;">$separator</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #666666; font-style: italic;"># The flat version does not allow nested spin blocks, but is much faster (~2x)<br />
</span>&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> static <span style="color: #000000; font-weight: bold;">function</span> flat<span style="color: #009900;">&#40;</span><span style="color: #000088;">$text</span><span style="color: #339933;">,</span> <span style="color: #000088;">$seedPageName</span> <span style="color: #339933;">=</span> <span style="color: #009900; font-weight: bold;">true</span><span style="color: #339933;">,</span> <span style="color: #000088;">$calculate</span> <span style="color: #339933;">=</span> <span style="color: #009900; font-weight: bold;">false</span><span style="color: #339933;">,</span> <span style="color: #000088;">$openingConstruct</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">'{{'</span><span style="color: #339933;">,</span> <span style="color: #000088;">$closingConstruct</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">'}}'</span><span style="color: #339933;">,</span> <span style="color: #000088;">$separator</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">'|'</span><span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #666666; font-style: italic;"># Choose whether to return the string or the number of permutations<br />
</span>&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000088;">$return</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">'text'</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$calculate</span><span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000088;">$permutations</span> &nbsp; <span style="color: #339933;">=</span> <span style="color: #cc66cc;">1</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000088;">$return</span> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #339933;">=</span> <span style="color: #0000ff;">'permutations'</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #666666; font-style: italic;"># If we have nothing to spin just exit (don't use a regexp)<br />
</span>&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">strpos</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$text</span><span style="color: #339933;">,</span> <span style="color: #000088;">$openingConstruct</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">===</span> <span style="color: #009900; font-weight: bold;">false</span><span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">return</span> <span style="color: #000088;">$$return</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">preg_match_all</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'!'</span><span style="color: #339933;">.</span><span style="color: #000088;">$openingConstruct</span><span style="color: #339933;">.</span><span style="color: #0000ff;">'(.*?)'</span><span style="color: #339933;">.</span><span style="color: #000088;">$closingConstruct</span><span style="color: #339933;">.</span><span style="color: #0000ff;">'!s'</span><span style="color: #339933;">,</span> <span style="color: #000088;">$text</span><span style="color: #339933;">,</span> <span style="color: #000088;">$matches</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #666666; font-style: italic;"># Optional, always show a particular combination on the page<br />
</span>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">self</span><span style="color: #339933;">::</span><span style="color: #004000;">checkSeed</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$seedPageName</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000088;">$find</span> &nbsp; &nbsp; &nbsp; <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000088;">$replace</span>&nbsp; &nbsp; <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">foreach</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$matches</span><span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">0</span><span style="color: #009900;">&#93;</span> <span style="color: #b1b100;">as</span> <span style="color: #000088;">$key</span> <span style="color: #339933;">=&gt;</span> <span style="color: #000088;">$match</span><span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000088;">$choices</span> <span style="color: #339933;">=</span> <span style="color: #990000;">explode</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$separator</span><span style="color: #339933;">,</span> <span style="color: #000088;">$matches</span><span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">1</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$key</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$calculate</span><span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000088;">$permutations</span> <span style="color: #339933;">*=</span> <span style="color: #990000;">count</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$choices</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">else</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000088;">$find</span><span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span> &nbsp; &nbsp; <span style="color: #339933;">=</span> <span style="color: #000088;">$match</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000088;">$replace</span><span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span>&nbsp; <span style="color: #339933;">=</span> <span style="color: #000088;">$choices</span><span style="color: #009900;">&#91;</span><span style="color: #990000;">mt_rand</span><span style="color: #009900;">&#40;</span><span style="color: #cc66cc;">0</span><span style="color: #339933;">,</span> <span style="color: #990000;">count</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$choices</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">-</span> <span style="color: #cc66cc;">1</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span><span style="color: #000088;">$calculate</span><span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #666666; font-style: italic;"># Ensure multiple instances of the same spinning combinations will spin differently<br />
</span>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000088;">$text</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">self</span><span style="color: #339933;">::</span><span style="color: #004000;">str_replace_first</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$find</span><span style="color: #339933;">,</span> <span style="color: #000088;">$replace</span><span style="color: #339933;">,</span> <span style="color: #000088;">$text</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">return</span> <span style="color: #000088;">$$return</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #666666; font-style: italic;"># The nested version allows nested spin blocks, but is slower<br />
</span>&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> static <span style="color: #000000; font-weight: bold;">function</span> nested<span style="color: #009900;">&#40;</span><span style="color: #000088;">$text</span><span style="color: #339933;">,</span> <span style="color: #000088;">$seedPageName</span> <span style="color: #339933;">=</span> <span style="color: #009900; font-weight: bold;">true</span><span style="color: #339933;">,</span> <span style="color: #000088;">$openingConstruct</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">'{{'</span><span style="color: #339933;">,</span> <span style="color: #000088;">$closingConstruct</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">'}}'</span><span style="color: #339933;">,</span> <span style="color: #000088;">$separator</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">'|'</span><span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #666666; font-style: italic;"># If we have nothing to spin just exit (don't use a regexp)<br />
</span>&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">strpos</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$text</span><span style="color: #339933;">,</span> <span style="color: #000088;">$openingConstruct</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">===</span> <span style="color: #009900; font-weight: bold;">false</span><span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">return</span> <span style="color: #000088;">$text</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #666666; font-style: italic;"># Find the first whole match<br />
</span>&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">preg_match</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'!'</span><span style="color: #339933;">.</span><span style="color: #000088;">$openingConstruct</span><span style="color: #339933;">.</span><span style="color: #0000ff;">'(.+?)'</span><span style="color: #339933;">.</span><span style="color: #000088;">$closingConstruct</span><span style="color: #339933;">.</span><span style="color: #0000ff;">'!s'</span><span style="color: #339933;">,</span> <span style="color: #000088;">$text</span><span style="color: #339933;">,</span> <span style="color: #000088;">$matches</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #666666; font-style: italic;"># Optional, always show a particular combination on the page<br />
</span>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">self</span><span style="color: #339933;">::</span><span style="color: #004000;">checkSeed</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$seedPageName</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #666666; font-style: italic;"># Only take the last block<br />
</span>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$pos</span> <span style="color: #339933;">=</span> <span style="color: #990000;">mb_strrpos</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$matches</span><span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">1</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span> <span style="color: #000088;">$openingConstruct</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">!==</span> <span style="color: #009900; font-weight: bold;">false</span><span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000088;">$matches</span><span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">1</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #990000;">mb_substr</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$matches</span><span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">1</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span> <span style="color: #000088;">$pos</span> <span style="color: #339933;">+</span> <span style="color: #990000;">mb_strlen</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$openingConstruct</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #666666; font-style: italic;"># And spin it<br />
</span>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000088;">$parts</span>&nbsp; <span style="color: #339933;">=</span> <span style="color: #990000;">explode</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$separator</span><span style="color: #339933;">,</span> <span style="color: #000088;">$matches</span><span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">1</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000088;">$text</span> &nbsp; <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">self</span><span style="color: #339933;">::</span><span style="color: #004000;">str_replace_first</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$openingConstruct</span><span style="color: #339933;">.</span><span style="color: #000088;">$matches</span><span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">1</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">.</span><span style="color: #000088;">$closingConstruct</span><span style="color: #339933;">,</span> <span style="color: #000088;">$parts</span><span style="color: #009900;">&#91;</span><span style="color: #990000;">mt_rand</span><span style="color: #009900;">&#40;</span><span style="color: #cc66cc;">0</span><span style="color: #339933;">,</span> <span style="color: #990000;">count</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$parts</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">-</span> <span style="color: #cc66cc;">1</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span> <span style="color: #000088;">$text</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #666666; font-style: italic;"># We need to continue until there is nothing left to spin<br />
</span>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">return</span> <span style="color: #000000; font-weight: bold;">self</span><span style="color: #339933;">::</span><span style="color: #004000;">nested</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$text</span><span style="color: #339933;">,</span> <span style="color: #000088;">$seedPageName</span><span style="color: #339933;">,</span> <span style="color: #000088;">$openingConstruct</span><span style="color: #339933;">,</span> <span style="color: #000088;">$closingConstruct</span><span style="color: #339933;">,</span> <span style="color: #000088;">$separator</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">else</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #666666; font-style: italic;"># If we have nothing to spin just exit<br />
</span>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">return</span> <span style="color: #000088;">$text</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #666666; font-style: italic;"># Similar to str_replace, but only replaces the first instance of the needle<br />
</span>&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">private</span> static <span style="color: #000000; font-weight: bold;">function</span> str_replace_first<span style="color: #009900;">&#40;</span><span style="color: #000088;">$find</span><span style="color: #339933;">,</span> <span style="color: #000088;">$replace</span><span style="color: #339933;">,</span> <span style="color: #000088;">$string</span><span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #666666; font-style: italic;"># Ensure we are dealing with arrays<br />
</span>&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span><span style="color: #990000;">is_array</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$find</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000088;">$find</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$find</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span><span style="color: #990000;">is_array</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$replace</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000088;">$replace</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$replace</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">foreach</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$find</span> <span style="color: #b1b100;">as</span> <span style="color: #000088;">$key</span> <span style="color: #339933;">=&gt;</span> <span style="color: #000088;">$value</span><span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$pos</span> <span style="color: #339933;">=</span> <span style="color: #990000;">mb_strpos</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$string</span><span style="color: #339933;">,</span> <span style="color: #000088;">$value</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">!==</span> <span style="color: #009900; font-weight: bold;">false</span><span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #666666; font-style: italic;"># If we have no replacement make it empty<br />
</span>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span><span style="color: #990000;">isset</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$replace</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$key</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000088;">$replace</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$key</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">''</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000088;">$string</span> <span style="color: #339933;">=</span> <span style="color: #990000;">mb_substr</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$string</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">0</span><span style="color: #339933;">,</span> <span style="color: #000088;">$pos</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">.</span><span style="color: #000088;">$replace</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$key</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">.</span><span style="color: #990000;">mb_substr</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$string</span><span style="color: #339933;">,</span> <span style="color: #000088;">$pos</span> <span style="color: #339933;">+</span> <span style="color: #990000;">mb_strlen</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$value</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">return</span> <span style="color: #000088;">$string</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">private</span> static <span style="color: #000000; font-weight: bold;">function</span> checkSeed<span style="color: #009900;">&#40;</span><span style="color: #000088;">$seedPageName</span><span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #666666; font-style: italic;"># Don't do the check if we are using random seeds<br />
</span>&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$seedPageName</span><span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$seedPageName</span> <span style="color: #339933;">===</span> <span style="color: #009900; font-weight: bold;">true</span><span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #990000;">mt_srand</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">crc32</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$_SERVER</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'REQUEST_URI'</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">elseif</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$seedPageName</span> <span style="color: #339933;">==</span> <span style="color: #0000ff;">'every second'</span><span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #990000;">mt_srand</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">crc32</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$_SERVER</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'REQUEST_URI'</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">.</span><span style="color: #990000;">date</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'Y-m-d-H-i-s'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">elseif</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$seedPageName</span> <span style="color: #339933;">==</span> <span style="color: #0000ff;">'every minute'</span><span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #990000;">mt_srand</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">crc32</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$_SERVER</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'REQUEST_URI'</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">.</span><span style="color: #990000;">date</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'Y-m-d-H-i'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">elseif</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$seedPageName</span> <span style="color: #339933;">==</span> <span style="color: #0000ff;">'hourly'</span> OR <span style="color: #000088;">$seedPageName</span> <span style="color: #339933;">==</span> <span style="color: #0000ff;">'every hour'</span><span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #990000;">mt_srand</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">crc32</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$_SERVER</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'REQUEST_URI'</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">.</span><span style="color: #990000;">date</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'Y-m-d-H'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">elseif</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$seedPageName</span> <span style="color: #339933;">==</span> <span style="color: #0000ff;">'daily'</span> OR <span style="color: #000088;">$seedPageName</span> <span style="color: #339933;">==</span> <span style="color: #0000ff;">'every day'</span><span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #990000;">mt_srand</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">crc32</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$_SERVER</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'REQUEST_URI'</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">.</span><span style="color: #990000;">date</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'Y-m-d'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">elseif</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$seedPageName</span> <span style="color: #339933;">==</span> <span style="color: #0000ff;">'weekly'</span> OR <span style="color: #000088;">$seedPageName</span> <span style="color: #339933;">==</span> <span style="color: #0000ff;">'every week'</span><span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #990000;">mt_srand</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">crc32</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$_SERVER</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'REQUEST_URI'</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">.</span><span style="color: #990000;">date</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'Y-W'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">elseif</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$seedPageName</span> <span style="color: #339933;">==</span> <span style="color: #0000ff;">'monthly'</span> OR <span style="color: #000088;">$seedPageName</span> <span style="color: #339933;">==</span> <span style="color: #0000ff;">'every month'</span><span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #990000;">mt_srand</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">crc32</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$_SERVER</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'REQUEST_URI'</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">.</span><span style="color: #990000;">date</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'Y-m'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">elseif</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$seedPageName</span> <span style="color: #339933;">==</span> <span style="color: #0000ff;">'annually'</span> OR <span style="color: #000088;">$seedPageName</span> <span style="color: #339933;">==</span> <span style="color: #0000ff;">'every year'</span><span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #990000;">mt_srand</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">crc32</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$_SERVER</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'REQUEST_URI'</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">.</span><span style="color: #990000;">date</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'Y'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">elseif</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">preg_match</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'!every ([0-9.]+) seconds!'</span><span style="color: #339933;">,</span> <span style="color: #000088;">$seedPageName</span><span style="color: #339933;">,</span> <span style="color: #000088;">$matches</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #990000;">mt_srand</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">crc32</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$_SERVER</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'REQUEST_URI'</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">.</span><span style="color: #990000;">floor</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">time</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">/</span> <span style="color: #000088;">$matches</span><span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">1</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">elseif</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">preg_match</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'!every ([0-9.]+) minutes!'</span><span style="color: #339933;">,</span> <span style="color: #000088;">$seedPageName</span><span style="color: #339933;">,</span> <span style="color: #000088;">$matches</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #990000;">mt_srand</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">crc32</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$_SERVER</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'REQUEST_URI'</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">.</span><span style="color: #990000;">floor</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">time</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">/</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$matches</span><span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">1</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">*</span> <span style="color: #cc66cc;">60</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">elseif</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">preg_match</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'!every ([0-9.]+) hours!'</span><span style="color: #339933;">,</span> <span style="color: #000088;">$seedPageName</span><span style="color: #339933;">,</span> <span style="color: #000088;">$matches</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #990000;">mt_srand</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">crc32</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$_SERVER</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'REQUEST_URI'</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">.</span><span style="color: #990000;">floor</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">time</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">/</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$matches</span><span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">1</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">*</span> <span style="color: #cc66cc;">3600</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">elseif</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">preg_match</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'!every ([0-9.]+) days!'</span><span style="color: #339933;">,</span> <span style="color: #000088;">$seedPageName</span><span style="color: #339933;">,</span> <span style="color: #000088;">$matches</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #990000;">mt_srand</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">crc32</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$_SERVER</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'REQUEST_URI'</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">.</span><span style="color: #990000;">floor</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">time</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">/</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$matches</span><span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">1</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">*</span> <span style="color: #cc66cc;">86400</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">elseif</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">preg_match</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'!every ([0-9.]+) weeks!'</span><span style="color: #339933;">,</span> <span style="color: #000088;">$seedPageName</span><span style="color: #339933;">,</span> <span style="color: #000088;">$matches</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #990000;">mt_srand</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">crc32</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$_SERVER</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'REQUEST_URI'</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">.</span><span style="color: #990000;">floor</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">time</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">/</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$matches</span><span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">1</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">*</span> <span style="color: #cc66cc;">604800</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">elseif</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">preg_match</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'!every ([0-9.]+) months!'</span><span style="color: #339933;">,</span> <span style="color: #000088;">$seedPageName</span><span style="color: #339933;">,</span> <span style="color: #000088;">$matches</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #990000;">mt_srand</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">crc32</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$_SERVER</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'REQUEST_URI'</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">.</span><span style="color: #990000;">floor</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">time</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">/</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$matches</span><span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">1</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">*</span> <span style="color: #cc66cc;">2620800</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">elseif</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">preg_match</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'!every ([0-9.]+) years!'</span><span style="color: #339933;">,</span> <span style="color: #000088;">$seedPageName</span><span style="color: #339933;">,</span> <span style="color: #000088;">$matches</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #990000;">mt_srand</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">crc32</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$_SERVER</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'REQUEST_URI'</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">.</span><span style="color: #990000;">floor</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">time</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">/</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$matches</span><span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">1</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">*</span> <span style="color: #cc66cc;">31449600</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">else</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">throw</span> <span style="color: #000000; font-weight: bold;">new</span> Exception<span style="color: #009900;">&#40;</span><span style="color: #000088;">$seedPageName</span><span style="color: #339933;">.</span> <span style="color: #0000ff;">' Was not a valid spin time option!'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
<span style="color: #009900;">&#125;</span></div></div>

<p>And an example:</p>

<div class="codecolorer-container php default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="php codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000088;">$string</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">'{{The|A}} {{quick|speedy|fast}} {{brown|black|red}} {{fox|wolf}} {{jumped|bounded|hopped|skipped}} over the {{lazy|tired}} {{dog|hound}}'</span><span style="color: #339933;">;</span><br />
<br />
<span style="color: #b1b100;">echo</span> <span style="color: #0000ff;">'&lt;p&gt;'</span><span style="color: #339933;">;</span><br />
<br />
<span style="color: #b1b100;">for</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$i</span> <span style="color: #339933;">=</span> <span style="color: #cc66cc;">1</span><span style="color: #339933;">;</span> <span style="color: #000088;">$i</span> <span style="color: #339933;">&lt;=</span> <span style="color: #cc66cc;">5</span><span style="color: #339933;">;</span> <span style="color: #000088;">$i</span><span style="color: #339933;">++</span><span style="color: #009900;">&#41;</span><br />
<span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">echo</span> Spinner<span style="color: #339933;">::</span><span style="color: #004000;">detect</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$string</span><span style="color: #339933;">,</span> <span style="color: #009900; font-weight: bold;">false</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">.</span><span style="color: #0000ff;">'&lt;br /&gt;'</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// or Spinner::flat($string, false).'&lt;br /&gt;';</span><br />
<span style="color: #009900;">&#125;</span><br />
<br />
<span style="color: #b1b100;">echo</span> <span style="color: #0000ff;">'&lt;/p&gt;'</span><span style="color: #339933;">;</span></div></div>

<p>Which produces:</p>

<p>The speedy black wolf bounded over the lazy hound<br />
A speedy brown fox skipped over the tired hound<br />
The quick red wolf bounded over the lazy hound<br />
The fast brown fox hopped over the tired dog<br />
The speedy brown fox jumped over the tired dog<br />
</p>

<p><b>and</b> it will work happily as a nested PHP spinner too:</p>

<div class="codecolorer-container php default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="php codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000088;">$string</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">'{{A {{simple|basic}} example|An uncomplicated scenario|The {{simplest|trivial|fundamental|rudimentary}} case|My {{test|invest{{igative|igation}}}} case}} to illustrate the {{function|problem}}'</span><span style="color: #339933;">;</span><br />
<br />
<span style="color: #b1b100;">echo</span> <span style="color: #0000ff;">'&lt;p&gt;'</span><span style="color: #339933;">;</span><br />
<br />
<span style="color: #b1b100;">for</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$i</span> <span style="color: #339933;">=</span> <span style="color: #cc66cc;">1</span><span style="color: #339933;">;</span> <span style="color: #000088;">$i</span> <span style="color: #339933;">&lt;=</span> <span style="color: #cc66cc;">5</span><span style="color: #339933;">;</span> <span style="color: #000088;">$i</span><span style="color: #339933;">++</span><span style="color: #009900;">&#41;</span><br />
<span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">echo</span> Spinner<span style="color: #339933;">::</span><span style="color: #004000;">detect</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$string</span><span style="color: #339933;">,</span> <span style="color: #009900; font-weight: bold;">false</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">.</span><span style="color: #0000ff;">'&lt;br /&gt;'</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// or Spinner::nested($string, false).'&lt;br /&gt;';</span><br />
<span style="color: #009900;">&#125;</span><br />
<br />
<span style="color: #b1b100;">echo</span> <span style="color: #0000ff;">'&lt;/p&gt;'</span><span style="color: #339933;">;</span></div></div>

<p>Which produces:</p>

<p>A basic example to illustrate the function<br />
My test case to illustrate the problem<br />
The rudimentary case to illustrate the function<br />
An uncomplicated scenario to illustrate the problem<br />
The fundamental case to illustrate the problem<br />
</p>

<h2>Improvement</h2>

<p>The spinner now allows seed page options to be strings such as &#8216;daily&#8217;, &#8216;every 2.5 hours&#8217; or &#8216;every 3 weeks&#8217; rather than just true / false so the spun text will automatically update every set period of time. See the checkSeed (bottom) function for allowed values.</p>

<p>Have fun spinning articles! Any comments, suggestions or improvements are welcome.</p>]]></content:encoded>
			<wfw:commentRss>http://www.paul-norman.co.uk/2010/09/php-spinner-updated-spin-articles-for-seo/feed/</wfw:commentRss>
		<slash:comments>25</slash:comments>
		</item>
	</channel>
</rss>

