<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	xmlns:series="http://unfoldingneurons.com/"
	>

<channel>
	<title>Stephen Foskett, Pack Rat &#187; Apache Archives  &#8211; Stephen Foskett, Pack Rat</title>
	<atom:link href="http://blog.fosketts.net/tag/apache/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.fosketts.net</link>
	<description>Understanding the accumulation of data</description>
	<lastBuildDate>Fri, 10 Feb 2012 17:40:43 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=</generator>
<atom:link rel="hub" href="http://pubsubhubbub.appspot.com" />
	<atom:link rel="hub" href="http://superfeedr.com/hubbub" />
			<item>
		<title>How To Force Apache To Redirect To Canonical Hostnames, or ServerAlias Is Not Your Friend</title>
		<link>http://blog.fosketts.net/2010/08/01/force-apache-redirect-canonical-hostnames-serveralias-friend/</link>
		<comments>http://blog.fosketts.net/2010/08/01/force-apache-redirect-canonical-hostnames-serveralias-friend/#comments</comments>
		<pubDate>Sun, 01 Aug 2010 15:19:42 +0000</pubDate>
		<dc:creator>Stephen</dc:creator>
				<category><![CDATA[Enterprise storage]]></category>
		<category><![CDATA[Everything]]></category>
		<category><![CDATA[Apache]]></category>
		<category><![CDATA[Google]]></category>
		<category><![CDATA[HTTP]]></category>
		<category><![CDATA[lighttpd]]></category>
		<category><![CDATA[redirect]]></category>
		<category><![CDATA[SEO]]></category>
		<category><![CDATA[ServerAlias]]></category>
		<category><![CDATA[VirtualHost]]></category>

		<guid isPermaLink="false">http://blog.fosketts.net/?p=3475</guid>
		<description><![CDATA[Today I came up against a frustrating realization: Apache doesn't have a satisfying way to redirect multiple domains to canonical hostnames! In other words, it's fairly easy to redirect one domain's content from "www.example.com" to just plain "example.com" or to make both hostnames work, but there's no one-stop solution to do this with a dozen domains. I've hit on a method that correctly redirects alternate hostnames and will save you aggravation in the long run.]]></description>
			<content:encoded><![CDATA[<p>Yesterday I discussed <a href="http://blog.fosketts.net/2010/07/30/high-performance-memory-apache-php-virtual-private-server/"  target="_blank">how to set up a lightweight PHP web server using Apache</a>. Next we have to get everything running smoothly, and I came up against a frustrating realization: Apache doesn&#8217;t have a satisfying way to redirect multiple domains to canonical hostnames! In other words, it&#8217;s fairly easy to redirect one domain&#8217;s content from &#8220;www.example.com&#8221; to just plain &#8220;example.com&#8221; or to make both hostnames work, but there&#8217;s no one-stop solution to do this with a dozen domains. But I&#8217;ve hit on a method that correctly redirects alternate hostnames and will save you aggravation in the long run.</p>
<h3>The Easy Way</h3>
<p>Apache is one amazingly flexible web server. It handles multiple domains with ease, using the VirtualHost method, and the ServerAlias directive allows you to host permutations easily. Consider the following totally made-up example:</p>
<pre>&lt;VirtualHost *:80&gt;
  ServerName blog.fosketts.net
  ServerAlias www.blog.fosketts.net
  ServerAlias fosketts.net
  ServerAlias www.fosketts.net
  DocumentRoot /var/www/
&lt;/VirtualHost&gt;</pre>
<p>This looks great, right? It tells Apache to watch any IP on port 80 for an HTTP request for a server called blog.fosketts.net and to serve it the content from /var/www/. It also tells Apache to accept plain old &#8220;fosketts.net&#8221;, &#8220;www.fosketts.net&#8221;, and even &#8221;www.blog.fosketts.net&#8221;.</p>
<h3>What&#8217;s Wrong With Easy?</h3>
<p>Although accepting all these hostnames seems like the friendly and correct thing to do, it&#8217;s not in your best interest. It tells web clients that the exact same content lives on four different servers, and they&#8217;ll start linking to your content every which way. Pretty soon you&#8217;ll have incoming links for all four hostnames. So what&#8217;s wrong with this?</p>
<ol>
<li><strong>It&#8217;s confusing for users</strong> &#8211; They&#8217;ll start asking, &#8220;is your site www.fosketts.net or blog.fosketts.net?&#8221; It&#8217;s fine to segment things, but confusing to do it unnecessarily.</li>
<li><strong>It&#8217;s hard to configure and maintain</strong> &#8211; Once your site starts getting linked to and shared around, you&#8217;re stuck supporting all possible combinations. When you switch hosts or server platforms (<a href="http://blog.fosketts.net/2010/07/30/high-performance-memory-apache-php-virtual-private-server/"  target="_blank">ahem</a>) you have to make sure everything still works.</li>
<li><strong>It hurts your search ranking</strong> &#8211; You might not be all that concerned with search engine placement, and <a rel="nofollow" href="http://googlewebmastercentral.blogspot.com/2008/09/demystifying-duplicate-content-penalty.html"  target="_blank">it&#8217;s not as bad</a> <a href="http://www.seomoz.org/blog/gonna-set-it-straight-this-watergate"  target="_blank">as some say</a>, but splitting your traffic between multiple sites also splits your &#8220;SEO juice&#8221;.</li>
<li><strong>Web crawls overload your servers</strong> &#8211; Search engines treat each host name as a different server. If you allow links to multiple names without a proper redirect, you&#8217;ll get multiple crawls, often at the same time.</li>
</ol>
<p>In summary, the easy was isn&#8217;t good. ServerAlias looks friendly, but it&#8217;s not a friend when used this way.</p>
<p>Let&#8217;s say your name was Stephen, but some people call you Steve. Rather than insist on one or the other, you could just go through life accepting either. But imprecision can lead to issues, even in the real world. Will people know to look up Stephen in the company directory when they know you as Steve? You might start getting duplicate junk mail for both names as they find their way onto mailing lists. Then there&#8217;s the embarrassing &#8220;I always called him Steve&#8221; moment at the company party, when someone feels like they&#8217;re not part of the &#8220;in crowd&#8221; that knows your real name. It&#8217;s best to be friendly and accept anything but politely suggest that everyone uses just one name in the interest of sanity.</p>
<h3>Redirection is Right</h3>
<p>The best approach in life is also the correct method on the web. Your server should be set to accept any number of possible names in case someone comes in with the wrong one. But rather than blithely accepting the name, your server should issue a proper &#8220;redirect&#8221; call, instructing the browser or crawler to reload the page using the correct name from that point on.</p>
<p>This is simple when using Lighttpd. I just added the following lines to my lighttpd.conf file and it magically issued a proper redirect whenever someone came in using the &#8220;www&#8221; name:</p>
<pre>$HTTP["host"] =~ "^www\.(.*)$" {
  url.redirect  = (
    "^/(.*)" =&gt; "http://%1/$1",
  )
}</pre>
<p>I was amazed that I could locate no such universal redirect option in Apache. You can do all the RedirectMatch calls you want, but their regular expressions only operate on the path part of the URL, not the hostname. This is great for adding a &#8220;www&#8221; but makes it impossible to create a generic rule to eliminate them!</p>
<p>Instead, we have to use RedirectMatch on each VirtualHost domain individually. This also opens the possibility to deal with other conditions we might come across, but it&#8217;s not as simple and clean as the Lighttpd method.</p>
<p>Here&#8217;s where the magic is. Each VirtualHost configuration you add (in /etc/apache2/sites-available on Ubuntu) should include rules to deal with the incorrect names as well as the single correct one. Here&#8217;s the correct redirect rule for the example above:</p>
<pre>&lt;VirtualHost *:80&gt;
  ServerName fosketts.net
  ServerAlias www.fosketts.net
  ServerAlias www.blog.fosketts.net
  RedirectMatch 301 (.*) http://blog.fosketts.net$1
&lt;/VirtualHost&gt;

&lt;VirtualHost *:80&gt;
  DocumentRoot /var/www/
  ServerName blog.fosketts.net
&lt;/VirtualHost&gt;</pre>
<p>The first VirtualHost block matches all the incorrect hostnames and redirects them (with a code of 301 for &#8220;Permanent&#8221;) to the correct hostname. The &#8220;(.*)&#8221; part matches any and all paths and arguments and the &#8220;$1&#8243; part appends them to the new hostname. Then we set up another VirtualHost block for only the correct hostname and put any and all rules in there.</p>
<p>This way, any clients or crawlers that hit &#8220;www.fosketts.net&#8221; or any of the other alternatives will get a proper 301 redirect to &#8220;blog.fosketts.net&#8221; and go about its business. It tells Google that there is only one proper server name for this content and encourages users (who will likely copy and paste from the address bar) to use it, too. Neat and tidy, and very friendly.</p>
<p>I&#8217;d love to hear alternative methods of doing this. Please leave a comment if you have a suggestion that uses a 301 redirect and works across multiple domains!</p>
<div id="crp_related"><h3>You might also want to read these other posts...</h3><ul><li><a href="http://blog.fosketts.net/2010/07/30/high-performance-memory-apache-php-virtual-private-server/"  rel="bookmark" class="crp_title">A High-Performance, Low-Memory Apache/PHP Virtual Private Server</a></li><li><a href="http://blog.fosketts.net/2009/06/26/multiserver-web-host-environment/"  rel="bookmark" class="crp_title">Setting Up a Multi-Server Web Hosting Environment</a></li><li><a href="http://blog.fosketts.net/guides/ipad-exchange-activesync/ipad-exchange-activesync-troubleshooting-guide/"  rel="bookmark" class="crp_title">iPad Exchange ActiveSync Troubleshooting Guide</a></li><li><a href="http://blog.fosketts.net/2011/04/26/5307/"  rel="bookmark" class="crp_title"></a></li><li><a href="http://blog.fosketts.net/2009/06/29/tuning-lighttpd-linux/"  rel="bookmark" class="crp_title">Tuning Lighttpd For Linux</a></li></ul></div><script src="http://feeds.feedburner.com/~s/sfoskett?i=http://blog.fosketts.net/2010/08/01/force-apache-redirect-canonical-hostnames-serveralias-friend/" type="text/javascript" charset="utf-8"></script><hr />
<p><small>© sfoskett for <a href="http://blog.fosketts.net">Stephen Foskett, Pack Rat</a>, 2010. |
<a href="http://blog.fosketts.net/2010/08/01/force-apache-redirect-canonical-hostnames-serveralias-friend/">How To Force Apache To Redirect To Canonical Hostnames, or ServerAlias Is Not Your Friend</a>
<br/>
This post was categorized as <a href="http://blog.fosketts.net/category/everything/enterprisestorage/" title="View all posts in Enterprise storage" rel="category tag">Enterprise storage</a>, <a href="http://blog.fosketts.net/category/everything/" title="View all posts in Everything" rel="category tag">Everything</a>. Each of my categories has its own feed if you'd like to filter out or focus on posts like this.<br/>
</small></p>]]></content:encoded>
			<wfw:commentRss>http://blog.fosketts.net/2010/08/01/force-apache-redirect-canonical-hostnames-serveralias-friend/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
	
		<series:name><![CDATA[Web Hosting]]></series:name>
	</item>
		<item>
		<title>A High-Performance, Low-Memory Apache/PHP Virtual Private Server</title>
		<link>http://blog.fosketts.net/2010/07/30/high-performance-memory-apache-php-virtual-private-server/</link>
		<comments>http://blog.fosketts.net/2010/07/30/high-performance-memory-apache-php-virtual-private-server/#comments</comments>
		<pubDate>Fri, 30 Jul 2010 18:16:38 +0000</pubDate>
		<dc:creator>Stephen</dc:creator>
				<category><![CDATA[Computer History]]></category>
		<category><![CDATA[Everything]]></category>
		<category><![CDATA[Personal]]></category>
		<category><![CDATA[Apache]]></category>
		<category><![CDATA[CGI]]></category>
		<category><![CDATA[FCGI]]></category>
		<category><![CDATA[lighttpd]]></category>
		<category><![CDATA[mod_fcgi]]></category>
		<category><![CDATA[mpm-worker]]></category>
		<category><![CDATA[Netscape]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[php-cgi]]></category>
		<category><![CDATA[Slicehost]]></category>
		<category><![CDATA[Ubuntu]]></category>
		<category><![CDATA[WordPress]]></category>
		<category><![CDATA[WP-SuperCache]]></category>

		<guid isPermaLink="false">http://blog.fosketts.net/?p=3472</guid>
		<description><![CDATA[I've previously written about my Multi-Server Web Hosting Environment and the how I Tuned Lighttpd For Linux to run as well as possible. But I've been having weird issues with that setup lately and was forced to rebuild the server entirely. While I was at it, I decided to give Apache another try, since the lighttpd hackery I needed to perform to get things like WP-SuperCache running were starting to get me down. The configuration documented here uses Ubuntu Lucid (10.04), Apache 2.2, FCGI, and PHP-CGI tuned for a 512 MB virtual private server (VPS) running on Rackspace Slicehost.]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve previously written about my <a href="http://blog.fosketts.net/2009/06/26/multiserver-web-host-environment/" >Multi-Server Web Hosting Environment</a> and the how I <a href="http://blog.fosketts.net/2009/06/29/tuning-lighttpd-linux/" >Tuned Lighttpd For Linux</a> to run as well as possible. But I&#8217;ve been having weird issues with that setup lately and was forced to rebuild the server entirely. While I was at it, I decided to give Apache another try, since the lighttpd hackery I needed to perform to get things like WP-SuperCache running were starting to get me down. The configuration documented here uses Ubuntu Lucid (10.04), Apache 2.2, FCGI, and PHP-CGI tuned for a 512 MB virtual private server (VPS) running on Rackspace Slicehost.</p>
<h3>A Brief History of the Web</h3>
<p>I&#8217;ve been pretty happy with lighttpd as my web server. It&#8217;s light and quick and has a workable fastcgi/PHP implementation. Right out of the box, lighttpd kicks Apache up and down the block on low-memory servers &#8211; the kind you&#8217;ll find in virtual private server hosting companies.</p>
<p>To understand why lighttpd is so good, we have to understand why Apache is so bad. And this means going way back in time to the dawn of the web. In the beginning, web servers were single-threaded processes that slapped pages over network connections on demand. This is like a single lemonade stand, where every customer waits in line but there&#8217;s only one item on offer and it&#8217;s a quick serve. So the line moves pretty quickly but it&#8217;s not all that interesting.</p>
<p>The Netscape Navigator browser revolutionized end-user experience by downloading web page elements in parallel and displaying them as they came in. Web servers responded by &#8220;forking&#8221; multiple copies of themselves to handle these requests (and those from other users) in parallel. Our lemonade stand is still limited in selection, but it now has more workers to hand over the juice.</p>
<p>At the same time, users began demanding more-interesting content. Web 2.0 replaced the old static HTML pages and graphics with interactive web applications, and the PHP language became dominant. Today, most popular web software (including WordPress and Mediawiki) require a PHP interpreter as well as an HTTP server to run. In the old days, server-side compute was handled by a &#8220;back room&#8221; CGI task. Our lemonade counter is now a restaurant, with a kitchen and added a variety of hot foods. But customers (and servers) have to wait while these are cooked up.</p>
<p>The Apache answer to this challenge was to add a kitchen to every checkout position. Out of the box, installing Apache and PHP adds a complete PHP runtime to each Apache process. And since the Apache PHP module is reputed to be unstable in multi-threaded environments, these default setups use the &#8220;prefork&#8221; single-thread-per-process method of handling multiple connections. Now our imaginary fast food restaurant can handle an unlimited number of customers in parallel, right?</p>
<p>In practice, this doesn&#8217;t work well. A 50-position counter could handle tons of customers, but that would be one wide restaurant! The same issue crops up with Apache. It looks super-speedy until loaded up (say, with a midnight Google, Yahoo, or MSN crawl) when it promptly uses up all of your memory forcing the OOM killer to murder your system. The only way to get this default (mod_php/mpm-prefork) version of Apache to be stable, other than adding RAM, is to limit the number of processes spawned. Customers are now back to waiting in line for just a few servers and their experience suffers.</p>
<h3>Lighty Did It, Apache Didn&#8217;t?</h3>
<p>Lighttpd (&#8220;lighty&#8221;) is totally different. It is a small, lightweight HTTP server that farms out PHP tasks to a constantly-running PHP process. This sounds pretty much exactly like the single-kitchen CGI approach of the mid-1990&#8242;s, but there&#8217;s a trick here (as there was then) that makes it work. In traditional CGI, the command processor was started on demand and closed when its work was done. Like a short-order cook, PHP-CGI makes everything to order.</p>
<p>But Netscape had a better idea. They built an always-running server (NSAPI) that could save work in a cache and reuse it for the next visitor. Suddenly we have a full kitchen up and running, complete with prep and sous chefs, able to turn orders around almost as quickly as the servers placed them. FastCGI was an open implementation of this concept, and it allows little lighttpd processes to serve up complex PHP web sites with ease.</p>
<p>Apache has a similar capability, using the modern FCGI implementation, and has also added multi-threaded server capability called mpm-worker. But the multi-threaded server is reputedly unstable when running PHP as a module, and configuring both mpm-worker and mod_fcgi isn&#8217;t yet standard-issue for Apache installs. So most Apache users still use the old prefork/mod_php configuration while most lighttpd users now rely on fastcgi.</p>
<p>Now, these FCGI PHP processes aren&#8217;t exactly light. Each can use 100 MB or more, especially when xcache is used for faster processing. So a lightweight server still needs to limit the number of &#8220;kitchens&#8221; serving the customers. And using a separate process to handle PHP isn&#8217;t as speedy as having an integrated PHP engine. But having more light HTTP servers to move files around reduces the overall load on the system, even if complicated tasks might have to wait for PHP processing.</p>
<p>Then there&#8217;s WP-SuperCache. This WordPress plugin converts complicated PHP pages into simple HTML for the HTTP server to hand off to visitors. In combination with a lightweight server like Apache/mpm-worker or Lighttpd, WP-SuperCache speeds up WordPress sites dramatically.</p>
<p>Although it&#8217;s possible to convince Lighttpd to play nicely with WP-SuperCache (using mod_magnet), it&#8217;s much easier and better-supported in Apache. I was also having an odd issue with Lighttpd &#8220;pausing&#8221; for a few seconds when clients connected it. So I decided to make the switch back to Apache.</p>
<h3>Configuring Apache With MPM-Worker and Mod_FCGI/PHP-CGI</h3>
<p>Now for the technical details. WP-SuperCache and Lighttpd might be poorly-documented, but Mod_FCGI in Apache isn&#8217;t much better. There are a dozen ways to do everything, and everyone&#8217;s recipe differs. Here&#8217;s how I got it to work.</p>
<p>First, I spun up a fresh 512 MB VPS on Slicehost running Ubuntu 10.04 Lucid. I configured it my normal way (locking down access, setting up a restrictive firewall, and installing only basic packages) and rsync-ed over my web site content.</p>
<p>One goal when tuning a server is to use all of the RAM but not much of the swap. Unused RAM is wasted potential, while swapping processes can quickly kill performance. This is one reason to run Apache with FCGI: You can run just a few heavy (large RAM footprint) PHP engines and many more light (3-5 MB) HTTP servers. Using the multi-threaded mpm-worker mode allows each of those Apache processes to serve more requests with less process creation and destruction.</p>
<p>My next step was to install Apache and its required modules along with mpm-worker, mod_fcgi, php5-cgi, and the rest needed to support wordpress. I think the following command should do the trick:</p>
<pre>sudo apt-get install apache2-mpm-worker libapache2-mod_fcgi \
php5-cgi php5-xcache php5-mysql wordpress</pre>
<p>This won&#8217;t work out of the box. We have to set up some wrapper scripts and configuration files for fcgi and php-cgi, but more important is the tuning, which we&#8217;ll get to next.</p>
<p>First, create a php-cgi wrapper for FCGI to use. I called mine /usr/local/bin/php-wrapper and set up a very basic environment. Be sure to make this script executable, too.</p>
<pre>#!/bin/sh
# Set desired PHP_FCGI_* environment variables.
# Example:
# PHP FastCGI processes exit after 500 requests by default.
PHP_FCGI_MAX_REQUESTS=1000
export PHP_FCGI_MAX_REQUESTS
# DO NOT SET PHP_FCGI_CHILDREN!
# Replace with the path to your FastCGI-enabled PHP executable
exec /usr/bin/php-cgi</pre>
<p>As the script comment says, whatever you do, do not set PHP_FCGI_CHILDREN in some misguided attempt to conserve RAM. It will conflict with mod_fcgi and you&#8217;ll end up spawning RAM-hungry but useless child processes and killing your system!</p>
<p>Next, create an fcgi configuration file called /etc/apache2/conf.d/php-fcgid.conf and containing something like the following lines:</p>
<pre>FcgidInitialEnv PHPRC=/etc/php5/cgi
FcgidInitialEnv PHP_FCGI_MAX_REQUESTS 1000
# FcgidMaxRequestsPerProcess should be &lt;= PHP_FCGI_MAX_REQUESTS
# The example PHP wrapper script overrides the default PHP setting.
FcgidMaxRequestsPerProcess 1000
FcgidMaxProcesses 3
FcgidMaxProcessesPerClass 3
FcgidMinProcessesPerClass 1
# Uncomment the following line if cgi.fix_pathinfo is set to 1 in php.ini:
# FcgidFixPathinfo 1
# This makes php scripts work everywhere Apache serves
&lt;Location /&gt;
AddHandler fcgid-script .php
Options +ExecCGI
FcgidWrapper /usr/local/bin/php-wrapper .php
# Customize the next two directives for your requirements.
Order allow,deny
Allow from all
&lt;/Location&gt;</pre>
<p>This is a very permissive configuration, and you might want to tweak things somewhat. But you get the general idea. The important things going on here are the configuration of FCGI to launch just 3 PHP-CGI engines and the assignment of the php-wrapper script to files ending in &#8220;php&#8221; anywhere Apache finds them. This means no special configuration is needed in VirtualHost directives, or anywhere else really.</p>
<p>One more tweak I like is to limit Apache to just 6 worker processes. Since each is multi-threaded and under 5 MB in this configuration, this works well. Add a line to /etc/apache2/apache2.conf in the &#8220;&lt;IfModule mpm_worker_module&gt;&#8221; section saying the following. This is a good complement to the default setting of 25 ThreadsPerChild and  150 MaxClients.</p>
<pre>ServerLimit             6</pre>
<p>Limiting the number of php-cgi processes launched is critical for low-memory systems. A good-sized opcode cache (thanks to xcache) helps them perform well but grows the memory usage like crazy. Although I had just three php-cgi processes running, with one topping 225 MB, overall system performance remained good thanks to WP-SuperCache and six multi-threaded lightweight Apache HTTP servers.</p>
<p>So far, I&#8217;m able to serve multiple WordPress and Mediawiki sites with a few thousand pageviews per day on a 512 MB slice. Running with six Apache workers and 3 or 4 php-cgi processes just gets me under the RAM limit. Of course, I&#8217;m still using a separate 256 MB server for MySQL in addition.</p>
<div id="crp_related"><h3>You might also want to read these other posts...</h3><ul><li><a href="http://blog.fosketts.net/2009/06/26/multiserver-web-host-environment/"  rel="bookmark" class="crp_title">Setting Up a Multi-Server Web Hosting Environment</a></li><li><a href="http://blog.fosketts.net/2010/08/01/force-apache-redirect-canonical-hostnames-serveralias-friend/"  rel="bookmark" class="crp_title">How To Force Apache To Redirect To Canonical Hostnames, or ServerAlias Is Not Your Friend</a></li><li><a href="http://blog.fosketts.net/2009/06/29/tuning-lighttpd-linux/"  rel="bookmark" class="crp_title">Tuning Lighttpd For Linux</a></li><li><a href="http://blog.fosketts.net/2009/02/07/apologies-404s/"  rel="bookmark" class="crp_title">Apologies For The 404s!</a></li><li><a href="http://blog.fosketts.net/2010/03/25/robocopy-multi-threaded/"  rel="bookmark" class="crp_title">Robocopy: Better, Faster, Stronger</a></li></ul></div><script src="http://feeds.feedburner.com/~s/sfoskett?i=http://blog.fosketts.net/2010/07/30/high-performance-memory-apache-php-virtual-private-server/" type="text/javascript" charset="utf-8"></script><hr />
<p><small>© sfoskett for <a href="http://blog.fosketts.net">Stephen Foskett, Pack Rat</a>, 2010. |
<a href="http://blog.fosketts.net/2010/07/30/high-performance-memory-apache-php-virtual-private-server/">A High-Performance, Low-Memory Apache/PHP Virtual Private Server</a>
<br/>
This post was categorized as <a href="http://blog.fosketts.net/category/everything/computerhistory/" title="View all posts in Computer History" rel="category tag">Computer History</a>, <a href="http://blog.fosketts.net/category/everything/" title="View all posts in Everything" rel="category tag">Everything</a>, <a href="http://blog.fosketts.net/category/everything/personal/" title="View all posts in Personal" rel="category tag">Personal</a>. Each of my categories has its own feed if you'd like to filter out or focus on posts like this.<br/>
</small></p>]]></content:encoded>
			<wfw:commentRss>http://blog.fosketts.net/2010/07/30/high-performance-memory-apache-php-virtual-private-server/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
	
		<series:name><![CDATA[Web Hosting]]></series:name>
	</item>
		<item>
		<title>Setting Up a Multi-Server Web Hosting Environment</title>
		<link>http://blog.fosketts.net/2009/06/26/multiserver-web-host-environment/</link>
		<comments>http://blog.fosketts.net/2009/06/26/multiserver-web-host-environment/#comments</comments>
		<pubDate>Sat, 27 Jun 2009 00:00:32 +0000</pubDate>
		<dc:creator>Stephen</dc:creator>
				<category><![CDATA[Personal]]></category>
		<category><![CDATA[Apache]]></category>
		<category><![CDATA[Dreamhost]]></category>
		<category><![CDATA[eaccelerator]]></category>
		<category><![CDATA[FriendConnect]]></category>
		<category><![CDATA[iptables]]></category>
		<category><![CDATA[lighttpd]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[MediaWiki]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[performance]]></category>
		<category><![CDATA[Rackspace]]></category>
		<category><![CDATA[security]]></category>
		<category><![CDATA[Slicehost]]></category>
		<category><![CDATA[ssh]]></category>
		<category><![CDATA[sudo]]></category>
		<category><![CDATA[Ubuntu]]></category>
		<category><![CDATA[VPS]]></category>
		<category><![CDATA[WordPress]]></category>
		<category><![CDATA[XCache]]></category>

		<guid isPermaLink="false">http://blog.fosketts.net/?p=2121</guid>
		<description><![CDATA[The last few weeks have been tough on my web servers. The release of iPhone OS 3.0 tripled my site traffic overnight as folks investigate the new Exchange integration features, and traffic to IT commentary site, Gestalt IT, which I also host, has been growing rapidly. Plus, Google just refreshed PageRank again, sending even more [...]]]></description>
			<content:encoded><![CDATA[<p>The last few weeks have been tough on my web servers. The release of <a href="http://blog.fosketts.net/2009/06/16/iphone-exchange-activesync-integration-30/"  target="_blank">iPhone OS 3.0</a> <strong>tripled my site traffic overnight</strong> as folks investigate the new Exchange integration features, and traffic to IT commentary site, <a href="http://gestaltit.com"  target="_blank">Gestalt IT</a>, which I also host, has been growing rapidly. Plus, <a href="http://blog.fosketts.net/2009/05/27/google-recalculated-pagerank/"  target="_blank">Google just refreshed PageRank</a> again, sending even more visitors my way.</p>
<p>I had <a href="http://blog.fosketts.net/2009/02/07/apologies-404s/"  target="_blank">switched from Dreamhost to Slicehost</a> back in February to improve reliability and performance, but the meagre 256 MB of RAM in my virtual private server (VPS) &#8220;slice&#8221; proved insufficient. The time had come to completely redo my core hosting infrastructure. After some experimentation, I have settled on <strong>a simple two-server configuration based on Ubuntu Linux, MySQL, and lighttpd</strong>. I thought it would be a good idea to document this new configuration, as well as my previous experiments, for posterity.</p>
<blockquote><p>If you&#8217;re interested in setting up a web site as outlined here, <a href="https://manage.slicehost.com/customers/new?referrer=31e5d9e0da4b70b80d0cb0bcc8efc95a"  target="_blank">I recommend Slicehost</a>. They&#8217;re not the cheapest, but their VPS servers are fast and reliable.</p></blockquote>
<h3>History</h3>
<p>My web hosting environment has transitioned over the past six months. I had relied on shared hosting from Dreamhost for almost a decade, with my servers sharing infrastructure and management with thousands of others. This worked fine until I began to see significant traffic increases since creating this blog. <strong>Shared hosting just didn&#8217;t cut it once I had more than a few thousand pageviews per day</strong>.</p>
<p>I tried Dreamhost&#8217;s interesting and very flexible virtual private server capabilities, but could never get them working reliably. Plus, the core networking and storage performance of the Dreamhost infrastructure left something to be desired. After much research I switched to Slicehost, an all-VPS provider that has recently been acquired by Rackspace. Although they are not the cheapest or most flexible, <strong>Slicehost is a very professional service with good support and excellent infrastructure and connectivity</strong>.</p>
<p>I had been using a single 256 MB slice to host my entire site, and had managed to get everything well with lighttpd and MySQL, but this configuration ran into serious performance issues once traffic built again. Once I passed 10,000 pageviews per day, which happened quicker than I hoped, it was again time to upgrade.</p>
<h3>Server Configuration</h3>
<p>My core question was whether to go with a single 512MB or two 256 MB slices. <strong>Would resource contention in a single server be outweighed by the extra available RAM?</strong> After consulting with the experts, I decided that it was time to separate the database and web servers.</p>
<div id="attachment_2122" class="wp-caption aligncenter" style="width: 451px;  border: 1px solid #dddddd; background-color: #f3f3f3; padding-top: 4px; margin: 10px; text-align:center; display: block; margin-right: auto; margin-left: auto;"><a href="http://blog.fosketts.net/wp-content/uploads/2009/06/Web-slice-setup.png" ><img class="size-full wp-image-2122 " title="Web slice setup" src="http://blog.fosketts.net/wp-content/uploads/2009/06/Web-slice-setup.png" alt="A multi-server setup delivers performance, reliability, and future capability." width="441" height="193" /></a><p style=' padding: 0 4px 5px; margin: 0;'  class="wp-caption-text">A multi-server setup delivers performance, reliability, and future capability.</p></div>
<p>As illustrated above, the database and web servers communicate via a high-speed private network, a standard Slicehost component. I created extremely restrictive iptables firewall policies to control access to both servers, disabling almost all communication. The database server in particular is inaccessible except from the web server, and even then only allows MySQL and public key ssh. Both servers are running bare-bones versions of Ubuntu 9.04.</p>
<h3>MySQL Configuration</h3>
<p><strong>MySQL is much happier on its own dedicated server</strong>. It makes excellent use of its own query cache and operating system buffers and has very little disk access at all. Query performance immediately jumped, and site performance noticeably improved.</p>
<p>My only change to my.cnf was to enable the query cache. This works great on my 256 MB slice:</p>
<pre># Enable query cache
query_cache_limit       = 2M
query_cache_size        = 32M</pre>
<p>I&#8217;m not a believer in security through obscurity. Sure, you can use a special high MySQL port, but by then you&#8217;ve probably lost anyway. Regardless, set up iptables to only allow access from your web server&#8217;s private interface using the -s parameter:</p>
<pre># Allow connections on our MySQL port
-A INPUT -p tcp --dport mysql -s 10.176.x.x -j ACCEPT</pre>
<p>It&#8217;s a pretty simple configuration, but it works well. MySQL is humming along without much paging at all, using the entirety of the 256 MB available for caching. I haven&#8217;t had to resort to any tricks to keep the performance up.</p>
<p>One more configuration suggestion: <strong>Use a unique username and password for each database application</strong> and <strong>grant access only to that user on the private network interface</strong>. That way, your risk is segmented to a single database should an intruder use a SQL injection or something similar.</p>
<p>For example, say you were configuring the database &#8220;myblog_wp&#8221; for the user &#8220;me_myblog&#8221; with the password &#8220;123456abcdef&#8221;. You use the web server&#8217;s private interface address, 10.176.x.x as well so it is harder to get in even if your firewall is breached.</p>
<pre>mysql -u root -p
Enter password:
mysql&gt; grant all on myblog_wp.* to 'me_myblog'@'10.176.x.x' identified by '123456abcdef';</pre>
<p>All set!</p>
<h3>Basic Lighttpd Configuration</h3>
<p>Back on the web server, we <strong>configure iptables to only allow connections to lighttpd on port 80 and ssh</strong> on whatever port you decide. Again, some suggest using a high port for ssh, but if you&#8217;ve configured sshd correctly then using an obscure port number is more likely to be a hassle for you than keep anyone out. Here are some good settings for /etc/ssh/sshd_config:</p>
<pre>PermitRootLogin no
PubkeyAuthentication yes
PasswordAuthentication no
X11Forwarding no
UsePAM no
UseDNS no</pre>
<p>This forces all logins to use established public/private key pairs rather than passwords. <strong>Protect your keys</strong> and you&#8217;re in good shape. Key passphrases are a very good idea here! You&#8217;re also disallowing root in any case, since <strong>you&#8217;re using sudo for all administrative tasks</strong>, right?</p>
<p>Next we need to set up lighttpd. I&#8217;m using the basic packaged versions for ease of maintenance rather than building my own. I also loaded the stock versions of php5 and mysql-client which integrate nicely. I used to use eaccelerator but didn&#8217;t love having to recompile it myself and had some mysterious lockups with it running. So <strong>I went with XCache</strong>, which is developed by the same fine folks who created lighttpd.</p>
<pre>sudo aptitude install mysql-client lighttpd php5-xcache</pre>
<p>Why not use Apache? I actually tested Apache with my site before deciding to use lighttpd. I was able to tweak it to run in 256 MB of RAM by limiting the number of worker processes created to 4, but <strong>Apache just couldn&#8217;t handle the site load</strong>. Connections were stacking up and pageviews dropped as people gave up. <strong>Lighttpd with XCache is blindingly fast</strong> and fits in my 256 MB RAM envelope nicely.</p>
<p>The only real issue I have with lighttpd is that configuration is entirely different from Apache and remains less well-supported. It doesn&#8217;t use with .htaccess files, for example, and rewrites use a unique syntax.</p>
<h3>Lighttpd for WordPress</h3>
<p>Here&#8217;s a basic virtual server for /etc/lighttpd/lighttpd.conf for a WordPress domain:</p>
<pre>$HTTP["host"] =~ "^(blog\.)?yourdomain\.com$" {
  server.name = "yourdomain.com"
  server.document-root = basedir + server.name + "/blog"
  url.access-deny = ( "wp-config.php" )
  dir-listing.activate = "disable"
  url.rewrite-final = (
    # Exclude some directories from rewriting
    "^/(wp-admin|wp-includes|wp-content)/(.*)" =&gt; "$0",
    # Uncomment to exclude Google FriendConnect files
    # "^/(canvas.html|rpc_relay.html)" =&gt; "$0",
    # Exclude .php, robots.txt, favicon.*, and sitemap.xml files at root from rewriting
    "^/(.*.php|sitemap.xml|robots.txt|favicon.*)" =&gt; "$0",
    # Handle WordPress permalinks and feeds
    "^/(.*)$" =&gt; "/index.php/$1"
  )
  accesslog.filename = basedir + "/" + server.name + "/log/blog.access.log"
}</pre>
<p>This configuration accomplishes many of the important tasks of WordPress configuration. Most importantly, <strong>it works</strong>!</p>
<ol>
<li>Permalinks and feeds are correctly redirected so no ugly index.php is used</li>
<li>Critical directories like wp-admin and files like robots.txt still work</li>
<li>Your wp-config.php file is explicitly protected</li>
<li>Directory listings are disabled</li>
<li>A site-specific access log is used (like Apache)</li>
</ol>
<p><strong>I&#8217;d love feedback on this configuration! </strong>One weird thing I&#8217;ve not yet figured out is how to use a site-specific error log. I haven&#8217;t configured pretty MediaWiki links in lighttpd yet, but imagine a similar configuration would work there.</p>
<div id="crp_related"><h3>You might also want to read these other posts...</h3><ul><li><a href="http://blog.fosketts.net/2009/02/07/apologies-404s/"  rel="bookmark" class="crp_title">Apologies For The 404s!</a></li><li><a href="http://blog.fosketts.net/2010/07/30/high-performance-memory-apache-php-virtual-private-server/"  rel="bookmark" class="crp_title">A High-Performance, Low-Memory Apache/PHP Virtual Private Server</a></li><li><a href="http://blog.fosketts.net/2009/06/29/tuning-lighttpd-linux/"  rel="bookmark" class="crp_title">Tuning Lighttpd For Linux</a></li><li><a href="http://blog.fosketts.net/2010/08/01/force-apache-redirect-canonical-hostnames-serveralias-friend/"  rel="bookmark" class="crp_title">How To Force Apache To Redirect To Canonical Hostnames, or ServerAlias Is Not Your Friend</a></li><li><a href="http://blog.fosketts.net/2009/11/30/configure-drobo-dashboard-email-gmail-google-apps/"  rel="bookmark" class="crp_title">How To Configure Drobo Dashboard Email for Gmail and Google Apps</a></li></ul></div><script src="http://feeds.feedburner.com/~s/sfoskett?i=http://blog.fosketts.net/2009/06/26/multiserver-web-host-environment/" type="text/javascript" charset="utf-8"></script><hr />
<p><small>© sfoskett for <a href="http://blog.fosketts.net">Stephen Foskett, Pack Rat</a>, 2009. |
<a href="http://blog.fosketts.net/2009/06/26/multiserver-web-host-environment/">Setting Up a Multi-Server Web Hosting Environment</a>
<br/>
This post was categorized as <a href="http://blog.fosketts.net/category/everything/personal/" title="View all posts in Personal" rel="category tag">Personal</a>. Each of my categories has its own feed if you'd like to filter out or focus on posts like this.<br/>
</small></p>]]></content:encoded>
			<wfw:commentRss>http://blog.fosketts.net/2009/06/26/multiserver-web-host-environment/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
	
		<series:name><![CDATA[Web Hosting]]></series:name>
	</item>
	</channel>
</rss>

