<?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"
	>

<channel>
	<title>Rudd-O.com &#187; Server management</title>
	<atom:link href="http://rudd-o.com/archives/category/server-management/feed/" rel="self" type="application/rss+xml" />
	<link>http://rudd-o.com</link>
	<description>We only do fun stuff.</description>
	<pubDate>Thu, 24 Jul 2008 20:34:45 +0000</pubDate>
	<generator>http://wordpress.org/?v=2.6</generator>
	<language>en</language>
			<item>
		<title>Monitoring Dirvish backup servers using Nagios</title>
		<link>http://rudd-o.com/archives/2008/02/01/monitoring-dirvish-backup-servers-using-nagios/</link>
		<comments>http://rudd-o.com/archives/2008/02/01/monitoring-dirvish-backup-servers-using-nagios/#comments</comments>
		<pubDate>Fri, 01 Feb 2008 08:23:02 +0000</pubDate>
		<dc:creator>Rudd-O</dc:creator>
		
		<category><![CDATA[Cool]]></category>

		<category><![CDATA[Programming]]></category>

		<category><![CDATA[Server management]]></category>

		<category><![CDATA[Software bacán]]></category>

		<category><![CDATA[Tips]]></category>

		<guid isPermaLink="false">http://rudd-o.com/archives/2008/02/01/monitoring-dirvish-backup-servers-using-nagios/</guid>
		<description><![CDATA[Dirvish is an excellent disk-based rotating backup application.  Nagios is a fabulous service monitor.  Combine the two using this Nagios plugin and you will know, at all times, the status of your latest backup run:



The script

Stash it in /usr/lib/nagios/plugins of the Dirvish backup machine, naming it check_dirvish.  This script assumes that your [...]]]></description>
			<content:encoded><![CDATA[<p>Dirvish is an excellent disk-based rotating backup application.  Nagios is a fabulous service monitor.  Combine the two using this Nagios plugin and you will know, at all times, the status of your latest backup run:</p>

<p><span id="more-1877"></span></p>

<h2>The script</h2>

<p>Stash it in <code>/usr/lib/nagios/plugins</code> of the Dirvish backup machine, naming it <code>check_dirvish</code>.  This script assumes that your Dirvish vaults are in <code>/mnt/backup</code>, so tune it if that isn&#8217;t true in your case:</p>

<p><pre>#!/bin/bash</pre></p>

<p>for a in /mnt/backup/* ; do
        if [ -f <code>ls -d "$a/"* 2&amp;gt; /dev/null | grep -v /dirvish | sort -g | tail -1</code>/rsync_error ] ; then
                echo "CRITICAL: latest backup in vault $a failed"
                exit 2
        else
                /bin/true
        fi
done
echo "OK: All backups OK"</p>

<h2>The security setup</h2>

<p>Create a <code>nagios</code> user on your Dirvish backup machine, and set up SSH passwordless authentication.</p>

<p>Now, if your Dirvish vaults are accessible only to root, set up <code>sudo</code> to allow Nagios to run this script as root:</p>

<p><pre>nagios ALL = NOPASSWD: /usr/lib/nagios/plugins/check_dirvish</pre></p>

<h2>The Nagios setup</h2>

<p>Finally, set Nagios up:</p>

<p><pre>define command{
        command_name    ssh_dirvish_sudo
        command_line    /usr/lib/nagios/plugins/check_by_ssh -t 29 -H $HOSTADDRESS$ -C 'sudo /usr/lib/nagios/plugins/check_dirvish'
        }
define service{
        use                             generic-service
        host_name                       gabriela
        service_description             Backups
        check_command                   ssh_dirvish_sudo
        }</pre></p>

<p>Of course, the <code>sudo</code> call is only needed if the Dirvish vaults are restricted for the <code>nagios</code> user.</p>
]]></content:encoded>
			<wfw:commentRss>http://rudd-o.com/archives/2008/02/01/monitoring-dirvish-backup-servers-using-nagios/feed/</wfw:commentRss>
		</item>
		<item>
		<title>How to automate torrent downloads using TorrentFlux-b4rt, cron and rsync</title>
		<link>http://rudd-o.com/archives/2007/10/31/how-to-automate-torrent-downloads-using-torrentflux-b4rt-cron-and-rsync/</link>
		<comments>http://rudd-o.com/archives/2007/10/31/how-to-automate-torrent-downloads-using-torrentflux-b4rt-cron-and-rsync/#comments</comments>
		<pubDate>Wed, 31 Oct 2007 12:40:52 +0000</pubDate>
		<dc:creator>Rudd-O</dc:creator>
		
		<category><![CDATA[Cool]]></category>

		<category><![CDATA[Free software]]></category>

		<category><![CDATA[Linux]]></category>

		<category><![CDATA[Server management]]></category>

		<category><![CDATA[Ubuntu]]></category>

		<guid isPermaLink="false">http://rudd-o.com/archives/2007/10/31/how-to-automate-torrent-downloads-using-torrentflux-b4rt-cron-and-rsync/</guid>
		<description><![CDATA[TorrentFlux-b4rt is an awesome masterpiece of engineering.  You install it on your Web server, and then you can start downloading BitTorrent torrents right away.  The catch is that those torrents are saved in your Web server until you actually download them to your PC.  And having to schedule downloads separately is a [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://tf-b4rt.berlios.de/">TorrentFlux-b4rt</a> is an awesome masterpiece of engineering.  You install it on your Web server, and then you can start downloading BitTorrent torrents right away.  The catch is that those torrents are saved in your Web server until you actually download them to your PC.  And having to schedule downloads separately is a pain.  Well, no more.</p>

<p><span id="more-1795"></span></p>

<h2>Awesome awesomeness: start your downloads minutes after TorrentFlux finishes them</h2>

<p>I&#8217;ve created a very, very complicated and interwoven (translation: awesome and straightforward) script that you may use and modify on your home computer.  It works like this:</p>

<ul>
    <li>Using SSH, it queries your TorrentFlux server&#8217;s transfer list, asking which torrents are completely downloaded.</li>
    <li>For each of the completed torrents, it grabs the file name of the downloaded file.</li>
    <li>Then, it uses rsync to incrementally transfer the downloaded file to your PC.</li>
    <li>Again using rsync, it removes the file from your TorrentFlux server, freeing disk space.</li>
</ul>

<h3>What you need to do before using the script</h3>

<p>For you to use it, you will need to do the following:</p>

<ul>
    <li>Enable SSH access to your (soon-to-be) TorrentFlux server.</li>
    <li>Set up public key (passwordless) authentication so that your home computer&#8217;s user account can freely log in to your server without asking for a password.</li>
    <li>Install TorrentFlux-b4rt and set it up so that your SSH user has read/write access to the torrents and downloads folders/files.  Umask/permissions, you know the drill.</li>
    <li>Enable <code>fluxcli</code> usage on your TorrentFlux setup.</li>
    <li>Install <code>rsync</code> on both your server and your home computer.</li>
    <li>Install the BitTorrent package that contains the program named <code>torrentinfo-console</code> on your server.</li>
    <li>Create a destination directory on your home computer.</li>
    <li>Install a mail program such as <code>mailx</code> on your home computer.</li>
    <li>Install <code>cron</code> on your home computer.</li>
    <li>Configure the script altering the variables at the top.</li>
</ul>

<p>Yeah, it&#8217;s a lot of work.  Go bitch somewhere else, we&#8217;re here for the fun.</p>

<h3>Installing the script</h3>

<p>Put the script somewhere in your <code>PATH</code>.  Make it executable.  Set up a cron job for the purpose:
<pre># m h  dom mon dow   command
0,10,20,30,40,50 * * * * /home/rudd-o/bin/torrentleecher -q</pre>
Make sure the cron job line ends with a line ending (carriage return) &#8212; otherwise it doesn&#8217;t run.</p>

<h3>The script itself</h3>

<p>It&#8217;s a stunning, hackish example of subprocessing, SSH remoting, pipeline integration, text processing, POSIX daemonizing and file locking, and samizdat logging.  It gets almost all of them wrong, and yet it manages to stay standing.  If you&#8217;re interested in reading <a href="post:how-to-divide-and-conquer-a-problem-the-unix-way">a complete account of how this script grew out of nothing, well, click here</a>.</p>

<p>It&#8217;s a miracle:
<pre>#!/usr/bin/env python</pre></p>

<p>from subprocess import Popen,PIPE,STDOUT,call
import fcntl
import re
import os
import sys
import signal</p>

<h1>FIXME: this script doesn't deal with multifile torrents</h1>

<h1>vars!</h1>

<h1>wherever they are used, it's MOST LIKELY they need quoting</h1>

<h1>FIXME whatever calls SSH remoting needs to protect/quote the commands for spaces or else this might turn out to be a bitch</h1>

<p>torrentflux_base_dir = "/var/www/html/torrents/torrents"
torrentflux_download_dir = "/var/www/html/torrents/torrents/incoming"
torrentflux_server = "yourserver.com"
torrentleecher_destdir = "/home/rudd-o/download/"
fluxcli = "fluxcli"
torrentinfo = "torrentinfo-console"
email_address = "rudd-o@awesome.com"</p>

<p>def getstdout(cmdline):
        p = Popen(cmdline,stdout=PIPE)
        output = p.communicate()[0]
        if p.returncode != 0: raise Exception, "Command %s return code %s"%(cmdline,p.returncode)
        return output
def getstdoutstderr(cmdline,inp=None): # return stoud and stderr in a single string object
        p = Popen(cmdline,stdin=PIPE,stdout=PIPE,stderr=STDOUT)
        output = p.communicate(inp)[0]
        if p.returncode != 0: raise Exception, "Command %s return code %s"%(cmdline,p.returncode)
        return output
def passthru(cmdline): return call(cmdline) # return status code, pass the outputs thru
def getssh(cmd): return getstdout(["ssh","-o","BatchMode yes","-o","ForwardX11 no",torrentflux_server] + [cmd]) # return stdout of ssh.  doesn't return stderr
def sshpassthru(cmd): return call(["ssh","-o","BatchMode yes","-o","ForwardX11 no",torrentflux_server] + [cmd]) # return status code from a command executed using ssh
def mail(subject,text): return getstdoutstderr(["mail","-s",subject,email_address],text)</p>

<p>def get_finished_torrents():
        stdout = getssh("%s transfers"%fluxcli)
        stdout = stdout.splitlines()[2:-5]
        stdout = [ re.match("^- (.+) - [0123456789.]+ MB - (Seeding|Done)",line) for line in stdout ]
        return [ match.group(1) for match in stdout if match ]</p>

<p>def get_file_name(torrentname):
        cmd = "LANG=C %s %s/.transfers/%s"%(torrentinfo,torrentflux_base_dir,torrentname)
        stdout = getssh(cmd).splitlines()
        filenames = [ l[22:] for l in stdout if l.startswith("file name...........: ") ]
        assert len(filenames) is 1
        return filenames[0]</p>

<p>def dorsync(filename):
        cmdline = ["rsync","-avzP","--remove-source-files",
                "%s:%s/%s"%(torrentflux_server,torrentflux_download_dir,filename),"."]
        return passthru(cmdline)</p>

<p>def exists_on_server(filename):
        cmd = "test -f %s/%s"%(torrentflux_download_dir,filename)
        returncode = sshpassthru(cmd)
        if returncode == 1: return False
        elif returncode == 0: return True
        else: assert False # Not reached</p>

<p>def get_files_to_download():
        torrents = get_finished_torrents()
        for t in torrents:
                yield (t,get_file_name(t))</p>

<p>def lock():
        global f
        try:
                fcntl.lockf(f.fileno(),fcntl.LOCK_UN)
                f.close()
        except: pass
        try:
                f=open(os.path.join(torrentleecher_destdir,".torrentleecher.lock"), 'w')
                fcntl.lockf(f.fileno(),fcntl.LOCK_EX | fcntl.LOCK_NB)
        except IOError,e:
                if e.errno == 11: return False
                else: raise
        return True</p>

<p>def daemonize():
        """Detach a process from the controlling terminal and run it in the
        background as a daemon.
        """
        try: pid = os.fork()
        except OSError, e: raise Exception, "%s [%d]" % (e.strerror, e.errno)</p>

<pre><code>    if (pid == 0):           # The first child.
            os.setsid()
            try: pid = os.fork()              # Fork a second child.
            except OSError, e: raise Exception, "%s [%d]" % (e.strerror, e.errno)

            if (pid == 0):   # The second child.
                    os.chdir("/")
            else:
                    # exit() or _exit()?  See below.
                    os._exit(0)      # Exit parent (the first child) of the second child.
    else: os._exit(0)                # Exit parent of the first child.

    import resource                           # Resource usage information.
    maxfd = resource.getrlimit(resource.RLIMIT_NOFILE)[1]
    if (maxfd == resource.RLIM_INFINITY):
            maxfd = 1024

    # Iterate through and close all file descriptors.
    for f in [ sys.stderr, sys.stdout, sys.stdin ]:
            try: f.flush()
            except: pass

    for fd in range(0, 2):
            try: os.close(fd)
            except OSError: pass

    for f in [ sys.stderr, sys.stdout, sys.stdin ]:
            try: f.close()
            except: pass

    sys.stdin = file("/dev/null", "r")
    sys.stdout = file(os.path.join(torrentleecher_destdir,".torrentleecher.log"), "a",0)
    sys.stderr = file(os.path.join(torrentleecher_destdir,".torrentleecher.log"), "a",0)
    os.dup2(1, 2)

    return(0)
</code></pre>

<p>sighandled = False
def sighandler(signum,frame):
        global sighandled
        if not sighandled:
                print &#8220;Received signal %s&#8221;%signum
                # temporarily immunize from signals
                oldhandler = signal.signal(signum,signal.SIG_IGN)
                os.killpg(0,signum)
                signal.signal(signum,oldhandler)
                sighandled = True</p>

<p>def report_file_failed(filename):
        try: os.symlink(os.path.join(torrentleecher_destdir,&#8221;.torrentleecher.log&#8221;),&#8221;%s.log&#8221;%filename)
        except OSError,e:
                if e.errno != 17: raise #file exists should be ignored of course
        sys.stdout.flush()
        sys.stderr.flush()
        errortext = &#8220;&#8221;"Please take a look at the log files in
%s&#8221;"&#8221;%torrentleecher_destdir
        mail(&#8221;Leecher: error &#8212; %s&#8221;%filename,errortext)</p>

<p>def report_file_done(filename):
        try: file(&#8221;%s is done&#8221;%filename,&#8221;w&#8221;).write(&#8221;Done&#8221;)
        except OSError,e:
                if e.errno != 17: raise #file exists should be ignored of course
        mail(&#8221;Leecher: done &#8212; %s&#8221;%filename,&#8221;The file is at %s&#8221;%torrentleecher_destdir)</p>

<p>def main():
        if not ( len(sys.argv) &gt; 1 and &#8220;-D&#8221; in sys.argv[1:] ): daemonize()
        os.chdir(torrentleecher_destdir)
        if not lock(): # we need to lock the file after the daemonization
                if not ( len(sys.argv) &gt; 1 and &#8220;-q&#8221; in sys.argv[1:] ):
                        print &#8220;Other process is downloading the file &#8212; add -q argument to command line to squelch this message&#8221;
                sys.exit(0)
        signal.signal(signal.SIGTERM,sighandler)
        signal.signal(signal.SIGINT,sighandler)</p>

<pre><code>    print "Starting download of finished torrents"

    try:

            for torrent,filename in get_files_to_download():
                    # no point in doing anything if the file was removed, right?
                    # so we continue if the file doesn't exist
                    if not exists_on_server(filename): continue
                    print "Downloading %s from torrent %s"%(filename,torrent)
                    retvalue = dorsync(filename)
                    if retvalue == 0:
                            report_file_done(filename)
                            print "Download of %s complete"%filename
                            # TODO: make use of fluxcli to kill the torrent out of TF
                    else:
                            if retvalue == 20:
                                    print "Download of %s stopped -- rsync process interrupted"%(filename)
                                    print "Finishing by user request"
                                    sys.exit(2)
                            elif retvalue &amp;lt; 0:
                                    report_file_failed(filename)
                                    print "Download of %s failed -- rsync process killed with signal %s"%(filename,-retvalue)
                                    print "Aborting"
                                    sys.exit(1)
                            else:
                                    report_file_failed(filename)
                                    print "Download of %s failed -- rsync process exited with return status %s"%(filename,retvalue)
                                    print "Aborting"
                                    sys.exit(1)

            print "Download of finished torrents complete"

    except Exception,e:
            report_file_failed("00 - General error")
            raise
</code></pre>

<p>if <strong>name</strong> == &#8220;<strong>main</strong>&#8220;: main()</p>

<p>If you want to learn the process of <a href="post:how-to-divide-and-conquer-a-problem-the-unix-way">how this script grew out of nothing, here&#8217;s the story</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://rudd-o.com/archives/2007/10/31/how-to-automate-torrent-downloads-using-torrentflux-b4rt-cron-and-rsync/feed/</wfw:commentRss>
		</item>
		<item>
		<title>The shell challenge: changing another process&#8217; working directory</title>
		<link>http://rudd-o.com/archives/2007/09/06/the-shell-challenge-changing-another-process-working-directory/</link>
		<comments>http://rudd-o.com/archives/2007/09/06/the-shell-challenge-changing-another-process-working-directory/#comments</comments>
		<pubDate>Thu, 06 Sep 2007 07:57:42 +0000</pubDate>
		<dc:creator>Rudd-O</dc:creator>
		
		<category><![CDATA[Linux]]></category>

		<category><![CDATA[Server management]]></category>

		<category><![CDATA[Tips]]></category>

		<guid isPermaLink="false">http://rudd-o.com/archives/2007/09/06/the-shell-challenge-changing-another-process-working-directory/</guid>
		<description><![CDATA[Don’t you hate it when you leave a shell open and you can’t unmount a disk volume because the shell has a firm grip on a directory in that disk?  Well, there’s a solution.



Put this on a script, and run it with the offending process ID as the first argument, and the destination directory [...]]]></description>
			<content:encoded><![CDATA[<p>Don&#8217;t you hate it when you leave a shell open and you can&#8217;t unmount a disk volume because the shell has a firm grip on a directory in that disk?  Well, there&#8217;s a solution.</p>

<p><span id="more-1672"></span></p>

<p>Put this on a script, and run it with the offending process ID as the first argument, and the destination directory as the second one:</p>

<p><pre>#!/bin/bash</pre></p>

<p>pid="$1" # get the PID
cwd="$2" # first argument is the CWD, there is a quoting bug below but I really couldn't care less</p>

<h1>now let's command the GNU debugger</h1>

<p>gdb -q &gt;&gt; EOF
attach $pid
call (int) chdir("$cwd")
detach
quit
EOF</p>

<p><a href="http://mces.blogspot.com/2007/09/linux-shell-puzzle.html">Inspired by Behdad</a>.  Took me one minute to write it, two to <a href="http://sial.org/howto/debug/unix/lsof/">look up how it&#8217;s done</a>.  Thank <a href="http://www.google.com/">Google</a>.</p>

<p>Things to notice:</p>

<ol>
<li>Yes, there&#8217;s a quoting bug in the here-document fed to GDB.  I couldn&#8217;t care less; post the fix as a comment if you want to.</li>
<li><em>Caveat luser</em>: when you sweep the rug off of <code>bash</code>&#8217;s feet using this trick, the <code>bash</code> prompt will continue to have the <em>wrong</em> idea of the current directory, but every other command (not using the <code>$PWD</code> variable, of course) will operate correctly.</li>
<li>Processes holding files open on a volume to be mounted could conceivably get their files closed using GDB as well.  Trivial and left as an exercise for the reader.</li>
<li><code>bash</code> is my bitch, I rule, then you die.</li>
</ol>
]]></content:encoded>
			<wfw:commentRss>http://rudd-o.com/archives/2007/09/06/the-shell-challenge-changing-another-process-working-directory/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Call to arms: two system management applications we sorely need in Linux land</title>
		<link>http://rudd-o.com/archives/2006/10/30/call-to-arms-two-system-management-applications-we-sorely-need-in-linux-land/</link>
		<comments>http://rudd-o.com/archives/2006/10/30/call-to-arms-two-system-management-applications-we-sorely-need-in-linux-land/#comments</comments>
		<pubDate>Mon, 30 Oct 2006 13:03:37 +0000</pubDate>
		<dc:creator>Rudd-O</dc:creator>
		
		<category><![CDATA[Free software]]></category>

		<category><![CDATA[Linux]]></category>

		<category><![CDATA[Pensamientos]]></category>

		<category><![CDATA[Server management]]></category>

		<guid isPermaLink="false">http://rudd-o.com/archives/2006/10/30/call-to-arms-two-system-management-applications-we-sorely-need-in-linux-land/</guid>
		<description><![CDATA[Diagnosing server (and desktop, and network) load issues is always tricky.  When an application misbehaves for short bursts of time, it’s often a matter of guesswork to find out which.



The regular monitoring application suite is just not enough.  top only analyzes CPU usage.  vmstat and iostat only present summaries, but can’t find [...]]]></description>
			<content:encoded><![CDATA[<p>Diagnosing server (and desktop, and network) load issues is always tricky.  When an application misbehaves for short bursts of time, it’s often a matter of guesswork to find out which.</p>

<p><span id="more-1204"/></p>

<p>The regular monitoring application suite is just not enough.  <code>top</code> only analyzes CPU usage.  <code>vmstat</code> and <code>iostat</code> only present summaries, but can’t find culprits.  <code>strace</code> is too low-level and doesn’t allow to visualize proportions of disk accesses among processes.  But pinpointing the exact application or daemon that’s taxing computer resources, whether it’s for short or long times, that’s currently impossible.</p>

<p>Therefore, I propose someone very clever creates these two applications, which should close the gap.</p>

<h2>Application 1: psnettop</h2>

<p>We need a combo between <code>top</code> and <code>iftop</code>.  I should be able to fire up an application that shows me network usage, not by port or by interface, but by process.  That way, I can quickly diagnose whether it’s BitTorrent or Firefox.  Network admins could remotely log onto users’ computers and inspect which applications are sucking their Internet links.</p>

<p>It should also let me collapse statistics per-application or per-PID.</p>

<p>On Windows land, there’s the fantastic NetLimiter which, apart from setting network bandwidth limits per-process, automatically shows you the instantanteous bandwidth per-process.  We need this.</p>

<h2>Application 2: disktop</h2>

<p>We also need an application, <code>top</code>-style, that shows us disk transactions per application.  Not just disk accesses, but real major page faults (swap-ins) and disk reads/writes, bypassing the disk cache.  One column for page faults.  Another for blocks read.  A third for blocks written.  They should be reported as they happen, on hardware, so the caches should be ignored.  Thus, system admins can identify applications that are:</p>

<ul>
<li>causing memory pressure to increase</li>
<li>sucking up disk bandwidth with excessive swapins/outs</li>
<li>exercising the disk by loading files not in the cache</li>
</ul>

<p><code>strace</code> does not cut it, because it doesn’t show which accesses caused actual disk hardware operations, and because it only monitors a single process.</p>

<p>It should also let me collapse statistics per-application or per-PID.</p>

<h2>Extra wishes</h2>

<p>If these applications or monitoreables could be taken advantage of in the following ways, it’d be even greater.</p>

<h3>KSysGuard integration</h3>

<p>As much of a fan I am of the command line, I’ve grown very accustomed to the great KSysGuard.  If these monitoreables could be integrated in a graphical console, then it would be very easy to spot problems at a glance.</p>

<h3>Logging à là <code>sar</code></h3>

<p>Those of us who have used <code>sar</code> know it’s a valuable way to make assessments on a timeline.  If periodic logging of these monitoreables were incorporated into the system, we could quickly diagnose problems that have occurred in the past, and share log files with debuggers and developers everywhere.  Thus we wouldn’t rely on anecdotic evidence and hearsay when it comes to discussing naughty applications.</p>

<h2>Please help!</h2>

<p>Sadly, I don’t have the skillset required to do this.  I’m hoping someone in the Free Software community can help us in this sense.  I understand that clever work can use SystemTap to derive these values.  So there’s a start.</p>

<p>Have a great day!</p>
]]></content:encoded>
			<wfw:commentRss>http://rudd-o.com/archives/2006/10/30/call-to-arms-two-system-management-applications-we-sorely-need-in-linux-land/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Automating Nagios service checks via SSH</title>
		<link>http://rudd-o.com/archives/2006/09/17/automating-nagios-service-checks-via-ssh/</link>
		<comments>http://rudd-o.com/archives/2006/09/17/automating-nagios-service-checks-via-ssh/#comments</comments>
		<pubDate>Sun, 17 Sep 2006 06:58:46 +0000</pubDate>
		<dc:creator>Rudd-O</dc:creator>
		
		<category><![CDATA[Free software]]></category>

		<category><![CDATA[Server management]]></category>

		<category><![CDATA[Software bacán]]></category>

		<category><![CDATA[Tutorials]]></category>

		<guid isPermaLink="false">http://rudd-o.com/archives/2006/09/17/automating-nagios-service-checks-via-ssh/</guid>
		<description><![CDATA[Hello!  Here’s a nifty article on the Server management series.  Today, we’ll learn how to automate Nagios service checks via SSH, even when the remote server does not support password-less (key-based) SSH logins.



We’ll cobble a lot of technologies together in order to achieve this amazing feat.  While no experience is required with [...]]]></description>
			<content:encoded><![CDATA[<p>Hello!  Here’s a nifty article on the Server management series.  Today, we’ll learn how to automate Nagios service checks via SSH, even when the remote server does not support password-less (key-based) SSH logins.</p>

<p><span id="more-1149"/></p>

<p>We’ll cobble a lot of technologies together in order to achieve this amazing feat.  While no experience is required with most of the technologies we’ll be using, you’ll need to be proficient in configuring Nagios.  I’m also assuming you already have a Nagios instance up, running and operational.</p>

<p>Beware that this guide will require you to save your SSH password for the remote server in a file — not awfully secure.  This file will be unreadable to anyone except the Nagios service checker — not even the Web interface has access to it.  I consider this an acceptable compromise under the circumstances, but you may not.</p>

<p>Without further ado, here’s the guide.</p>

<h2>Why this guide?</h2>

<p>Now, what prompts me to do this guide?  Of course, it’s an itch to be scratched.  My home computer runs Nagios, and I’ve set it up to periodically check for the health of the Apache service that runs this site, because it tends to go haywire and very slow during traffic storms.</p>

<p>The <code>check_http</code> Nagios plugin does work.  So why don’t I use it? Because it doesn’t work as I intended.  This is better explained by live example.</p>

<p>Most Nagios plugins are simple command-line programs which accept two timeout threshold arguments: the warning and the critical threshold.  They report back the success, failure, warning or critical status to the Nagios server in a line of text.</p>

<p>This makes for powerful, modular server supervision and testing. Remote testing of service health is a piece of cake: once you’ve set it up, it’s fire and forget (until any problem with the server arises).  In this particular case, Nagios periodically runs the <code>check_http</code> plugin, which times the response time of the Apache server; if the service takes too long to respond, Nagios issues a WARNING or a CRITICAL message to me.</p>

<p>Of course, in a perfect world, air poses no resistance, cows are perfectly round, and network congestion is a non-issue.  But my computer is at 18 high-latency hops from the server I’m checking.  To boot, I usually have a BitTorrent client open and, no matter now much tuning you do, that kind of traffic breeds congestion.  While the service itself may be serving one page in 0.5 seconds, Nagios usually reports times above 10 seconds (in my book, that’s CRITICAL).</p>

<p>So <code>check_http</code>, as shipped, is useless to me — I cannot reliably determine if my remote host is truly slow, or if it’s just me.</p>

<h2>The solution: time server response times directly at the source</h2>

<p>With that in mind, I set out to find a solution.  And the first one that sprang to mind is the one that I implemented.  Basically, running <code>check_http</code> directly on this server would yield good timing information, and drastically cut back on warnings.  And you can run <code>check_http</code> via SSH, which is an even better proposition.</p>

<p>Keep reading to find out how I did it.</p>
]]></content:encoded>
			<wfw:commentRss>http://rudd-o.com/archives/2006/09/17/automating-nagios-service-checks-via-ssh/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Repairing unbootable Windows XP systems with one command</title>
		<link>http://rudd-o.com/archives/2006/05/23/repairing-unbootable-windows-xp-systems-with-one-command/</link>
		<comments>http://rudd-o.com/archives/2006/05/23/repairing-unbootable-windows-xp-systems-with-one-command/#comments</comments>
		<pubDate>Wed, 24 May 2006 01:10:02 +0000</pubDate>
		<dc:creator>Rudd-O</dc:creator>
		
		<category><![CDATA[Free software]]></category>

		<category><![CDATA[Linux]]></category>

		<category><![CDATA[Server management]]></category>

		<category><![CDATA[Software bacán]]></category>

		<guid isPermaLink="false">http://rudd-o.com/archives/2006/05/23/repairing-unbootable-windows-xp-systems-with-one-command/</guid>
		<description><![CDATA[Perhaps you’ve read the fabulous Repairing Windows XP in Eight Commands - Guide - Short-Media already.  Perhaps not.  But what happens when you can’t even get to the recovery console?



Yes, it does happen.  Sometimes the file system of your boot volume gets corrupted… oh, okay, that probably sounded like gibberish, but it’s [...]]]></description>
			<content:encoded><![CDATA[<p>Perhaps you’ve read the fabulous <a href="http://www.short-media.com/review.php?r=313">Repairing Windows XP in Eight Commands - Guide - Short-Media</a> already.  Perhaps not.  But <strong>what happens when you can’t even get to the recovery console?</strong></p>

<p><span id="more-916"/></p>

<p>Yes, it does happen.  Sometimes the file system of your boot volume gets corrupted… oh, okay, that probably sounded like gibberish, but it’s true.  In other words, your disk can get so messed up, that you can’t even get to the recovery console because <strong>Windows XP will boot, show the Windows XP logo, wait a few seconds, and then simply restart</strong>.</p>

<p><em>How on Earth do you fix this?</em></p>

<p>Easy!  You just <strong>use Linux to solve this problem</strong>.  Now, pay attention, because this solution does require some elbow grease, but if you need your files right away, you’d better be prepared.</p>

<h2>First step: download INSERT</h2>

<p><a href="http://www.inside-security.de/insert_en.html">INSERT</a> is the Inside Security Linux distribution.  It comes with a lot of utilities designed to perform forensics and fixing systems (yes, even Windows XP!).  Additionally, you have full read and write capabilities for Windows XP’s NTFS file system (which isn’t included in most Linux distributions.  As if it weren’t enough, INSERT is a very small download (in relation to other Linux distributions).  And, finally, it will autodetect your computer’s hardware, without the need for installation.</p>

<p>So, just in case, <a href="http://www.inside-security.de/insert_en.html">download INSERT</a> and burn it on a disk.  It fits on a business card-sized CD-R (normal CD-Rs are also okay).  Place it in your wallet, or on your car’s glove compartment — you’ll end up needing it eventually.</p>

<h2>Step two: boot into INSERT</h2>

<p>Insert your newly burnt INSERT disk on your computer, and tell your computer to boot from the CD-ROM (instructions for this, of course, vary, since this is a task to be done through the BIOS or the boot menu of your computer).</p>

<p class="centered"><a href="http://rudd-o.com/wp-content/uploads/images/fix-windows-xp/bootmenu.png" title="Here's how your BIOS boot menu may look like.  Take it with a grain of salt." target="_self" rel="lightbox"><img class="thumbnail" src="http://rudd-o.com/wp-content/uploads/images/fix-windows-xp/thumb_bootmenu.png" alt="Here's how your BIOS boot menu may look like.  Take it with a grain of salt." width="150" height="111"/></a><br />
Here’s how your BIOS boot menu may look like.  Take it with a grain of salt.</p>

<p>After INSERT boots, you’ll see a prompt with a nice logo.</p>

<p class="centered"><a href="http://rudd-o.com/wp-content/uploads/images/fix-windows-xp/insert-boot.png" title="Here's the boot menu that shows when booting from the INSERT CD" target="_self" rel="lightbox"><img class="thumbnail" src="http://rudd-o.com/wp-content/uploads/images/fix-windows-xp/thumb_insert-boot.png" alt="Here's the boot menu that shows when booting from the INSERT CD" width="150" height="113"/></a></p>

<p>Type <code>insert 2</code> and hit ENTER.  You’ll see INSERT booting and autodetecting your hardware, and then you’ll be dumped into a command interpreter.  That’s Linux.</p>

<p class="centered"><a href="http://rudd-o.com/wp-content/uploads/images/fix-windows-xp/insert-autoconfiguring.png" title="Here's how INSERT looks like when it's inspecting your computer" target="_self" rel="lightbox"><img class="centered" src="http://rudd-o.com/wp-content/uploads/images/fix-windows-xp/thumb_insert-autoconfiguring.png" alt="Here's how INSERT looks like when it's inspecting your computer" width="150" height="113"/></a><br />Here’s how INSERT looks like when it’s inspecting your computer</p>

<p class="centered"><a href="http://rudd-o.com/wp-content/uploads/images/fix-windows-xp/insert-prompt.png" title="And here's the INSERT prompt.  This is a bash shell." target="_self" rel="lightbox"><img class="centered" src="http://rudd-o.com/wp-content/uploads/images/fix-windows-xp/thumb_insert-prompt.png" alt="And here's the INSERT prompt.  This is a bash shell." width="150" height="113"/></a><br />And here’s the INSERT prompt.  This is a <code>bash</code> shell.</p>

<p>Do not be afraid.  Everything is just fine.</p>

<h2>Step three: fix your NTFS volume</h2>

<p>If you’re like me, and you have an El Cheapo computer (which is, like, 99% of the world population) you’ll have a single IDE disk.  If you’re not so lucky (or, perhaps, even luckier, and you have several disks) you’ll have SATA or SCSI disks, one or more.  View the contents of the <code>/etc/fstab</code> file:</p>

<p><pre>cat /etc/fstab</pre></p>

<p>should show you the contents of that file.  You’ll see several lines, and each line will most probably begin with a <code>/dev/hdXX</code> or <code>/dev/sdXX</code>.  Usually, your first NTFS volume should be <code>/dev/hda1</code> (for IDE disks) or <code>/dev/sda1</code> (for SATA or SCSI disks).</p>

<p class="centered"><a href="http://rudd-o.com/wp-content/uploads/images/fix-windows-xp/insert-fstab.png" title="And here's the INSERT prompt.  This is a bash shell." target="_self" rel="lightbox"><img class="centered" src="http://rudd-o.com/wp-content/uploads/images/fix-windows-xp/thumb_insert-fstab.png" alt="The contents of my hypothetical /etc/fstab file" width="150" height="113"/></a><br />The contents of my hypothetical <code>/etc/fstab</code> file</p>

<p>Run <code>ntfsfix</code> on it.</p>

<p><pre>ntfsfix /dev/sda1</pre></p>

<p>That should chug along for a few seconds, perform some checks, and return to the prompt.  Voilà!  Your Windows XP system should be bootable again.  Type <code>sync</code> then hit ENTER to ensure data to the disks is written, wait for two seconds, and then hit the reset button of your computer (or power it off and then back on).  Don’t forget to remove the CD-ROM as soon as the computer starts.</p>

<p>Once Windows XP boots, you’ll see it claiming that it needs to check the disks.  Let it check your disks.</p>

<p>That’s it.  Your computer should now boot normally</p>

<h2>Going beyond</h2>

<p>Of course, while using INSERT, there’s a lot of things just waiting to be discovered.  You’ll be able to back up your data onto other disks without touching anything from the source disks.  You’ll also be able to log on to the Internet and download software.  You’ll also be able to check your disks for Windows viruses.  But that’s material for another article.  In the meantime, I hope this small tutorial has convinced you to give Linux a shot.  Perhaps you won’t need to rescue a Windows XP system ever again <img src="http://rudd-o.com/wp-includes/images/smilies/icon_wink.gif" alt=";-)" class="wp-smiley"/> </p>

<p>Hope everything’s working just fine for you now.  Have a great day!</p>
]]></content:encoded>
			<wfw:commentRss>http://rudd-o.com/archives/2006/05/23/repairing-unbootable-windows-xp-systems-with-one-command/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Setting up a mail server using Postfix in 5 minutes</title>
		<link>http://rudd-o.com/archives/2006/03/17/setting-up-a-mail-server-using-postfix-in-5-minutes/</link>
		<comments>http://rudd-o.com/archives/2006/03/17/setting-up-a-mail-server-using-postfix-in-5-minutes/#comments</comments>
		<pubDate>Sat, 18 Mar 2006 01:34:54 +0000</pubDate>
		<dc:creator>Rudd-O</dc:creator>
		
		<category><![CDATA[Free software]]></category>

		<category><![CDATA[Linux]]></category>

		<category><![CDATA[Server management]]></category>

		<category><![CDATA[Software bacán]]></category>

		<guid isPermaLink="false">http://rudd-o.com/archives/2006/03/17/setting-up-a-mail-server-using-postfix-in-5-minutes/</guid>
		<description><![CDATA[Hello, again!  Continuing the (now lengthy) Server management series, this time we’ll learn how to set up a mail server, using the famous and very secure Postfix mail server package.



For the record, I’m assuming that you’ll be using your favorite distribution’s packages for the installation.  I’m also assuming that you have root access [...]]]></description>
			<content:encoded><![CDATA[<p>Hello, again!  Continuing the (now lengthy) <a href="/archives/category/server-management/">Server management series</a>, this time we’ll learn how to set up a mail server, using the famous and very secure Postfix mail server package.</p>

<p><span id="more-834"/></p>

<p>For the record, I’m assuming that you’ll be using your favorite distribution’s packages for the installation.  I’m also assuming that you have <code>root</code> access to your server.</p>

<p>Oh, by the way, I’ve getting several comments about users having issues with highlighted keywords on my articles.  If you’re one of those users, please <strong>get a Web browser that displays transparent PNGs properly</strong>.  Microsoft <strong>Internet Explorer is not one of them</strong>.  Any comments about highlighted keywords from IE users will go straight to <code>/dev/null</code>.</p>

<h2>Postfix: the reliable mail package</h2>

<p>Postfix is my favorite mail server package.  Why?  Postfix is unique in that:</p>

<ul>
<li>it’s surprisingly easy to configure (contrast that to Sendmail, and you’ll understand this point)</li>
<li>it’s very secure, featuring a security model with separate user contexts for each task</li>
<li>it’s also very popular</li>
<li>it’s fast</li>
</ul>

<h2>Configuring Postfix</h2>

<p>Remember that I’m assuming you’re installing Postfix from your favorite distribution’s install CDs or download servers.  With that in mind, I’d really like to assume that you’ve already installed Postfix, and skip to the configuration part.</p>

<p>To set Postfix up so it runs as a service, use the following commands:</p>

<p><pre>/sbin/chkconfig --add postfix
/sbin/chkconfig --level 35 postfix on</pre></p>

<p>And that’s it.  <code>/sbin/service postfix start</code> and see if it’s running with a quick <code>ps ax</code> command.   You should see several new processes.</p>

<p>Now, on to configuration.  The Postfix configuration file is <code>main.cf</code>.  You can usually find it in <code>/etc/postfix</code> (although your distribution’s file layout may vary).  The three most commonly changed configuration settings are the following:</p>

<ul>
<li><code>myorigin</code></li>
<li><code>mydestination</code></li>
<li><code>mynetworks_style</code> and <code>mynetworks</code></li>
<li><code>inet_interfaces</code></li>
</ul>

<p>Stick to this tutorial.  We’ll understand each one of these, in order.</p>

<h3>Mail origin: <code>myorigin</code></h3>

<p>Your mail server needs to know how it should identify itself to other mail servers.  And here’s how.</p>

<p>The <code>myorigin</code> configuration key specifies the origin domain for all mail sent through your server.  While, by default, <code>myorigin</code> is configured to use your server hostname, you may want to change it to your actual domain name.  You can accomplish this by setting the configuration key as follows:</p>

<p><pre>myorigin = $mydomain</pre></p>

<p><code>$mydomain</code> will automatically be filled in with the domain name your server is using.</p>

<h3>Destinations: <code>mydestination</code></h3>

<p>Your mail server also needs to know which domains it serves.  <code>mydestination</code> fills that need.</p>

<p><code>mydestination</code> lets Postfix know which domains your server will accept mail from.  In other words, mail sent to any of the domains listed in  <code>mydestination</code> will be delivered to local mail boxes.  The default value:</p>

<p><pre>mydestination = $myhostname localhost.$mydomain</pre></p>

<p>is not exactly useful, but it’s very secure, though most of the time you’d like it to receive mail for your entire domain.  If that’s what you want, you should configure Postfix as follows:</p>

<p><pre>mydestination = $myhostname localhost.$mydomain $mydomain</pre></p>

<p>That, of course, assumes that an <code>MX</code> DNS record exists and points to your server as the final destination for e-mail.  Don’t forget the DNS step: it’s very important (but, sadly, outside the scope of this 5-minute tutorial).</p>

<p>Of course, there’s nothing stopping you from accepting mail for multiple destinations.  An example:</p>

<p><pre>mydestination = $myhostname localhost.$mydomain usm.edu.ec company.com</pre></p>

<h3>Relay control</h3>

<p>Postfix has a relay control that’s very simple to use.  In short, <strong>relaying</strong> means <em>using your mail server to transfer mail from a client to a destination which is <strong>not</strong> your mail server</em>.</p>

<p>As you’ve probably noticed, most consumer-level ISPs have an outbound mail server set up for their clients.  That’s a good example of a relaying mail server: that mail server is configured to accept relay requests from customers’ e-mail clients.  Of course, all mail servers should have a properly tuned relay control configuration &mdash; overly zealous servers won’t let their users send mail to other users, while overly permissive servers will let spam and all its consequences through.</p>

<p>You’ll no doubt be in the same position in your organization: you’ll need workstations in your organization to be able to relay mail through your mail server.  Again, that’s easy to accomplish.  By default, Postfix is configured to accept e-mail from local networks.  To change this, we’ll explore two configuration options.</p>

<p>First of all, there’s the <code>mynetworks_style</code> configuration parameter.  This parameter can take the following values:</p>

<ul>
<li><code>subnet</code> (default): Postfix will let e-mail clients relay mail, if they are in the same IP subnetworks Postfix is connected to.</li>
<li><code>class</code>: Postfix will let e-mail clients relay mail, if they are in the same class A/B/C networks Postfix is connected to.
Trust SMTP clients in the IP subnetworks that Postfix is connected to.</li>
<li><code>host</code>: Postfix will let e-mail clients relay mail, only if they run in the same server</li>
</ul>

<p>For most usage scenarios, you’ll want to leave this configuration as <code>subnet</code>.</p>

<p>If you want more fine-grained control, there’s the <code>mynetworks</code> parameter.  Through <code>mynetworks</code>, you let Postfix know exactly which networks are allowed to relay mail.  <strong>Keep in mind that the <code>mynetworks_style</code> parameter will be ignored if <code>mynetworks</code> is set.</strong></p>

<p><pre>mynetworks = 168.100.189.0/24, 127.0.0.0/8</pre></p>

<p>is a good example.  That will let e-mail clients relay mail, but only if they’re originating either from the mail server, or any of the computers in the IP subnetwork <code>168.100.189.</code>.</p>

<h3>Network configuration</h3>

<p>The final, and perhaps most important, configuration parameter for Postfix, is the <code>inet_interfaces</code> parameter.  Through <code>inet_interfaces</code>, you let Postfix know which network interfaces should use.</p>

<p>The default is usually:</p>

<p><pre>inet_interfaces = all</pre></p>

<p>though your distribution may have changed this to make Postfix only listen through the <code>localhost</code> network interface (Fedora Core is a good example of this).  You can set this to one or more network addresses, domain names, or leave it as <code>all</code>.  I recommend you leave it as <code>all</code> and <a href="http://rudd-o.com/archives/2006/02/27/hardening-a-linux-server-in-10-minutes/" title="Hardening a Linux server in 10 minutes">do any securing through <code>iptables</code></a>.</p>

<h2>Letting Postfix know you’ve changed its configuration</h2>

<p>Once you’ve configured Postfix, restart it using the <code>/sbin/service postfix restart</code> command (though this may vary from distribution to distribution).  You should have a Postfix server up and running.  To test it, I recommend the following testing procedure:</p>

<ul>
<li>sending an e-mail from <code>root</code> in that server to <code>root</code>, and seeing if it arrives</li>
<li>sending an e-mail from <code>root</code> in that server to another user in the machine, and seeing if it arrives</li>
<li>sending an e-mail to a user in the machine, using a mail client within your organization (that is, one that falls in the <code>mynetworks</code> group), and seeing if it arrives</li>
<li>sending an e-mail to a user in the machine, using Hotmail, Gmail or any other free e-mail provider, and seeing if it arrives</li>
<li>sending an e-mail to a Hotmail or Gmail account, using a mail client within your organization, and seeing if it arrives</li>
<li>sending an e-mail to a Hotmail or Gmail account, using a mail client outside of your organization’s <code>mynetworks</code>, and configured using your newly installed mail server as the outbound mail server &mdash; and verifying that this test <strong>fails</strong>, which is a telltale sign that your server won’t act as a spam server</li>
</ul>

<h2>Conclusions</h2>

<p>I honestly don’t want to start a religious flamewar but, in my own very humble opinion, Postfix is the best mail server out there.  If you’re not using Postfix, I seriously recommend it to you.  Give it a spin &mdash; it’ll probably stay in your organization for good.</p>

<p><a href="http://www.postfix.org/documentation.html">There’s more documentation about Postfix</a> in the project’s Web site.  Be sure to peek into it as soon as you have more than 5 minutes to spare.</p>

<p>That’s it for today.  Happy hacking!</p>
]]></content:encoded>
			<wfw:commentRss>http://rudd-o.com/archives/2006/03/17/setting-up-a-mail-server-using-postfix-in-5-minutes/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Tracking, auditing and managing your server configuration with Subversion in 10 minutes</title>
		<link>http://rudd-o.com/archives/2006/03/14/tracking-auditing-and-managing-your-server-configuration-with-subversion-in-10-minutes/</link>
		<comments>http://rudd-o.com/archives/2006/03/14/tracking-auditing-and-managing-your-server-configuration-with-subversion-in-10-minutes/#comments</comments>
		<pubDate>Tue, 14 Mar 2006 17:10:29 +0000</pubDate>
		<dc:creator>Rudd-O</dc:creator>
		
		<category><![CDATA[Free software]]></category>

		<category><![CDATA[Linux]]></category>

		<category><![CDATA[Publicaciones]]></category>

		<category><![CDATA[Server management]]></category>

		<category><![CDATA[Software bacán]]></category>

		<guid isPermaLink="false">http://rudd-o.com/archives/2006/03/14/tracking-auditing-and-managing-your-server-configuration-with-subversion-in-10-minutes/</guid>
		<description><![CDATA[Hello, again!  For this article in the Server management series, we’ll explore an uncommon use of Subversion — instead of using it for source code management, you’ll be using it as a tool to make server administration painless and error-proof.



Most servers are configured once, then left to run for as long as they can [...]]]></description>
			<content:encoded><![CDATA[<p>Hello, again!  For this article in the Server management series, we’ll explore an uncommon use of Subversion &mdash; instead of using it for source code management, you’ll be <em>using it as a tool to make server administration painless</em> and error-proof.</p>

<p><span id="more-831"/></p>

<p>Most servers are configured once, then left to run for as long as they can (which, in practical terms, means ‘until hardware or software fails’).  More often than not, the <strong>cause for server failure is rooted in configuration mistakes</strong>.  That’s why it’s wise to keep a log of all configuration changes, and take detailed notes every time a setting is changed.  But, as the collection of servers you need to manage grows, <strong>bookkeeping tasks turn into a humongous monster</strong>.</p>

<p>No more.  Enter Subversion.</p>

<h2>What Subversion is</h2>

<p>Subversion is, primarily, a source code control system.  <em>You feed your files into a Subversion repository, and from that point on, Subversion oversees them</em>.  As you or other developers change files, you periodically commit your changes to the Subversion repository.  Subversion tracks those modifications, and allows you to replicate them, take snapshots of an entire source tree, and other nifty things.  Even file moves, copies and deletes are (nearly) transparently tracked by Subversion &mdash; and it has the memory of an elephant: you can delete files and, later on, recall them by revision number.</p>

<p><em>Subversion also excels with text files</em>; fortunately for us, <em>UNIX configuration files are, mostly, text</em>.</p>

<p>Subversion is, as you probably already know, <q>a better CVS than CVS</q>.  Indeed, it was designed as a replacement for CVS, so if you’re familiar with CVS, you’ll probably feel right at home with Subversion.</p>

<p>Let’s understand three fundamental concepts in Subversion.</p>

<ul>
<li><strong>There’s a central repository</strong>.  Only the repository administrator should touch that.  You’ll be playing the role of repository administrator only once.</li>
<li><strong>Users don’t touch the central repository</strong>.  They check out private “working copies” and work on those copies.  Once they’ve hacked their working copy into a desired state, they commit those changes into the repository.  You’ll be playing the role of user most of the time.</li>
<li>On any given working copy, there are <strong>two ‘axes’ users can travel</strong> (whether to check out a few files, or to make a <code>diff</code> between two states):

<ul>
<li><strong>in time</strong>: once you’re using Subversion, you can go back and forth “in time”, by switching to older and newer revisions (the newest of which is customarily called <code>HEAD</code>)</li>
<li><strong>between branches and tags</strong>: at any point in time, you can instruct Subversion to make a copy of a folder into another folder.  You can use this functionality to make periodic snapshots of a certain state, regardless of revision number.</li>
</ul></li>
</ul>

<h2>How we’ll use Subversion</h2>

<p>First, let’s review the tasks we’ll perform:</p>

<ul>
<li>We’ll create a Subversion repository to store the server configuration history</li>
<li>We’ll prepare the configuration directory</li>
<li>We’ll check the configuration files in</li>
<li>We’ll investigate how to perform followup tasks</li>
</ul>

<p>I’m assuming that you have Subversion installed; in other words, you should have the <code>svn</code> and <code>svnadmin</code> commands and they should work properly.  I’m also assuming that you’ll be performing the following tasks as <code>root</code>.</p>

<p>The ideal situation to begin applying this tutorial is right after your server has been freshly installed.  However, for practical purposes, any server that’s configured and running will do.</p>

<p>Okay.  That’s enough of the lists and introductions.  Time for some action.</p>

<h2>Creating the Subversion repository</h2>

<p>If you’re familiar with UNIX, you’ll know <code>/var</code> is the customary directory for files that pertain to the whole system and are changed.  So, following tradition, we’ll create a <code>/var/preserve/config</code> repository.  Type the following command at your console:</p>

<p><pre>[rudd-o@amauta2 ~]# svnadmin create \
/var/preserve/config</pre></p>

<p>(note the backslashes are being used to add whitespace)</p>

<p>That should create a <code>/var/preserve/config</code> directory, with a couple of files in it.  Those files are not meant to be editing, and they’ll be opaque to us for the rest of the tutorial.  As usual, I’d advise you to secure that directory so only <code>root</code> can read and write files to it.</p>

<p>Now, you’ll create two directories directly into the repository.  You’ll use these directories to travel back and forth between known configuration states.</p>

<ul>
<li><code>trunk/</code> will contain the current configuration</li>
<li><code>tags/</code> will contain snapshots (we’ll learn more about them later)</li>
</ul>

<p>To perform this task, just type:</p>

<p><pre>[rudd-o@amauta2 ~]# svn mkdir \
file:///var/preserve/config/trunk/ \
file:///var/preserve/config/tags/ \
-m 'Creating trunk and tags directories'</pre></p>

<p>The <code>-m</code> argument specifies a message to attach to the operation.  You can consult these messages afterwards through the <code>svn log</code> command.</p>

<h2>Preparing the configuration directory</h2>

<p>In true UNIX tradition, <code>/etc</code> is the place to go for system-wide configuration.  For the rest of the tutorial, I’ll assume those are the files you want to keep in check.</p>

<p>To track files in <code>/etc</code>, you need to both:</p>

<ul>
<li>place its contents into the Subversion repository</li>
<li>make it into a working copy</li>
</ul>

<p>That’s easily accomplished via the following command:</p>

<p><pre>[rudd-o@amauta2 ~]# svn checkout \
file:///var/preserve/config/trunk/ /etc</pre></p>

<p>Once you’ve done that, <code>/etc</code> will be a working copy.  Time to add existing files into Subversion.</p>

<h2>Checking existing configuration files into the repository</h2>

<p><pre>[rudd-o@amauta2 ~]# cd /etc
[rudd-o@amauta2 /etc]# svn status</pre></p>

<p>You should see a long listing of files, like this:</p>

<p><pre>?      4Suite
?      acpi
?      adjtime</pre></p>

<p>The question marks at the beginning of each line mean that Subversion has no idea what those files are doing there.  So, you’ll add them to the repository:</p>

<p><pre>[rudd-o@amauta2 /etc]# svn add *</pre></p>

<p>You’ll see <code>svn</code> working intensely to add those files.  Note that the files are not being added to the repository yet &mdash; they’re only being queued for addition.  To commit these files into the repository:</p>

<p><pre>[rudd-o@amauta2 /etc]# svn commit \
-m 'Initial addition of files'</pre></p>

<p>And <code>svn</code> should start doing its magic.  Once it’s done, it’ll tell you the revision number.</p>

<h2>Followup maintenance</h2>

<p>Okay, let’s review a few things you need to keep in mind from now on.</p>

<h3>When configuration files are added to <code>/etc</code></h3>

<p>Check for added files with <code>svn status /etc</code>.  You should see them listed with a question mark.</p>

<p>You should use <code>svn add</code> to add them to the working copy, and then <code>svn commit</code> the added files into the repository.  Many people make the mistake of configuring freshly installed files.  Do not do that.  Instead, <code>commit</code> new files first, then edit.  That way, you’ll have a way to track modifications right back to the pristine configuration files.</p>

<h3>When configuration files are deleted from <code>/etc</code></h3>

<p>Check for deleted files with <code>svn status /etc</code>.  You should see them listed with an exclamation sign.</p>

<p>After doing the check, <code>svn delete</code> them.  Don’t forget to <code>commit</code> at the end.</p>

<h3>Before moving files or directories within <code>/etc</code></h3>

<p>Disregard the standard UNIX <code>coreutils</code> for file management, because they bypass Subversion tracking.  Use <code>svn add</code>, <code>svn copy</code>, <code>svn move</code> and so on.  Don’t forget to <code>commit</code> at the end.</p>

<h3>What to write on log messages</h3>

<p>Use your imagination!  At the very least, you should be typing who did the change, the reasons behind the change and any other related ideas that might be forgotten but needed later on.</p>

<h3>How to view the log and audit changes</h3>

<p>Use <code>svn log /etc</code>.  Adding a <code>--verbose</code> option will show you the paths changed.</p>

<p>You can also obtain a patch (<code>diff</code> output) of changes between revisions.  Use <code>svn diff -r first:last /etc</code>, replacing <code>first</code> and <code>last</code> with the first and last revision numbers you want to use as first and last reference points, respectively.  Remember that <code>HEAD</code> works great when used in place of the last revision.  A plain <code>svn diff /etc</code> will show you the differences in files that haven’t been committed yet, in <code>diff</code> format.</p>

<h3>How to snapshot the configuration and travel between snapshots</h3>

<p>To snapshot the configuration, first ensure no files have changes pending to be committed in <code>/etc</code> (using <code>svn diff /etc</code> and <code>svn commit /etc</code>), then use the following command:</p>

<p><pre>[rudd-o@amauta2 ~]# svn copy \
file:///var/preserve/config/trunk \
file:///var/preserve/config/tags/a-snapshot</pre></p>

<p>replacing <code>a-snapshot</code> with the name of the snapshot you want to take.  Subversion will take a snapshot of the current configuration state.</p>

<p>Seeing what’s changed between two tags or the trunk and a tag is easy:</p>

<p><pre>[rudd-o@amauta2 ~]# svn diff \
file:///var/preserve/config/tags/a-snapshot \
file:///var/preserve/config/tags/a-newer-snapshot</pre></p>

<p><pre>[rudd-o@amauta2 ~]# svn diff \
file:///var/preserve/config/tags/old-snap \
file:///var/preserve/config/tags/trunk</pre></p>

<p>And traveling to a tag, making the whole <code>/etc</code> and its contents go to a known state, is easy as well.</p>

<p><pre>[rudd-o@amauta2 ~]# cd /etc; \
svn switch file:///var/preserve/config/tags/known-state</pre></p>

<p>I don’t recommend making any changes to configuration files and then committing those changes if your <code>/etc</code> directory has been <code>switch</code>ed to a tag, because you’d overwrite the snapshot with those changes.  Better to create a top-level <code>branches/</code> directory in your repository, copy the tag to <code>branches/a-branch-name</code>, switch to the branch <code>a-branch-name</code> and then make changes there.</p>

<h2>Conclusions</h2>

<p>Indeed, adding Subversion to the server management mix introduces extra complexity.  But the gains fairly outweigh the drawbacks.  Clever readers should have noticed, just by skimming this piece, the potential that Subversion has.  Subversion makes auditing, known configuration state restoration, and configuration backups much more deterministic and predictable.</p>

<p>Moreover, common snapshotting tasks can be automated via Vixie <code>cron</code> jobs.  If you know how to serve Subversion repositories through the network, you’ll see that designing, staging and distributing configuration sets and managing them remotely from a central location is incredibly easy.  And there’s so much more Subversion can do to stretch your limited available time.  If you want to know more, there’s always the Subversion book (aptly named <q>Version control with Subversion</q>).</p>

<p>And that’s my cue to continue my day job.  Happy hacking!</p>
]]></content:encoded>
			<wfw:commentRss>http://rudd-o.com/archives/2006/03/14/tracking-auditing-and-managing-your-server-configuration-with-subversion-in-10-minutes/feed/</wfw:commentRss>
		</item>
		<item>
		<title>5 minutes to finding issues in production PHP Web applications</title>
		<link>http://rudd-o.com/archives/2006/03/10/5-minutes-to-finding-issues-in-production-php-web-applications/</link>
		<comments>http://rudd-o.com/archives/2006/03/10/5-minutes-to-finding-issues-in-production-php-web-applications/#comments</comments>
		<pubDate>Fri, 10 Mar 2006 22:41:19 +0000</pubDate>
		<dc:creator>Rudd-O</dc:creator>
		
		<category><![CDATA[Free software]]></category>

		<category><![CDATA[Linux]]></category>

		<category><![CDATA[PHP]]></category>

		<category><![CDATA[Programming]]></category>

		<category><![CDATA[Server management]]></category>

		<guid isPermaLink="false">http://rudd-o.com/archives/2006/03/10/5-minutes-to-finding-issues-in-production-php-web-applications/</guid>
		<description><![CDATA[Detecting and correcting problems with applications at early stages is an important role of the server manager.  Unfortunately, not all errors are detected at the testing stages.  Even more unfortunate is the fact that most errors go undetected because they are usually triggered when a certain set of criteria is met.



Since all you [...]]]></description>
			<content:encoded><![CDATA[<p>Detecting and correcting problems with applications at early stages is an important role of the server manager.  Unfortunately, not all errors are detected at the testing stages.  Even more unfortunate is the fact that most errors go undetected because they are usually triggered when a certain set of criteria is met.</p>

<p><span id="more-828"></span></p>

<p>Since all you have is 5 minutes (which is one of the tenets of this Server management series, and quite possibly the only simple truth in your case), in this installment, we&#8217;ll unlock the secret of server log foraging.</p>

<h2>All you need is <code>grep</code>.</h2>

<p>I don&#8217;t know what the Beatles would say about this heading, but, indeed, <code>grep</code> is all you need.</p>

<p>This guide is laid out in two distinct sections:</p>

<ul>
<li>Configuring PHP to report errors</li>
<li>Actually mulling over the server logs</li>
</ul>

<p>I&#8217;m assuming you&#8217;re using Apache on Linux, of course.  I will also assume you have access to your server logs and write permission to the PHP configuration file (usually <code>/etc/php.ini</code>).</p>

<h2>Configuring PHP to report errors</h2>

<p>Okay, fire up your trusty editor of choice (I use <code>nano</code>, and that&#8217;s only because I&#8217;m accustomed to <code>pico</code> &mdash; no longer shipped with any Free Software distro &mdash; and please let&#8217;s not get into an editor flamefest here) while being <code>root</code>.  Open <code>/etc/php.ini</code> and look for the following configuration keys:</p>

<p><pre>display_errors = On</pre></p>

<p>Set it to <code>Off</code>.  Production PHP applications should not reveal any bugs to the outside world.  For the true hacker, the log files will say all that&#8217;s needed.  And, for that, change the following configuration key:</p>

<p><pre>error_reporting = E_ALL</pre></p>

<p>Set it to <code>E_ALL</code>, because you&#8217;re interested in warnings, notices and errors.  Finally, look for the following configuration key:</p>

<p><pre>log_errors = Off</pre></p>

<p>and set it to <code>On</code>.  Save the file, and restart Apache (<a href="post:tuning-an-apache-server-in-5-minutes">here&#8217;s how</a>).</p>

<p>Let the application run for a couple of minutes (or hours, depending on your visitor volume).</p>

<h2><code>grep</code>ping the logs</h2>

<p>Now it&#8217;s time to start working on those logs.  Locate your Apache error log file (usually at <code>/var/log/httpd/error_log</code>.  Then use the following command to find all PHP-related error messages:</p>

<p><pre>grep PHP /var/log/httpd/error_log</pre></p>

<p>That may spit out a hefty amount of messages, so you&#8217;ll probably want to redirect it into a file:</p>

<p><pre>grep PHP /var/log/httpd/error_log &gt; /root/phperrors</pre></p>

<p>The greater-than symbol directs the output of <code>grep</code> into the file <code>/root/phperrors</code>.</p>

<p>Inspect the newly created file with your favorite editor and look for messages.  Does any of them say <code>PHP Fatal Error</code> or <code>PHP Error</code>?  If so, you&#8217;ve got a real problem between hands.  Warnings are also a cause for concern, because they usually mean an error occurred in your application, but the application just kept going like nothing happened.  Notices aren&#8217;t so much a concern, but they should be dealt with individually, because they usually point to common programming mistakes that must be fixed.</p>

<p>The PHP log messages provide you with another useful tidbit of information: they say the file and line number of the error, notice or warning:</p>

<p><code>PHP Warning:  strtotime() [client 157.100.84.91] PHP Warning:  strtotime(): Called with an empty time parameter. in /home/rudd-o/public_html/links.php on line 53, referer: http://rudd-o.com/index.php</code></p>

<p>That information is very useful to find the source of the problem.</p>

<h2>Conclusions</h2>

<p>Whether you have to fix errors yourself, or there&#8217;s a dedicated team behind the Web applications you&#8217;re overseeing, any PHP-related messages usually pinpoint to issues that need to be paid attention to.</p>

<p>It&#8217;s also a good idea to automate this procedure into a shell or <code>CGI</code> script for the developers of the applications you oversee.  That way, they&#8217;ll have a way to get early notice of any issues, and you won&#8217;t need to be involved in the process.  Here&#8217;s an example shell script that would send those messages to someone at your company, to be run through <code>cron</code>:</p>

<p><pre>#!/bin/bash</pre></p>

<p>grep PHP /var/log/httpd/error_log | \
    mail -s 'PHP messages' someone@yourcompany.com
</p>

<p>Finally, this procedure should also be standard on testing and staging servers.  Finding a problem early on the development stage is invaluable.  You really don&#8217;t know how many customers you may lose to bugs that slip into production.</p>

<p>And that&#8217;s it for today!  Remember, keep your Web applications bug-free, and they&#8217;ll give lots of value in return.  Happy hacking!</p>
]]></content:encoded>
			<wfw:commentRss>http://rudd-o.com/archives/2006/03/10/5-minutes-to-finding-issues-in-production-php-web-applications/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Making Windows XP join a SAMBA domain in 5 minutes</title>
		<link>http://rudd-o.com/archives/2006/03/08/making-windows-xp-join-a-samba-domain-in-5-minutes/</link>
		<comments>http://rudd-o.com/archives/2006/03/08/making-windows-xp-join-a-samba-domain-in-5-minutes/#comments</comments>
		<pubDate>Wed, 08 Mar 2006 21:12:34 +0000</pubDate>
		<dc:creator>Rudd-O</dc:creator>
		
		<category><![CDATA[Free software]]></category>

		<category><![CDATA[Server management]]></category>

		<category><![CDATA[Software bacán]]></category>

		<guid isPermaLink="false">http://rudd-o.com/archives/2006/03/08/making-windows-xp-join-a-samba-domain-in-5-minutes/</guid>
		<description><![CDATA[How to get a Windows XP Professional or Server to join a SAMBA domain running on a Linux server.]]></description>
			<content:encoded><![CDATA[<p>Okay, let’s move on with the Server management series.  This time we’ll learn how to make a Windows XP server join a SAMBA domain name server.</p>

<p><span id="more-823"/></p>

<p>Print these instructions out and post them on a wall or a bulletin board in your office.  If you have a sizable park of Windows computers to manage, learn them by heart.  They may be very useful to you in the near future.</p>

<p>These instructions work if you’re running a SAMBA domain server on Linux or any other UNIX, and your domain server is not using LDAP services to store SAM information, but the standard SAMBA TDB files.</p>

<p>Three steps are all that’s required, if you have a properly configured SAMBA server (regrettably, out of the scope of this 5-minute topic).</p>

<h2>Add the machine account on the server</h2>

<p>Okay, time to do this.  As root, on the console, add a UNIX user account, with the following command:</p>

<p><pre>[root@amauta2 ~]# /usr/sbin/useradd 'machinename$'</pre></p>

<p>That should create a UNIX user account that, by default, has a disabled password.  So it won’t be useable as an interactive shell or graphical login account.  But, anyways, remember to replace <code>machinename</code> with the machine name you intend to set on the XP computer.  Do note that the <code>useradd</code> command may be on a different directory than <code>/usr/sbin</code> on your computer.</p>

<p>Please note that the single quotes are relevant.  Otherwise, they would be unprotected by the shell’s variable replacing tendency.</p>

<p>Now run the following command:</p>

<p><pre>[root@amauta2 ~]# smbpasswd -ma 'machinename'</pre></p>

<p>This command actually creates the machine account on the SAMBA server.</p>

<h2>Disable <code>RequireSignOrSeal</code></h2>

<p><a href="http://rudd-o.com/archives/2006/03/08/making-windows-xp-join-a-samba-domain-in-5-minutes/#comment-4573" title="Making Windows XP join a SAMBA domain in 5 minutes">According to a contributor</a>, you can skip this step if you’re using SAMBA 3 or higher.  But if you aren’t, then it’s time to disable a setting that makes Windows XP complain when attempting to join a SAMBA domain.  The famed <code>RequireSignOrSeal</code>.</p>

<p>Physically go to the Windows XP computer.  Log on using an administrative account (Administrator comes to mind) on the local machine.  Open the Registry editor (<code>regedit.exe</code>).    Now open the key named:</p>

<p><pre>My Computer\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Netlogon\Parameters</pre></p>

<p>You’ll see, on the right pane, a key named <code>requiresignorseal</code>. Double-click it and set the value data to <code>0</code>.  If it doesn’t exist, create a key named <code>requiresignorseal</code> of type <code>REG_DWORD</code> and set it to <code>0</code>.</p>

<p>Now, that machine is ready to join the SAMBA domain.</p>

<h2>Configure the machine to join the domain</h2>

<p>Open the Properties tab of My Computer.  Click the <em>Computer Name</em> tab, and click the <em>Change</em> button.</p>

<p>The computer name should be the same as the name of the machine account you created in the first step.  On the <em>Member of:</em> group, click <em>Domain</em>, and type the domain name you’ve configured in the SAMBA server.</p>

<p>Click OK.  A password prompt will surprise you.  Enter the <code>root</code> user name and the root password of the SAMBA server, and hit OK.  In the few moments after you’ve hit OK, Windows XP and SAMBA will be negotiating the process of joining the domain.</p>

<p>f everything went OK, you’ll see a <em>Welcome to the XYZ domain</em> popup.  If something went wrong, you’ll have a hard time figuring out what went wrong; the first place to go is the SAMBA log file.</p>

<h2>Conclusions</h2>

<p>Okay, that’s it.  You’ve successfully integrated one of the most pervasive unfree software packages to your trusty SAMBA server.</p>

<p>These instructions are bound to change in the future, as the SAMBA team continues to move aggresively towards LDAP.  But, in the meantime, for small- to medium-sized businesses, the ideal SAMBA setup won’t be needing LDAP magic anytime.</p>

<p>In case you want more information on the subject, there’s always <a href="http://www.samba.org/samba/docs/man/Samba-HOWTO-Collection/ClientConfig.html#id2545087">the Windows XP section of the SAMBA Client configuration HOWTO</a>.  That’s all for today.  Happy hacking!</p>
]]></content:encoded>
			<wfw:commentRss>http://rudd-o.com/archives/2006/03/08/making-windows-xp-join-a-samba-domain-in-5-minutes/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Tuning a MySQL server in 5 minutes</title>
		<link>http://rudd-o.com/archives/2006/03/02/tuning-a-mysql-server-in-5-minutes/</link>
		<comments>http://rudd-o.com/archives/2006/03/02/tuning-a-mysql-server-in-5-minutes/#comments</comments>
		<pubDate>Thu, 02 Mar 2006 23:39:11 +0000</pubDate>
		<dc:creator>Rudd-O</dc:creator>
		
		<category><![CDATA[Free software]]></category>

		<category><![CDATA[Linux]]></category>

		<category><![CDATA[Programming]]></category>

		<category><![CDATA[Publicaciones]]></category>

		<category><![CDATA[Server management]]></category>

		<guid isPermaLink="false">http://rudd-o.com/archives/2006/03/02/tuning-a-mysql-server-in-5-minutes/</guid>
		<description><![CDATA[Continuing with the Server management series, this time we’ll learn how to tune a MySQL server to handle high server loads.  Obviously, this piece assumes that you’re using MySQL to serve a dynamic site.  If this is not the case, you’ll still find this article useful, but you’ll have to derive your own [...]]]></description>
			<content:encoded><![CDATA[<p>Continuing with the Server management series, this time we&#8217;ll learn how to tune a MySQL server to handle high server loads.  Obviously, this piece assumes that you&#8217;re using MySQL to serve a dynamic site.  If this is not the case, you&#8217;ll still find this article useful, but you&#8217;ll have to derive your own interpretations out of it.</p>

<p><span id="more-805"></span></p>

<p>If you recall the article titled <a href="post:tuning-an-apache-server-in-5-minutes">Tuning an Apache server in 5 minutes</a>, you&#8217;ll also know that there&#8217;s a tunable for Apache which lets you set the maximum number of Apache processes that run on your server.  Once you&#8217;ve tuned Apache, it only makes sense to tune MySQL to handle that many connections simultaneously.</p>

<p>Before you go on, &#8220;Tuning a MySQL server in 5 minutes&#8221; is indeed an exaggeration.  I concede you that.  Database tuning is so much more than what this article says.  I don&#8217;t mean to disrespect DBAs: they usually perform large amounts of magic in order for databases to get from abysmal to top-dog performance.  But the first step to having a site that doesn&#8217;t break with traffic surges is usually what I&#8217;m about to discuss.</p>

<h2>Tips for very high loads</h2>

<p>Okay, on to our business.  First off, if you&#8217;re handling a very large number of simultaneous connections to your Apache server (in the order of 250 or higher), it would make sense to offload the database processing to a different server.  That way, you&#8217;ll have more control over loads exerted by Apache and by MySQL, separately.</p>

<p>If you&#8217;re short on money, that&#8217;s of course not an option.  Keep reading to find out an acceptable compromise then.</p>

<h2>The (important) differences between static and dynamic page loads</h2>

<p>For the purpose of this article, we&#8217;ll name two distinct types of connections to your Web server:</p>

<dl><dt>Dynamic requests</dt><dd>Any request to your Apache server that causes a MySQL connection to be opened and database queries to be emitted. A good example is a PHP page which requests a list of products from your database.</dd><dt>Static requests</dt><dd>Any request to your Apache server which doesn&#8217;t incur the cost of a MySQL connection.  Examples of these are static HTML pages or file downloads.</dd></dl>

<p>And, of course, you&#8217;ll need to discriminate between those two.</p>

<h2>Figuring out the right maximum number of MySQL connections</h2>

<p>Usually, a good starting estimate is one dynamic request for each 5 requests.  That&#8217;s because most pages load CSS style sheets, and images, although those files do not get loaded on subsequent requests from the same visitors (partly due to browser caching).  To get an exact number for this ratio, however, you&#8217;ll need to analyze your Apache <code>access_log</code> log file (manually, or via the known <a href="http://www.analog.cx/">Analog</a> or <a href="http://www.mrunix.net/webalizer/">Webalizer</a> log analysis packages).</p>

<p>Once you&#8217;ve arrived to an accurate estimate for your scenario, multiply that ratio by the maximum number of connections you&#8217;ve configured on your Apache server.  For example, if your Apache server is serving a maximum of 256 clients (which is <em>a lot</em>), and your ratio of dynamic requests vs. all requests is 1/8, you&#8217;d have an expected maximum of 32 database connections.  Just to be on the safe side, multiply that by two, and you&#8217;ll have a foolproof figure.  <em>But if you want to be really, really certain, you should always expect a maximum of 256 database connections</em>.</p>

<h2>Setting the maximum connections on your MySQL server</h2>

<p>Using your favorite text editor, as <code>root</code>, open up the <code>/etc/my.cnf</code> file (the location of the file may vary according to your distribution).  You should see something like this:</p>

<p><pre>[ecuagol@216-55-181-30 ~]$ cat /etc/my.cnf
[mysqld]
safe-show-database
innodb_data_file_path=ibdata1:10M:autoextend
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock</pre></p>

<p>[mysql.server]
user=mysql
basedir=/var/lib</p>

<p>[safe_mysqld]
err-log=/var/log/mysqld.log
pid-file=/var/run/mysqld/mysqld.pid
</p>

<p>We&#8217;ll be dealing with the <code>[mysqld]</code> section. Under that section, add two new parameters (or modify them, if they are already there and they aren&#8217;t commented):</p>

<ul>
<li><code>set-variable = max_connections = 60</code></li>
<li><code>set-variable = max_user_connections = 60</code></li>
</ul>

<p>MySQL defaults to 1 max connection, with 1 max connection per user.  Evidently, you&#8217;ll be replacing <code>60</code> with your expected maximum number of connections.  With these settings, you&#8217;ll be on the safe side.</p>

<p>The reason you&#8217;re setting both <code>max_connections</code> and <code>max_user_connections</code> is because, generally, Apache appears to your MySQL database server as one single user. So, you need to raise them both.</p>

<p>You may also want to increase other parameters, if you&#8217;ll be expecting heavy loads or unusual queries:</p>

<ul>
<li><code>set-variable = max_allowed_packet=1M</code> (sanity check to stop runaway queries) </li>
<li><code>set-variable = max_connect_errors=999999 </code></li>
<li><code>set-variable = table_cache=1200</code></li>
</ul>

<p>Where <code>1200</code> should be <code>max_user_connections</code> multiplied by the maximum number of <code>JOIN</code>s your heaviest SQL query contains.</p>

<p>After tuning your server, restart MySQL (<code>/sbin/service mysqld restart</code> usually does the trick on Fedora Core).</p>

<h2>Conclusions and final words</h2>

<p>That&#8217;s it!  Hope I&#8217;ll see you around for the next installment. By the way, if you spot any inaccuracies or errors, feel free to comment on it using the comment form right below this article.  Happy hacking!</p>
]]></content:encoded>
			<wfw:commentRss>http://rudd-o.com/archives/2006/03/02/tuning-a-mysql-server-in-5-minutes/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Tuning an Apache server in 5 minutes</title>
		<link>http://rudd-o.com/archives/2006/03/01/tuning-an-apache-server-in-5-minutes/</link>
		<comments>http://rudd-o.com/archives/2006/03/01/tuning-an-apache-server-in-5-minutes/#comments</comments>
		<pubDate>Wed, 01 Mar 2006 21:04:36 +0000</pubDate>
		<dc:creator>Rudd-O</dc:creator>
		
		<category><![CDATA[Free software]]></category>

		<category><![CDATA[Linux]]></category>

		<category><![CDATA[Programming]]></category>

		<category><![CDATA[Publicaciones]]></category>

		<category><![CDATA[Server management]]></category>

		<guid isPermaLink="false">http://rudd-o.com/archives/2006/03/01/tuning-an-apache-server-in-5-minutes/</guid>
		<description><![CDATA[Hello again.  This time, I’ll show you how to make a Web server running Apache and Linux survive heavy loads.



Before we go on, you should know something: this is not an article about securing Apache.  This is an article about making Apache behave under heavy load conditions.

Okay, now that we’re here, let’s discuss [...]]]></description>
			<content:encoded><![CDATA[<p>Hello again.  This time, I&#8217;ll show you how to make a Web server running Apache and Linux survive heavy loads.</p>

<p><span id="more-794"></span></p>

<p>Before we go on, you should know something: this is not an article about securing Apache.  This is an article about making Apache behave under heavy load conditions.</p>

<p>Okay, now that we&#8217;re here, let&#8217;s discuss scalability.</p>

<h2>Scalability</h2>

<p>Scalability is simply the ability of a server to withstand heavy loads.  If you tried to read the last article, <a href="post:hardening-a-linux-server-in-10-minutes">Hardening a Linux server in 10 minutes</a>, you probably noticed that this server was down.</p>

<p>That&#8217;s a scalability fault.</p>

<p>Let&#8217;s put it in another light.  This server has 512 MB of RAM.  The surge of traffic (thanks to LinuxToday links pointing to this site) caused the server to fail (more accurately, the MySQL server appeared to hang).  Brag all you want about Linux&#8217;s ability to survive these events, nothing will help you against a misconfigured server.</p>

<h2>It all boils down to configuration</h2>

<p>In this particular case, the misconfiguration was Apache&#8217;s.  Weighing 13 MB per <code>httpd</code> process (though some of it is shared with other processes), it&#8217;s pretty simple to understand that a runaway Apache server can bring your server down completely.  When your Apache server starts serving a lot of requests, all those processes quickly fill the available memory (physical <em>and</em> virtual).  When your Linux server runs out of RAM, it will start killing processes it deems &#8216;memory hogs&#8217;.  Usually the first ones to go down are the MySQL processes.  If you&#8217;re serving dynamic pages, that&#8217;s a disaster.</p>

<h2>On to Apache configuration</h2>

<p>By default, Apache comes preconfigured to serve a maximum of 256 clients simultaneously.  This particular configuration setting can be found in the file <code>/etc/httpd/conf/httpd.conf</code> (though the location of the file may vary, depending on the Linux distribution you use).</p>

<p>Whip your favorite text editor out and open that file (remember that you should be doing this as <code>root</code> &mdash; the administrative account on the majority of Linux servers out there).</p>

<p>Look for <code>MaxClients</code>.  It will probably look like this:</p>

<p><pre># prefork MPM</pre></p>

<h1>StartServers: number of server processes to start</h1>

<h1>MinSpareServers: minimum number of server processes which are kept spare</h1>

<h1>MaxSpareServers: maximum number of server processes which are kept spare</h1>

<h1>ServerLimit: maximum value for MaxClients for the lifetime of the server</h1>

<h1>MaxClients: maximum number of server processes allowed to start</h1>

<h1>MaxRequestsPerChild: maximum number of requests a server process serves</h1>

<p>&lt;IfModule prefork.c&gt;
StartServers       4
MinSpareServers    3
MaxSpareServers   10
ServerLimit      256
MaxClients       256
MaxRequestsPerChild  10000
&lt;/IfModule&gt;</p>

<p>That&#8217;s the configuration section for the <code>prefork</code> module.  99% of the Apache servers out there use the prefork module to serve requests, so unless you have an exotic configuration, you&#8217;ll be changing these settings.</p>

<p>Time to calculate a good value for the <code>MaxClients</code> directive.  Find out how much memory your Apache processes use.  Using <code>top</code>, check the <code>RES</code> column.  That&#8217;s the resident memory size.  It should say the size in megabytes that your Apache processes are taking.  In my example, it&#8217;s <code>22m</code>.</p>

<p>Figure out a good value.  If your server has 512 MB of RAM (in my case, this is true), and you&#8217;re sharing your server with MySQL and Sendmail (true in my case, as well), you&#8217;ll want to reserve about half of it for Apache (256 MB).  Divide that by the resident memory each process takes up, and you&#8217;ll have a number of processes (say, 11).  That&#8217;s the maximum amount of processes you can run without resorting to virtual memory.  Resorting to virtual memory (swap) will make your server thrash and become extremely slow.</p>

<p>It&#8217;s, of course, all about balance.  If you have one gigabyte of swap, you may want to raise the number of Apache processes.  Raising it too much will cause heavy traffic to spawn lots of Apache processes, bringing your server down.</p>

<h2>Setting the MaxClients and StartServers directive</h2>

<p>You now have your start value (in our example, it was 11).  Change the <code>MaxClients</code> and the <code>ServerLimit</code> directives to it.  Save the file and restart Apache (<code>/sbin/service httpd restart</code> does that trick in Fedora Core).</p>

<p>Now it&#8217;s time to start testing.  Keep a root login open to that server.  Using your favorite testing tool (<code>ab</code> and <code>wget</code> are good at this), start a storm of connections (more than 1024 simultaneous requests) directed to a page served by your Apache server (ideally, one that exercises the server, like dynamic pages with lots of queries).  Issuing the <code>uptime</code> command in your root login should not yield a load average above 1, and the server should respond to commands quickly.</p>

<p><pre>[rudd-o@amauta2 conf]$ uptime
 15:54:18 up  1:41,  3 users,  load average: 0.86, 0.70, 1.50</pre></p>

<h2>Tuning the configuration</h2>

<p>That&#8217;s great.  Once the test is finished, duplicate <code>MaxClients</code> and <code>StartServers</code>, and try your storm test again.  The load average should be low.</p>

<p>Keep tuning until you hit your maximum desired load average.  For servers used interactively often, having a load above 3 is way too much to use the server comfortably.  For servers used mostly as real servers, a maximum load average of 10 should be acceptable.  More than that, and you&#8217;ll find yourself needing to reboot the server when experiencing heavy traffic conditions, because no terminal or remote console will respond quickly to commands, and managing the server will be impossible.</p>

<h2>Conclusions</h2>

<p>That&#8217;s it!  With practice, you&#8217;ll be able to skip the memory math and learn the ideal setting for any server.  Other tuning options you may try (in order of diminishing returns):</p>

<ul>
<li>Eliminating unnecessary Apache modules from the configuration (perhaps uninstalling them altogether, by use of RPM or your favorite distribution&#8217;s packaging tool)</li>
<li>Recompiling Apache, optimizing for memory consumption (the <code>-Os</code> option of <code>gcc</code>)</li>
<li>Recompiling Apache, building modules in instead of having them run as modules</li>
</ul>

<p>Remember: if you have any questions or suggestions, please leave them as comments below.  Happy hacking!</p>
]]></content:encoded>
			<wfw:commentRss>http://rudd-o.com/archives/2006/03/01/tuning-an-apache-server-in-5-minutes/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Hardening a Linux server in 10 minutes</title>
		<link>http://rudd-o.com/archives/2006/02/27/hardening-a-linux-server-in-10-minutes/</link>
		<comments>http://rudd-o.com/archives/2006/02/27/hardening-a-linux-server-in-10-minutes/#comments</comments>
		<pubDate>Mon, 27 Feb 2006 23:55:56 +0000</pubDate>
		<dc:creator>Rudd-O</dc:creator>
		
		<category><![CDATA[Free software]]></category>

		<category><![CDATA[Information security]]></category>

		<category><![CDATA[Linux]]></category>

		<category><![CDATA[Publicaciones]]></category>

		<category><![CDATA[Server management]]></category>

		<guid isPermaLink="false">http://rudd-o.com/archives/2006/02/27/hardening-a-linux-server-in-10-minutes/</guid>
		<description><![CDATA[Did you know that a freshly installed Linux server can be hardened in less than 10 minutes?  Here’s how!



Print these instructions out, and keep them posted on a wall in your office or home.  Before plugging a freshly installed network server, simply remember to follow these instructions.  Make these instructions second nature [...]]]></description>
			<content:encoded><![CDATA[<p>Did you know that a freshly installed Linux server can be hardened in less than 10 minutes?  Here&#8217;s how!</p>

<p><span id="more-792"></span></p>

<p>Print these instructions out, and keep them posted on a wall in your office or home.  Before plugging a freshly installed network server, simply remember to follow these instructions.  Make these instructions second nature to you.  Just in case you were wondering, a printout of this page will be &#8220;printer-friendly&#8221; because of the stylesheet used in this page.</p>

<p class="information">You&#8217;ll need a bit of experience with the Linux command-line environment, as the following commands are usually issued in a terminal.  You will need root access on your server as well.  By the way, the following instructions apply to any LSB-compliant Linux distribution, but I&#8217;ll use Fedora Core as an example.</p>

<p>Step 1: turn all unneeded services off</p>

<p>There are two kinds of network services:</p>

<ul>
<li>those that get started as <code>init.d</code> services</li>
<li>those that get started by <code>xinetd</code></li>
</ul>

<p>This distinction is important, as <code>xinetd</code> can start services on demand, while services started through <code>init.d</code> run all the time.</p>

<p>Okay, time to start securing your server.  On a terminal, as root (and, for the purposes of this tutorial, assume this from now on) run <code>netstat -ltunp</code>.  You should see a listing like this one:</p>

<p><pre>[root@andrea rudd-o]# netstat -ltunp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address               Foreign Address             State       PID/Program name
tcp        0      0 0.0.0.0:3493                0.0.0.0:*                   LISTEN      30562/upsd
tcp        0      0 0.0.0.0:3306                0.0.0.0:*                   LISTEN      12461/mysqld
tcp        0      0 0.0.0.0:6543                0.0.0.0:*                   LISTEN      12490/mythbackend
tcp        0      0 0.0.0.0:111                 0.0.0.0:*                   LISTEN      1771/portmap
tcp        0      0 0.0.0.0:6544                0.0.0.0:*                   LISTEN      12490/mythbackend
tcp        0      0 127.0.0.1:631               0.0.0.0:*                   LISTEN      31537/cupsd
tcp        0      0 127.0.0.1:25                0.0.0.0:*                   LISTEN      2143/sendmail: acce
tcp        0      0 :::80                       :::*                        LISTEN      5024/httpd
tcp        0      0 :::22                       :::*                        LISTEN      2009/sshd
tcp        0      0 0.0.0.0:19                  0.0.0.0:*                   LISTEN      2019/xinetd</pre></p>

<p></p>

<p>Those are all processes listening to specific ports.  As you can see, the PID (process ID) and the program name are displayed as well.</p>

<p>Make two lists:
- one for the services you absolutely need (which you should already know by heart), and
- one for the services that are expendable or you can start manually when they&#8217;re needed (tip:  each program name usually ships with a man page).</p>

<p>Shutdown each service on the second list (except for <code>xinetd</code>)  That&#8217;s a pretty straightforward task.  Each one of those services are started by <code>init.d</code>.  To find out the name of the service control script, just hop to <code>/etc/rc.d/init.d</code> and look for a file with a name similar to the program name.</p>

<p>Example: suppose I don&#8217;t need <code>mythbackend</code>.  To stop it: <code>/etc/rc.d/init.d/mythbackend stop</code> (some distributions provide the <code>service mythbackend stop</code> command, which is easier on your fingers).  Now, to disable it: <code>chkconfig --del mythbackend</code>.  After doing this, you should check to see if the offending service went away, with the same <code>netstat -ltunp</code> command.</p>

<h3>That pesky <code>xinetd</code></h3>

<p>Great.  So you got rid of the unneeded services.  But there&#8217;s more.  As we saw earlier, <code>xinetd</code> has its own ways.  In practice, this means that some services will be started on demand &mdash; thus, you won&#8217;t see them under your <code>netstat -ltunp</code> listing.</p>

<p>To find out which services <code>xinetd</code> manages, hop to <code>/etc/xinetd.d</code> and do a directory listing.  You should see some service configuration files.  Identify the ones you won&#8217;t be using, and edit each one of them, adding a line that says <code>disable = yes</code> between the curly braces.</p>

<p>Note that some services already ship with <code>disable = yes</code>, but some ship with <code>disable = no</code>.  If one of the configuration files says <code>disable = no</code>, just change it to <code>disable = yes</code>.  Now reload <code>xinetd</code> with the famous <code>/etc/rc.d/init.d/xinetd reload</code>, and run <code>netstat -ltunp</code> again, just to be sure.</p>

<p>That&#8217;s step 1.  With a bit of practice, you should be doing this in five minutes or less.</p>

<h2>Step 2: limit access to running services using <code>iptables</code></h2>

<p>Great, our server now runs the absolutely required services, and no more.  But some of those services aren&#8217;t meant to be accessed from everywhere, right?  For example: I may have a MySQL database server running, but that doesn&#8217;t mean MySQL should be accessible from any random IP address on the Internet, right?</p>

<p>So, we&#8217;ll use the firewall to stop evil at the door.  Again, make a list of services.  For each item on the list, identify which IP addresses should be able to reach the service.  For each service on your list, write down the TCP/UDP port(s) they use.</p>

<p>In my example, MySQL uses TCP port 3306, and should only be accessible by <code>localhost</code> (<code>127.0.0.1</code>).</p>

<p>Time to compose and activate the <code>iptables</code> rules.  Doing a quick check with <code>iptables -L</code>, I can see that my INPUT chain (the one I&#8217;ll be working with, since I want to disallow INPUTs to my server) is empty:</p>

<p><pre>[root@andrea xinetd.d]# iptables -L
Chain INPUT (policy ACCEPT)
target     prot opt source               destination</pre></p>

<p>Chain FORWARD (policy ACCEPT)
target     prot opt source               destination</p>

<p>Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination
</p>

<p>Your mileage may vary, because your distribution may already have set up some basic <code>iptables</code> rules; to make these instructions foolproof, I will be inserting rules at the beginning of the INPUT chain.</p>

<p>In this case, I want to allow access to <code>127.0.0.1:3306</code>, and deny access to everyone else on port <code>3306</code>, in that order.  So two rules are needed.  I&#8217;ll add the &#8220;allow&#8221; rule into position 1 (the very first):</p>

<p><pre>[root@andrea xinetd.d]# iptables -I INPUT 1 --protocol tcp --destination-port 3306 -s 127.0.0.1 -j ACCEPT
[root@andrea xinetd.d]# iptables -L
Chain INPUT (policy ACCEPT)
target     prot opt source               destination
ACCEPT     tcp  --  localhost.localdomain  anywhere            tcp dpt:mysql
</pre></p>

<p>Great.  I&#8217;m telling the firewall to <code>-j ACCEPT</code> all <code>--protocol tcp</code> connections to <code>--destination-port 3306</code> from the address <code>-s 127.0.0.1</code>.  Now, I&#8217;ll insert the &#8220;deny&#8221; rule into position 2:</p>

<p><pre>[root@andrea xinetd.d]# iptables -I INPUT 2 --protocol tcp --destination-port 3306 -j REJECT
[root@andrea xinetd.d]# iptables -L
Chain INPUT (policy ACCEPT)
target     prot opt source               destination
ACCEPT     tcp  --  localhost.localdomain  anywhere            tcp dpt:mysql
REJECT     tcp  --  anywhere             anywhere            tcp dpt:mysql reject-with icmp-port-unreachable
</pre></p>

<p>See how easy it is?  Let me explain: rule 2 tells the firewall to <code>-j REJECT</code> all <code>--protocol tcp</code> connections to <code>--destination-port 3306</code> from any address (since I omitted the address).  Since rules are processed &#8220;top-down&#8221; (from 1 to <em>n</em>), the first one that matches an incoming connection is applied.  If no rules match, then the default policy (which is normally <code>ACCEPT</code>) kicks in.</p>

<p>Lather. Rinse. Repeat for every service that you want to secure.</p>

<p>Finally, save the rules.  For this, you&#8217;ll need to use your distribution&#8217;s tools.  For Fedora Core, that&#8217;s as easy as issuing the command <code>service iptables save</code> and ensuring that the <code>iptables</code> service runs at boot time: <code>chkconfig --add iptables</code>.</p>

<p>It&#8217;s worth noting that some people prefer to <code>-j DROP</code> instead of <code>DENY</code>ing.  <code>DROP</code> means that your server will ignore connection attempts (neither denying connections nor accepting them).  I prefer <code>DENY</code>, because it&#8217;s easier to pinpoint a problem with <code>iptables</code> rules that way, and (most importantly) <code>DROP</code> rules make those ports appear as <q>filtered</q> to a hostile port scanner (which hints to the attacker that a service is running).</p>

<p>So that&#8217;s it, from insecure to secure in 10 minutes!  If you have any suggestions or questions, please leave them as comments below.  Happy hacking!</p>
]]></content:encoded>
			<wfw:commentRss>http://rudd-o.com/archives/2006/02/27/hardening-a-linux-server-in-10-minutes/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Why swap on Linux is always good, even with tons of RAM</title>
		<link>http://rudd-o.com/archives/2006/01/11/why-swap-is-good-even-with-tons-of-ram/</link>
		<comments>http://rudd-o.com/archives/2006/01/11/why-swap-is-good-even-with-tons-of-ram/#comments</comments>
		<pubDate>Wed, 11 Jan 2006 22:24:26 +0000</pubDate>
		<dc:creator>Rudd-O</dc:creator>
		
		<category><![CDATA[Linux]]></category>

		<category><![CDATA[Server management]]></category>

		<guid isPermaLink="false">http://rudd-o.com/archives/2006/01/11/why-swap-is-good-even-with-tons-of-ram/</guid>
		<description><![CDATA[Lately, I’ve been wondering if it’s at all convenient to disable swap on Linux, when memory is so cheap nowadays.  Of course, having tons of RAM is a great thing: the more code and data the operating system can maintain into RAM, the faster the system will go.  Ideally, you’d want to have [...]]]></description>
			<content:encoded><![CDATA[<p>Lately, I’ve been wondering if it’s at all convenient to disable swap on Linux, when memory is so cheap nowadays.  Of course, having tons of RAM is a great thing: the more code and data the operating system can maintain into RAM, the faster the system will go.  Ideally, you’d want to have as much physical RAM as needed to keep all your frequently-used programs and their data in memory.</p>

<p>I ended up keeping swap active.  And here’s why.</p>

<p><span id="more-688"/></p>

<h2>But… I do have enough RAM for my programs… so I disabled swap.  What’s the dillio?</h2>

<p>But, if you had enough RAM to keep the entire working set in memory (in other words, to keep both data and code for all your running programs in main memory, at all times), why would you want swap?  More concretely, if you had 512 MB of RAM, and your open programs occupied 490 MB of RAM, why would you need swap?</p>

<p>We all know using the disk as swap is slow.  So, many people eliminate swap from their systems as soon as they install lots of RAM.  And one of the biggest benefits of having lots of RAM is caching.  Linux will attempt to cache disk files as aggressively as possible.  Taking a page from the example I just concocted, if all I had left is (512-490) = 22 MB of free RAM, Linux would only be able to cache 22 MB of data.</p>

<h2>Caching and program startup speed</h2>

<p>Why is that figure important? Because, by now, you’ve probably noticed that the slowest operation on Linux is loading an application (especially big ones, like OpenOffice.org).  But what you probably don’t know is that most of the time used to load an application is spent on disk accesses: firing up OpenOffice.org causes at least 130 MB of mostly small files to be read from the disk, and those disk accesses add up dramatically, mainly because of disk seek time.</p>

<p>You’ve also probably noticed that loading the same application a little while later takes a much shorter time.  Why is that?  It’s the cache who’s responsible of this big speedup: if Linux avoids reading files from disk, it runs much, much faster.</p>

<p>It’s also clear that having 22 MB available for a disk cache is just not enough to have OpenOffice.org start in less than 10 seconds, whether it’s the first time you’re starting it, or you just ran it a few moments ago and you’re running it again.</p>

<p>Most other everyday operations are affected.  Opening folders in Nautilus or Konqueror are good examples.</p>

<h2>So, how does swap actually enter the RAM equation here?  What’s Linux not telling me?</h2>

<p>It’s unbelievably simple, although not apparent at first.</p>

<p>Most running programs have code paths and data in memory that they rarely, if ever, touch.  I would be bold and say most program-allocated memory is very rarely touched, but I might be wrong.  So, the RAM taken up by unused code and data would actually be better utilized as cache for frequently-used files (or, even more beneficial, inode and dentry cache).</p>

<p>Having a swap partition gives Linux a space to put those rarely-used code paths and data segments on disk, freeing memory for the disk cache and new tasks.  (Actually, shared libraries, unlike program data, can be evicted from RAM and re-read again from the shared library files when needed, but this incurs more disk seeks and computation effort than reading them back from swap, so if Linux has swap available for use, it’ll always prefer to put the shared libraries’ memory into swap).</p>

<p>The more memory available for the cache, the faster the response for frequently-performed tasks (like opening your huge MP3 folder… or my own huge MP3 folder, with Nautilus).</p>

<p>And that’s exactly why having swap is beneficial: unused code and data can be evicted from RAM, and that RAM can be put to better use.  Even if you had over a gigabyte of physical RAM, that RAM would be better utilized as disk cache instead of being taken up by unused code.  I’m not kidding: swap can make the difference between zero disk reads and three hundred disk reads.</p>

<p>This becomes more critical when low on RAM: imagine if the system were able to cache those 22 MB plus a 150-something MB of RAM, gotten by evicting unused stuff?  Seen under that light, starting OpenOffice.org up is beginning to sound even doable, right?</p>

<p>There’s another reason, but it’s not performance-related.  Some applications do allocate and consume a lot of memory.  If you were to load several of those applications, the possibility of hitting zero free memory without swap is greater.  And hitting zero memory is not good, because the system will kill processes it deems “memory hogs”.  Best-case scenario: the application you just started dies.  Worst-case scenario: a system daemon providing vital services (in my computer, it would be MythTV recording an episode of Nip/Tuck) dies.  No one wants that!</p>

<p>In short: don’t skimp on swap.  I do not believe in the 2.5X formula for swap (RAM times two point five).  But I do keep twp half-a-gigabyte swap partitions (on different disks, in separate controllers, with equal priorities for added performance, and not the disk I use for MythTV) mounted at all times.</p>

<p>And how much RAM should you buy?  As a general rule, if having all your commonly-used applications open causes the system to become slow (especially when opening the GNOME or KDE panel menu, or switching between applications), with applications appearing to “hang” for a couple of moments, that’s your cue to get more RAM: double it.</p>

<p>A faster processor won’t help at all, seeing as most of the time is spent on reading and writing to the disk swap partition.  More swap won’t save you from this occurrence (indeed, it’s the accesses into swap which is making your applications “hang”), but not having it would be even worse for system performance (seeing as your system would still be short on memory, and it wouldn’t have a space to put unused data away).</p>

<p>What might help, if you’re short on money and long on free disk space, is setting up two swap partitions, each on a different disk connected to a different controller, and mounted with the same priority.</p>

<p>But remember that deciding to not be a cheap bastard and getting more RAM is the best course of action.</p>
]]></content:encoded>
			<wfw:commentRss>http://rudd-o.com/archives/2006/01/11/why-swap-is-good-even-with-tons-of-ram/feed/</wfw:commentRss>
		</item>
	</channel>
</rss>
