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

<channel>
	<title>Web 2.1</title>
	<atom:link href="http://web.2point1.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://web.2point1.com</link>
	<description>Tim Whitlock&#039;s home in the Blogohedron</description>
	<lastBuildDate>Mon, 30 Aug 2010 21:43:13 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
		<item>
		<title>Varnish with PHP (and WordPress)</title>
		<link>http://web.2point1.com/2010/08/21/varnish-with-php-and-wordpress/</link>
		<comments>http://web.2point1.com/2010/08/21/varnish-with-php-and-wordpress/#comments</comments>
		<pubDate>Sat, 21 Aug 2010 15:34:16 +0000</pubDate>
		<dc:creator>tim</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[caching]]></category>
		<category><![CDATA[performance]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[varnish]]></category>
		<category><![CDATA[wordpress]]></category>

		<guid isPermaLink="false">http://web.2point1.com/?p=544</guid>
		<description><![CDATA[The final stage in speeding up my blog was to add some serious caching to the front of it. This may even have been overkill, because it was already pretty swift under nginx/php-fpm, but cutting out the database connections would speed it up even more. I had a quick go with the W3 Total Cache [...]]]></description>
			<content:encoded><![CDATA[<p>The final stage in <a href="http://web.2point1.com/2010/08/17/now-powered-by-wordpress-3-nginx-and-php-fpm/">speeding up my blog</a> was to add some serious caching to the front of it. This may even have been overkill, because it was already pretty swift under <a href="http://web.2point1.com/2010/08/17/php-fpm-5-3-3-under-nginx/" target="_blank">nginx/php-fpm</a>, but cutting out the database connections would speed it up even more.</p>
<p>I had a quick go with the <a href="http://wordpress.org/extend/plugins/w3-total-cache/" target="_blank">W3 Total Cache</a> WordPress plug-in, but it seems rather biased to running Apache (which I&#8217;m not) and I experienced some strange errors that I failed to immediately fix. Rather than wrestle with it, or try other WordPress caches, I decided to get to grips with <a href="http://varnish-cache.org/" target="_blank">Varnish</a>. This is something I&#8217;d been meaning to do for ages, and of course it isn&#8217;t limited to WordPress &#8211; <a href="http://varnish-cache.org/" target="_blank">Varnish</a> is a fabulous caching solution for whatever site you&#8217;re building.</p>
<p><span id="more-544"></span>The challenge with deploying Varnish to any site is to ensure you cache as much as you can while ensuring dynamic content is fresh when required. With WordPress as an example, the cases are fairly obvious. While logged in to the admin screens you don&#8217;t want to cache anything, but the outside world reading your posts should get cached pages whenever possible. In their simplest forms, these cases <em>almost </em>work out of the box with Varnish, but there are a few gotchas. There is also scope to cache more aggressively if you choose to, and most importantly you&#8217;ll want to ensure that when content is altered, the changes are visible to everyone immediately.</p>
<p><strong>Cookie gotcha no.1 </strong></p>
<p>By default, if you send a cookie to Varnish it assumes quite sensibly that you are in some way expecting dynamic content from the back end. e.g. you may be an admin user, logged in to the site. Of course Varnish can&#8217;t actually know what the cookie is for, so when your browser sends a completely redundant Google Analytics <a href="http://code.google.com/apis/analytics/docs/concepts/gaConceptsCookies.html" target="_blank">UTM cookie</a>, you&#8217;ll miss the cache. On this site, that means Varnish would only serve you a maximum of one cached page per visit.</p>
<p><strong>Anonymous session cookies</strong></p>
<p>If a visitor comments on a WordPress site, they are pseudo-logged-in by way of a simple cookie exchange. This means the site can do niceties like pre-populate comment forms for commenting again. These niceties are exactly that, so if you overlook this functionality and block those cookies you can serve more cached pages. In my case, I am happy to make this trade.</p>
<p>The following snippet from my configuration shows how I&#8217;ve maximised anonymous user caching while ensuring admin users always get dynamic content</p>
<pre>sub vcl_recv {
  # ...
  # admin users always miss the cache
  if( req.url ~ "^/wp-(login|admin)" || req.http.Cookie ~ "wordpress_logged_in_" ){
    return (pass);
  }
  # ignore any other cookies
  unset req.http.Cookie;
  return (lookup);
}</pre>
<p><strong>Purging when content changes</strong></p>
<p>HTTP defines a wealth of cache control headers that allow applications and clients to specify what is to be cached and for how long, etc.. but there is no standard way to tell a cache that certain content is to be purged. This is the main challenge of deploying Varnish to a site like WordPress.  A post may be updated, or a user may comment. You&#8217;ll want to purge any affected pages from the cache immediately, regardless of their original expiry. Putting that business logic into your VCL configuration would be hugely impractical &#8211; it&#8217;s really your application&#8217;s jurisdiction.</p>
<p>I looked at various purging techniques, and by far the best approach in my opinion is for your application to talk directly to the <a href="http://varnish-cache.org/wiki/CLI" target="_blank">Varnish administration CLI </a>which listens on the network on a different port to the cache itself. As long as your backend can access your front end by a secure, internal address, you can execute commands on all your Varnish front ends any time you want from your application.</p>
<p>To achieve this, I first had a look at the <a href="http://wordpress.org/extend/plugins/wordpress-varnish/" target="_blank">wp-varnish plug-in</a> which uses the <a href="http://varnish-cache.org/wiki/VCLExamplePurging" target="_blank">HTTP PURGE</a> method. I don&#8217;t like this approach at all; it&#8217;s very limited, too closely coupled to the VCL config, and also this plug-in doesn&#8217;t purge all pages relating to changes, such as tag and archive indexes.</p>
<p><strong>So, I rolled my own</strong></p>
<p>I started by writing a <a href="http://github.com/timwhitlock/php-varnish/blob/master/VarnishAdminSocket.php" target="_blank">VarnishAdminSocket</a> class, which talks to Varnish from PHP. This was pretty easy to do, because the <em>varnishadm</em> program uses a very basic text-based protocol. This isn&#8217;t designed for WordPress, this is designed for use in any PHP application.</p>
<p>My <a href="http://github.com/timwhitlock/php-varnish" target="_blank"><strong>php-varnish</strong> toolkit is on Github</a>. It includes a <a href="http://github.com/timwhitlock/php-varnish/blob/master/wordpress-plugin.php" target="_blank">WordPress plug-in </a>which I am using on this site and you can see <a href="http://github.com/timwhitlock/php-varnish/blob/master/wordpress-plugin/wordpress.vcl" target="_blank">the VCL configuration</a> I am using too.</p>
]]></content:encoded>
			<wfw:commentRss>http://web.2point1.com/2010/08/21/varnish-with-php-and-wordpress/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>WordPress 3 &#8230; yep, it&#8217;s still WordPress</title>
		<link>http://web.2point1.com/2010/08/21/wordpress-3-is-still-wordpress/</link>
		<comments>http://web.2point1.com/2010/08/21/wordpress-3-is-still-wordpress/#comments</comments>
		<pubDate>Sat, 21 Aug 2010 13:38:42 +0000</pubDate>
		<dc:creator>tim</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[wordpress]]></category>

		<guid isPermaLink="false">http://web.2point1.com/?p=516</guid>
		<description><![CDATA[As part of my &#8220;speeding up my blog&#8221; series, I planned to write a nice, informative post about upgrading to WordPress 3, deploying your theme to a CDN, and getting it all running under nginx. Unfortunately WordPress irritated me so much in the process, that this has turned into more of rant. Sorry in advance. [...]]]></description>
			<content:encoded><![CDATA[<p>As part of my &#8220;<a href="http://web.2point1.com/2010/08/17/now-powered-by-wordpress-3-nginx-and-php-fpm/">speeding up my blog</a>&#8221; series, I planned to write a nice, informative post about upgrading to WordPress 3, deploying your theme to a CDN, and getting it all <a href="http://web.2point1.com/2010/08/17/php-fpm-5-3-3-under-nginx/">running under nginx</a>. Unfortunately WordPress irritated me so much in the process, that this has turned into more of rant. Sorry in advance.</p>
<p>I have a like/hate relationship with WordPress. That is to say that it does a lot, it has a great admin area and there&#8217;s a large community producing themes and plug-ins. However, I am a PHP developer of many years, and every time I come into direct contact with the core WordPress code-base I end up being sick in my mouth.</p>
<p><em><span id="more-516"></span>What&#8217;s to hate?</em> Well it kind of reminds me of that old BMW advert (or was it Audi?) the one with the swan &#8211; On the surface it glides effortlessly, but under the water it&#8217;s an ugly son of a bitch, churning away to get the job done.  I had the misfortune of working on a nasty WPMU project last year and found myself looking under the <a href="http://simple.wikipedia.org/wiki/British_English#Vocabulary_in_British_English" target="_blank">bonnet</a> more than was good for me. Not only is WordPress a horribly written piece of PHP, (and possibly responsible for many a bad word said about PHP itself) it has a legacy of incremental improvements alongside a legacy of community-contributed code that strives to remain as reverse compatible as possible.</p>
<p>If you don&#8217;t want to read my rantings, skip to <a href="#bitattheend">the bit at the end</a>, otherwise &#8230; WordPress, let me count the ways a hate thee.</p>
<p><strong>1. Base URL hell</strong></p>
<p>I wanted to get as much of my static assets onto a CDN as I could &#8211; a topic I&#8217;ll cover in full later. This means serving static files (such as images and css) from a different base URL. It <em>should</em> be simple to upload your theme and plug-in directories to another server and ensure that WordPress points to the correct assets in your HTML. It is not simple. Just look at the <a href="http://codex.wordpress.org/Determining_Plugin_and_Content_Directories" target="_blank">hideousness of determining base URLs in WordPress</a>. This simple task should not require a complex plug-in to cover all possible legacy issues. Furthermore, WordPress allows <em>all</em> plug-ins to mess around with base URLs, which means one plug-in might completely undo the work of another.</p>
<p>Oh, by the way &#8211; WordPress defines the constant <code>WP_CONTENT_URL</code> before it loads any plug-ins, so the only way to override this is to define it in <code>wp-config.php</code>.</p>
<p><strong>2. Canonical domain ridiculousness</strong></p>
<p>If you access a WordPress site from a domain that is not hard-wired into the site&#8217;s database, it will redirect you to the &#8216;correct&#8217; URL. This is the default behaviour. So, if you want to host the same exact site from a different domain, or different port, (e.g. for debugging a distributed system) you will have to write a WordPress plug-in to override this behaviour. Why does this annoy me?</p>
<ol>
<li>It is not PHP&#8217;s job to decide what domain a site lives on &#8211; that is the job of the web server. A domain redirect like this should be done at server config level.</li>
<li>No system should hard-wire its domain into database-saved preferences. This is nuts, and WordPress does it in multiple places.</li>
</ol>
<p><strong>3. Magic quotes are the Devil\\\&#8217;s work</strong></p>
<p>Magic quotes are so utterly evil that they have been <a href="http://php.net/manual/en/security.magicquotes.php" target="_blank">removed from PHP 5.3</a>. They are testament to the amateur reputation of PHP. However, even in earlier versions of PHP, magic quotes could be easily disabled, and anyone who knows what they&#8217;re doing with PHP will have been doing so  for years. Furthermore any system written properly would insist on them being disabled. Not so with WordPress. In fact, being able to disable magic quotes poses a problem for WordPress. How can it guarantee to work if you can forcibly disable magic quotes?</p>
<p>Answer: By forcing them <em>even more forcibly</em>. WordPress 3 forces all script input through its own <code>wp_magic_quotes</code> function. Funnily enough <a href="http://wordpress.org/search/wp_magic_quotes" target="_blank">this isn&#8217;t documented</a>, but <a href="http://gist.github.com/542222" target="_blank">it looks like this</a>. Rather than mess around reversing this process, I wrote <a href="http://gist.github.com/542259" target="_blank">this simple utility</a> for accessing the unharmed postdata.</p>
<p><strong>4. mysqli support &#8211; or not.</strong></p>
<p>The core WordPress code-base uses the old mysql database driver. When I say <em>old</em>, consider that the mysqli (improved) extension was introduced for versions of MySQL &gt; 4.1.3  in PHP 5, which came out of beta in <strong>2004</strong>. WordPress does have a drop-in replacement system though, which allows you to place your own <code>db.php</code> file in <code>wp-content</code>. Here&#8217;s the third-party-developed <a href="http://barahmand.com/2010/06/wordpress-3-and-mysqli/" target="_blank">mysqli adapter for WordPress</a> that I am using on this site.</p>
<p>So that&#8217;s okay then, right? Well, judging by the required location for the <code>db.php</code> file, this adapter system looks rather like an after-thought. Using the alternative database adapter means calling <code>require_wp_db()</code> rather than just including the original <code>wp-includes/wp-db.php</code> file. Great &#8211; except is every plug-in out there doing this? Even WordPress itself isn&#8217;t fully patched to support this. At the time of writing, the &#8220;<em>famous </em>5-minute installer&#8221; uses the mysql adapter only &#8211; I had to <a href="http://gist.github.com/542243" target="_blank">patch wp-admin/install.php</a> to be able to install WordPress with only mysqli on my system.</p>
<p><strong>5. Depreciated code handling</strong></p>
<p>Watch out for depreciated function names. For example: WordPress changed <code>wp_specialchars</code> to <code>esc_html</code>. This will result in notices being raised in older themes, which you&#8217;ll only see if you enable <code>WP_DEBUG</code>. It&#8217;s a good idea to find-and-replace these if you&#8217;re upgrading an old theme to WP3. I don&#8217;t <em>really </em>hate WordPress for this, but it seems a bit of a pointless change, and isn&#8217;t it a bit late in the day for being pedantic about naming conventions? A whim like this just contributes to the amount of legacy in the system and the amount of code devoted to handling depreciation. There&#8217;s a 2,500 line file devoted to depreciating functions that are to be removed &#8220;later&#8221;. Making a clean break with WordPress 3 would have prevented many people from upgrading, so I understand why they do this; I just don&#8217;t like the effect it has on the code-base.</p>
<p>I could go on, but I&#8217;m hungry. If you want more, see what <a href="http://wonko.com/post/wordpresss_idea_of_sql_injection_security_addslashes" target="_blank">this guy has to say on the topic</a>.</p>
<p><a name="bitattheend"></a></p>
<p><strong>The bit at the end</strong></p>
<p>All in all, I&#8217;m disappointed that WordPress 3 wasn&#8217;t taken as an opportunity to improve upon its own legacy. It is fairly clear that popularity with amateurs, &#8216;ease of use&#8217; and backward compatibility is more important to the team than creating good, robust software that developers will appreciate. <a href="http://drupal.org/" target="_blank">Drupal</a> sets a much better example. I&#8217;m not saying I don&#8217;t have any gripes with Drupal, but they are much happier to take reduced backward compatibility on the chin when they release new versions. This means more incompatible modules, but such is the price of progress.</p>
]]></content:encoded>
			<wfw:commentRss>http://web.2point1.com/2010/08/21/wordpress-3-is-still-wordpress/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>PHP-FPM 5.3.3 under Nginx</title>
		<link>http://web.2point1.com/2010/08/17/php-fpm-5-3-3-under-nginx/</link>
		<comments>http://web.2point1.com/2010/08/17/php-fpm-5-3-3-under-nginx/#comments</comments>
		<pubDate>Tue, 17 Aug 2010 16:21:59 +0000</pubDate>
		<dc:creator>tim</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[nginx]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[php-fpm]]></category>

		<guid isPermaLink="false">http://web.2point1.com/?p=487</guid>
		<description><![CDATA[«« See previous post for getting nginx up and running. This post is about getting PHP running as a FastCGI. PHP 5.3 with FastCGI Process Manager Running PHP as a FastCGI (or even a regular CGI) means that it&#8217;s decoupled from the web server, and if you&#8217;ve historically run mod_php, then this is something you&#8217;ll [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://web.2point1.com/2010/08/17/now-powered-by-wordpress-3-nginx-and-php-fpm">«« See previous post </a>for getting nginx up and running. This post is about getting PHP running as a FastCGI.</p>
<h3><span id="more-487"></span>PHP 5.3 with FastCGI Process Manager</h3>
<p>Running PHP as a FastCGI (or even a regular CGI) means that it&#8217;s  decoupled from the web server, and if you&#8217;ve historically run mod_php,  then this is something you&#8217;ll have to get used to. For example,  restarting your web server won&#8217;t refresh your PHP settings. The CGI listens on a port much like the web server itself does, and that&#8217;s how  the web server passes requests though to PHP. There&#8217;s plenty of  information on why this is good news, <a href="http://2bits.com/articles/apache-fcgid-acceptable-performance-and-better-resource-utilization.html" target="_blank">like here</a>.</p>
<p>The nginx wiki has plenty of information and examples of <a href="http://wiki.nginx.org/PHPFcgiExample" target="_blank">running PHP as a FastCGI</a>, but I had some bad experiences using these examples. Quite  possibly this was due to my tuning it badly, but regardless, <strong>discovering <a href="http://php-fpm.org/" target="_blank">PHP-FPM</a> was a major result</strong>. Furthermore FPM is now bundled with <a href="http://www.php.net/archive/2010.php#id2010-07-22-2" target="_blank">PHP 5.3.3</a> &#8211; I thoroughly recommend, if you can upgrade to PHP 5.3.x that you do  so. If you can&#8217;t, and you still want to use PHP-FPM, it&#8217;s a lot more  effort to install and you may have to roll back your version of PHP  5.2.x &#8211; I won&#8217;t be covering that here, check the <a href="http://php-fpm.org/download/" target="_blank">various patches here</a> instead.</p>
<p>There doesn&#8217;t seem to be a huge amount of information about configuring PHP-FPM in PHP 5.3.3, so I&#8217;ll share my configs here. To start with building php-fpm from the downloaded PHP sources is as simple enabling the option. The rest of the build process is as normal, but you&#8217;ll have a php-fpm binary installed at <code>/usr/local/sbin/php-fpm</code></p>
<pre>$ ./configure --enable-fpm</pre>
<p>The  following is a single nginx server block, which defines a virtual host capable of executing PHP via FastCGI.</p>
<pre>server {
  listen       80;
  server_name  *.2point1.com 2point1.com;
  root         /home/vhosts/2point1.com/httpdocs;
  access_log   /home/vhosts/2point1.com/log/access.log main;
  error_log    /home/vhosts/2point1.com/log/error.log  warn;
  # Process PHP files with fastcgi
  location ~ \.php$ {
    if ( !-f $request_filename ) {
      return 404;
    }
   <strong> include /etc/nginx/fastcgi_params;</strong>
    fastcgi_pass   127.0.0.1:9000;
    fastcgi_index  index.php;
    fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
  }
  location / {
    index  index.php;
  }
}</pre>
<p>Notice the inclusion of <code>/etc/nginx/fastcgi_params</code>. This file may be bundled with your nginx installation already. If not, it looks like this:</p>
<pre>fastcgi_param  QUERY_STRING       $query_string;
fastcgi_param  REQUEST_METHOD     $request_method;
fastcgi_param  CONTENT_TYPE       $content_type;
fastcgi_param  CONTENT_LENGTH     $content_length;

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

fastcgi_param  GATEWAY_INTERFACE  CGI/1.1;
fastcgi_param  SERVER_SOFTWARE    nginx/$nginx_version;

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

# PHP only, required if PHP was built with --enable-force-cgi-redirect
#fastcgi_param  REDIRECT_STATUS    200;</pre>
<p>I also added the following lines, on the <a href="http://interfacelab.com/nginx-php-fpm-apc-awesome/" target="_blank">recommendation I found here</a> (in fact this is probably what went wrong with my earlier experiments with FPM under 5.2.x). I recommend adding these lines.</p>
<pre>fastcgi_connect_timeout 60;
fastcgi_send_timeout 180;
fastcgi_read_timeout 180;
fastcgi_buffer_size 128k;
fastcgi_buffers 4 256k;
fastcgi_busy_buffers_size 256k;
fastcgi_temp_file_write_size 256k;
fastcgi_intercept_errors on;</pre>
<p>That&#8217;s got nginx ready to pass PHP execution onto port 9000, so now we  have to get PHP-FPM up and running on that port. PHP-FPM has it&#8217;s own  configuration, which as of this new release has shifted from an XML format to the  familiar <em>ini</em> style. This is a great move, firstly because it looks  nicer, and secondly because it also allows us to add additional PHP ini settings.</p>
<p>My main <code>php.ini</code> and <code>php-fpm.conf</code> files are under <code>/usr/local/etc</code> which is the default location. The <code>php-fpm.conf</code> file contains global settings and settings for individual resource pools. Each pool listens on its own port, and can have its own PHP settings.</p>
<p>If you need to support multiple hosts as I do, then you&#8217;ll probably want each nginx server to pass PHP requests on to a different pool, specified by its port. To achieve this, I removed all resource pools from the main config and added a wild-card inclusion much like I did with the nginx config. My main <code>php-fpm.conf</code> file looks like this:</p>
<pre>[global]

pid = /usr/local/var/run/php-fpm.pid
error_log = /usr/local/var/log/php-fpm.log
log_level = notice
emergency_restart_threshold = 0
emergency_restart_interval = 0
process_control_timeout = 0
daemonize = yes

;  pools defined in virtual hosts
include=/home/vhosts/*/conf/php-fpm.include</pre>
<p>Then each host has its own config in <code>php-fpm.include</code> as follows.</p>
<pre>[mypool]

listen = 127.0.0.1:9000
listen.backlog = -1
listen.allowed_clients = 127.0.0.1

; Unix user/group of processes
user = nginx
group = nginx

; Choose how the process manager will control the number of child processes.
pm = dynamic
pm.max_children = 50
pm.start_servers = 10
pm.min_spare_servers = 5
pm.max_spare_servers = 10
pm.max_requests = 100

; Pass environment variables
env[HOSTNAME] = $HOSTNAME
env[PATH] = /usr/local/bin:/usr/bin:/bin
env[TMP] = /tmp
env[TMPDIR] = /tmp
env[TEMP] = /tmp

; host-specific php ini settings here
php_admin_value[open_basedir] = /home/vhosts/2point1.com/httpdocs:/tmp</pre>
<p>Any directives missing here were just left as default. Note that I set the user to nginx, although I don&#8217;t know whether this is a good idea, or not. This is possibly just a throw-back to my <code>mod_php</code> days where PHP would always run as the <code>apache</code> user.</p>
<p><strong>Process manager tuning</strong></p>
<p>There&#8217;s not much documentation on the <code>pm.*</code> directives, namely <code>max_children, start_servers, min_spare_servers, max_spare_servers, and max_requests</code>. However, they are analogous to other settings you may be familiar with. The <a href="http://httpd.apache.org/docs/2.0/mod/prefork.html" target="_blank">well documented Apache directives</a>,  <code>MaxClients, StartServers, MinSpareServers, MaxSpareServers and MaxRequestsPerChild</code> are worth a look to make sense of these options.</p>
<p>Once a process has been used it still occupies memory, even when idle, so you don&#8217;t want more of these processes running than your server can handle. I kept my spares low, and my max children under a number I was confident the server would have enough memory to cope with. This is not a particular area of expertise for me, so I suggest doing your own research.</p>
<p>To start up PHP, run the program telling it where your configs are:</p>
<pre># php-fpm -c /usr/local/etc  -y /usr/local/etc/php-fpm.conf</pre>
<p>If you need to reload any configuations, you can do a graceful reload will the kill command, as follows taking the process id from disk:</p>
<pre># cat /usr/local/var/run/php-fpm.pid | xargs kill -s USR2</pre>
<p>And that&#8217;s it. One speedy new nginx server powered by PHP 5.3.3. My next task was getting WordPress 3 running in this environment &#8211; post to follow shortly.</p>
]]></content:encoded>
			<wfw:commentRss>http://web.2point1.com/2010/08/17/php-fpm-5-3-3-under-nginx/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Now powered by WordPress 3, Nginx and PHP-FPM</title>
		<link>http://web.2point1.com/2010/08/17/now-powered-by-wordpress-3-nginx-and-php-fpm/</link>
		<comments>http://web.2point1.com/2010/08/17/now-powered-by-wordpress-3-nginx-and-php-fpm/#comments</comments>
		<pubDate>Tue, 17 Aug 2010 16:21:52 +0000</pubDate>
		<dc:creator>tim</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[fastcgi]]></category>
		<category><![CDATA[nginx]]></category>
		<category><![CDATA[performance]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[php-fpm]]></category>
		<category><![CDATA[scaling]]></category>

		<guid isPermaLink="false">http://web.2point1.com/?p=479</guid>
		<description><![CDATA[Speeding up my blog Performance issues aren&#8217;t just for high traffic sites. I&#8217;m lucky if I get 50 visitors a day to this site, but by using scaling techniques popular with the big boys, I figured I could increase page load speeds, (good for visitors and good for SEO). If I could achieve this and [...]]]></description>
			<content:encoded><![CDATA[<h3>Speeding up my blog</h3>
<p>Performance issues aren&#8217;t just for high traffic sites. I&#8217;m lucky if I get 50 visitors a day to this site, but by using  scaling techniques popular with the big boys, I figured I could increase page  load speeds, (good for visitors and <a href="http://googlewebmastercentral.blogspot.com/2010/04/using-site-speed-in-web-search-ranking.html" target="_blank">good for SEO</a>). If I could achieve this <em>and </em>use less resources, perhaps I could even save some money on my hosting bills. I currently run a 512MB VPS on Slicehost, and I&#8217;d rather not increase this right now.</p>
<p>With a few days off work, I decided to take the plunge and swap out some of the server tech powering this blog. From the bottom up, so to speak, this was as follows -</p>
<ol>
<li>Replace Apache with Nginx (<a href="#more-479">below</a>)</li>
<li>Upgrade to PHP 5.3.3 and run as a FastCGI (<a href="http://web.2point1.com/2010/08/17/php-fpm-5-3-3-under-nginx/">next post</a>)</li>
<li>Upgrade to WordPress 3</li>
<li>Deploy a CDN</li>
<li>Add a Varnish cache for extra speed</li>
</ol>
<p>I&#8217;ll go through my experience across a number of posts, starting with Nginx. I shan&#8217;t replicate any existing documentation; I&#8217;m just going to go through what I did and point you at the resources you&#8217;ll need.<br />
<span id="more-479"></span></p>
<h3>Nginx (Engine X)</h3>
<p>Apache has long been my comfort zone, as I imagine it is for most PHP developers, but I&#8217;ve been listening to people over the past couple of years saying the old work horse is bloated, and needs shooting. It has certainly been falling out of favour with high-traffic sites, while Nginx seems to be <a href="http://news.netcraft.com/archives/2010/04/15/april_2010_web_server_survey.html" target="_blank">gaining popularity</a>. Before this upgrade I&#8217;d already tried Nginx out on a few other sites, and it&#8217;s great. <a href="http://wiki.nginx.org/Main" target="_blank">Read about Nginx here</a>. Here&#8217;s an <a href="http://www.joeandmotorboat.com/2008/02/28/apache-vs-nginx-web-server-performance-deathmatch/" target="_blank">Nginx-Apache comparison</a> if you want some stats &#8211; I have none to offer you.</p>
<p><strong>Installing nginx</strong></p>
<p>I found I could install a fairly recent version on Fedora using yum, so <code># yum install nginx</code> was all I needed to do. I found it was totally unavailable in other repos, including CentOS, so you may have to <a href="http://wiki.nginx.org/NginxInstall#Source_Releases" target="_blank">build from source</a>. I won&#8217;t replicate any such tutorials here, except to say that you will most likely have to update <a href="http://monkey.org/~provos/libevent/" target="_blank">libevent</a>. You&#8217;ll need a recent version of that for the rest of this stack anyway, so may as well build that upfront.</p>
<p><strong>Virtual hosts</strong></p>
<p>As I have a couple of other small sites on this sever, I needed to set up virtual hosting. I did this with an include directive in the main <code>/etc/nginx.conf</code>, as follows:</p>
<pre>http {
  # ....
  include /home/vhosts/*/conf/nginx.include;
}
</pre>
<p>So each of my host directories has a <a href="http://wiki.nginx.org/NginxHttpCoreModule#server" target="_blank">server {&#8230;} block</a> defined in <code>nginx.include</code>. I actually removed the default server block from the main config, although that is entirely up to you. <a href="http://wiki.nginx.org/NginxHttpCoreModule#Directives" target="_blank">All nginx core directives listed here</a>.</p>
<p>Starting nginx is as simple as running <code># nginx</code>, and a graceful reload of altered configs can be done with <code># nginx -s reload</code>. If you install via yum, you may also have a service script at <code>/etc/init.d/nginx</code>. To ensure nginx is up on reboot, I just chucked a start command into <code>/etc/rc.local</code> although, I&#8217;m sure there&#8217;s a better way to do that.</p>
<h3>PHP</h3>
<p>So, nginx is running, what to do about PHP? Waving goodbye to Apache also means waving goodbye to <code>mod_php</code>.   If you&#8217;ve previously run PHP as a FastCGI, then you&#8217;re ahead of the   game on this one. If not, then you&#8217;re about to leave another comfort   zone. I&#8217;ll cover <a href="http://web.2point1.com/2010/08/17/php-fpm-5-3-3-under-nginx/">running PHP-FPM next »»</a></p>
]]></content:encoded>
			<wfw:commentRss>http://web.2point1.com/2010/08/17/now-powered-by-wordpress-3-nginx-and-php-fpm/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Annoyed by auto-tweeting, again</title>
		<link>http://web.2point1.com/2010/08/17/annoyed-by-auto-tweeting-again/</link>
		<comments>http://web.2point1.com/2010/08/17/annoyed-by-auto-tweeting-again/#comments</comments>
		<pubDate>Tue, 17 Aug 2010 13:18:18 +0000</pubDate>
		<dc:creator>tim</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[spam]]></category>
		<category><![CDATA[twitter]]></category>

		<guid isPermaLink="false">http://web.2point1.com/?p=469</guid>
		<description><![CDATA[Another Twitter app launched itself to momentary viral stardom this morning by using a practice that seems to irritate more-or-less everyone. I refer to the mandatory auto-tweet posted from your own account saying something like &#8220;I just scored X% using suchandsuch app&#8221; &#8211; you know the type. This particular app was the sneaky, (or misguided) [...]]]></description>
			<content:encoded><![CDATA[<p>Another Twitter app launched itself to momentary viral stardom this morning by using a practice that seems to irritate more-or-less everyone. I refer to the mandatory auto-tweet posted from your own account saying something like &#8220;<em>I just scored X% using suchandsuch app</em>&#8221; &#8211; you know the type. This particular app was the sneaky, (or misguided) type that gives no warning, and no way of opting out.</p>
<p>Anyhow, this isn&#8217;t the first time I&#8217;ve been annoyed by auto-tweeting, <a href="/2009/11/29/beating-noisy-twitter-apps/">I&#8217;ve written about it before</a>. It&#8217;s happened more times than I care to remember, so I won&#8217;t go into the details of today&#8217;s particular example, except to say that its author has [sort of]  <a href="http://twitter.com/jamescun/status/21394922905" target="_blank">apologised</a>. It&#8217;s <a href="http://www.nixonmcinnes.co.uk/2010/08/17/twifficiency-blink-and-youll-hate-it" target="_blank">already been blogged</a> anyway if you&#8217;re curious.</p>
<p>What I will harp on about though, is the fact that <strong>this is nothing short of spam</strong> &#8211; Twitter needs to agree, and needs to make it easier to report badly behaved apps.<span id="more-469"></span></p>
<h3>Best practice guidelines for auto-tweeting</h3>
<p>Best practice in my opinion is to at the very least provide a clear statement of  intent, that by authorizing this application it will tweet from your  account immediately. At best this should be an opt-in mechanic, or an  after-the-fact sharing mechanic. Maintaining moral integrity when your  app needs traction may be frustrating, but a good viral encourages users  to spread the message because they want to; i.e. passing the message on  provides value.</p>
<p>I checked Twitter&#8217;s growing <a href="http://dev.twitter.com/pages/api_terms" target="_blank">API terms</a> today to see if there are any guidelines around this specific issue. <em>I couldn&#8217;t find anything</em>. There are plenty of  <a href="http://support.twitter.com/articles/76915" target="_blank">guidelines around automation</a>, but nothing about moral use of the <a href="http://dev.twitter.com/doc/post/statuses/update" target="_blank">statuses/update method</a> when used to post a status update via another user&#8217;s account. I believe the use of this method should insist that if it is not invoked directly and knowingly by the owner of the account, that the owner must at least be been warned, and ideally given the opportunity to opt-out.</p>
<p>I posted <a href="http://qr.ae/Kze" target="_blank">a query about this on Quora</a> to see if anyone else could find anything in black and white about this.</p>
<h3>Defining Twitter spam</h3>
<p><a href="http://support.twitter.com/articles/18311-the-twitter-rules#spam" target="_blank">Twitter&#8217;s definition of spam</a> doesn&#8217;t include this practice either. An application auto-tweeting without consent, or warning is using other people&#8217;s accounts to distribute bulk messages without their permission, and consequently without the recipients&#8217; permission. That&#8217;s about as close to a definition of spam as I think you need to get.</p>
<p>However, despite Twitter&#8217;s maturing terms of service, they doesn&#8217;t seem to think the same. They do say that their <a href="http://support.twitter.com/articles/18311-the-twitter-rules#spam" target="_blank">definition of spam</a> &#8220;will continue to evolve as [they] respond to new tactics&#8221;, but this tactic is not in the least bit new.</p>
<p>If I were a cynic (<em>cough</em>), I may even suggest that identifying more activity as spam would not be in the company&#8217;s interest &#8230;  <a href="http://www.readwriteweb.com/archives/twitter_is_winning_its_fight_against_spammers.php" target="_blank">statistically speaking</a>.</p>
<h3>Reporting applications</h3>
<p>Twitter provide a way to <a href="http://support.twitter.com/articles/64986-how-to-report-spam-on-twitter" target="_blank">report spam</a>, (or you can do it through <a href="http://www.twitblock.org/" target="_blank">TwitBlock</a> <img src='http://web.2point1.com/wp-includes/images/smilies/icon_biggrin.gif' alt=':D' class='wp-smiley' /> ) &#8211; but this is really for individual user accounts; not all applications have a corresponding Twitter account, and the registered author may just be doing as they&#8217;re told by a client, or employer. There is no specific way to report an application for misbehaviour. You can complain by way of a <a href="http://twitter.com/help/escalate" target="_blank">support ticket</a>, but that&#8217;s not quite good enough. Facebook make reporting an application much easier. All applications have profile pages one click away from the Connect dialogue, and a report button, (albeit a discreet one) is available there. I want to see mandatory application profiles for Twitter, with clearer flagging and revoking facilities.</p>
<h3>Write access and revocation</h3>
<p>You can&#8217;t discuss this topic for long without the old issue of opt-in write access being raised. i.e. Should users be able to choose what privileges they grant an application? Personally, I think it should be made visually clearer (see Facebook), but if an app requires write access to function, I think it is reasonable that the user cannot concoct their own privilege cocktail. i.e. &#8220;This app requires write access to perform its primary function; if you don&#8217;t trust us, don&#8217;t use it&#8221;.</p>
<p>OAuth revocation is too well hidden on Twitter too. It may only be two clicks away from any part of the main UI, but most people don&#8217;t know it&#8217;s there. <em>How do I know this?</em> Firstly, by speaking to people who aren&#8217;t all developers, and secondly &#8211; of the 43,500 users who have authenticated on <a href="http://www.twitblock.org/" target="_blank">TwitBlock</a>, only about a thousand have revoked their &#8216;connection&#8217;, that&#8217;s less than 3%.</p>
<p>While both these issues are important and have room for improvement, I don&#8217;t believe they alone can solve the problem of applications being spammy. That requires a better definition of what it means to be spammy, and a better way to report those applications.</p>
]]></content:encoded>
			<wfw:commentRss>http://web.2point1.com/2010/08/17/annoyed-by-auto-tweeting-again/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>JASPA on ice</title>
		<link>http://web.2point1.com/2010/08/15/jaspa-on-ice/</link>
		<comments>http://web.2point1.com/2010/08/15/jaspa-on-ice/#comments</comments>
		<pubDate>Sun, 15 Aug 2010 12:16:44 +0000</pubDate>
		<dc:creator>tim</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[JASPA]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[php-fpm]]></category>

		<guid isPermaLink="false">http://web.2point1.com/?p=464</guid>
		<description><![CDATA[My much neglected personal project JASPA has been taken offline. All traffic to jaspa.org.uk is redirecting here for now. JASPA is/was a cross-compiler written in PHP which converts an ActionScript3-like language to native JavaScript prototypes. Essentially this is a language abstraction; an approach to JavaScript which is has its critics. I felt however that with [...]]]></description>
			<content:encoded><![CDATA[<p>My much neglected personal project <a href="/tag/jaspa">JASPA</a> has been taken offline. All traffic to <em>jaspa.org.uk</em> is redirecting here for now.</p>
<p><span id="more-464"></span>JASPA is/was a cross-compiler written in PHP which converts an ActionScript3-like language to native JavaScript prototypes. Essentially this is a language abstraction; an approach to JavaScript which is has <a href="http://ejohn.org/blog/javascript-language-abstractions/" target="_blank">its critics</a>. I felt however that with ActionScript being a derivative of ECMAScript that some such criticism was not quite applicable. It worked pretty well, and I used it some of my own work, but it has received little public interest, and I was unable to maintain it well enough for those who were interested. Thanks to all the people who did email me about the project &#8211; I may pick up the project again sometime, but I can&#8217;t make any promises.</p>
<p>My ultimate reason for physically bringing the site down was that was that it was powered by Mediawiki, which doesn&#8217;t <em>appear</em> to be compatible with PHP 5.3.x, and I wanted to upgrade so I could use the new version of PHP-FPM (post about that to follow). I could have debugged the wiki to see if 5.3.x was really the problem, but I decided instead to cut my losses. R.I.P.</p>
]]></content:encoded>
			<wfw:commentRss>http://web.2point1.com/2010/08/15/jaspa-on-ice/feed/</wfw:commentRss>
		<slash:comments>32</slash:comments>
		</item>
		<item>
		<title>Dictionary bookmarklet</title>
		<link>http://web.2point1.com/2010/08/09/dictionary-bookmarklet/</link>
		<comments>http://web.2point1.com/2010/08/09/dictionary-bookmarklet/#comments</comments>
		<pubDate>Mon, 09 Aug 2010 12:48:35 +0000</pubDate>
		<dc:creator>tim</dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[firefox]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[tools]]></category>

		<guid isPermaLink="false">http://web.2point1.com/?p=461</guid>
		<description><![CDATA[I use this really basic Firefox bookmarklet pretty much every day, so I thought I&#8217;d post it. &#8211;&#62; Dictionary.com &#60;&#8211; drag to toolbar Dictionary.com provide an &#8216;official&#8217; bookmarklet, here: http://dictionary.reference.com/tools/bookmarklets.html I&#8217;ve improved it a bit Selected text uses window.getSelection(), not document.getSelection() Trims junk out of current selection Opens a new window so you don&#8217;t lose [...]]]></description>
			<content:encoded><![CDATA[<p>I use this really basic Firefox bookmarklet pretty much every day, so I thought I&#8217;d post it.</p>
<p>&#8211;&gt; <strong><a href="javascript:void%20(function(){try{var%20b=window.getSelection(),a=b?b.toString().replace(/(^\W+|\W+$)/g,''):'';if(!a){a=prompt('Enter%20a%20word%20to%20look%20up');if(!a)return}var%20c='http://dictionary.reference.com/search?r=1&#038;q='+encodeURIComponent(a);window.open(c)}catch(d){alert('Oops:\n'+d.message)}})();">Dictionary.com</a></strong> &lt;&#8211; drag to toolbar</p>
<p>Dictionary.com provide an &#8216;official&#8217; bookmarklet, here:<br />
<a href="http://dictionary.reference.com/tools/bookmarklets.html" target="_blank">http://dictionary.reference.com/tools/bookmarklets.html</a></p>
<p>I&#8217;ve improved it a bit<span id="more-461"></span></p>
<ul>
<li>Selected text uses <code>window.getSelection()</code>,  not <code>document.getSelection()</code></li>
<li>Trims junk out of current selection</li>
<li>Opens a new window so you don&#8217;t lose the current page</li>
<li>Uses <code>encodeURIComponent()</code>, not <code>escape()</code></li>
</ul>
<p>Here&#8217;s the uncompressed source on Github</p>
<p><script src="http://gist.github.com/515450.js?file=improved%20dictionary.com%20bookmarklet"></script></p>
]]></content:encoded>
			<wfw:commentRss>http://web.2point1.com/2010/08/09/dictionary-bookmarklet/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>node-amf and node-rtmp</title>
		<link>http://web.2point1.com/2010/08/07/node-amf-and-node-rtmp/</link>
		<comments>http://web.2point1.com/2010/08/07/node-amf-and-node-rtmp/#comments</comments>
		<pubDate>Sat, 07 Aug 2010 13:56:16 +0000</pubDate>
		<dc:creator>tim</dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[AMF]]></category>
		<category><![CDATA[Flash]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[node]]></category>
		<category><![CDATA[NodeJS]]></category>
		<category><![CDATA[RTMP]]></category>

		<guid isPermaLink="false">http://web.2point1.com/?p=449</guid>
		<description><![CDATA[AMF and RTMP libraries for node.js &#8211; Flash remoting with node. I&#8217;ve been having fun playing with node.js over the past year, but have had little, or no excuse to use it in any production work, so I thought I&#8217;d set myself a challenge and build a module. That challenge was firstly to create a [...]]]></description>
			<content:encoded><![CDATA[<h3>AMF and RTMP libraries for node.js &#8211; Flash remoting with node.</h3>
<p>I&#8217;ve been having fun playing with <a href="http://nodejs.org/" target="_blank">node.js</a> over the past year, but have had little, or no excuse to use it in any production work, so I thought I&#8217;d set myself a challenge and build a module. That challenge was firstly to create a simple AMF gateway for Flash remoting, and secondarily to see if an RTMP socket server was achievable in node.</p>
<p>If you don&#8217;t know about &#8220;<a href="http://nodejs.org/" target="_blank">node&#8221;</a> &#8211; It&#8217;s a JavaScript runtime that allows you to write socket servers. I like it a lot &#8211; it brings asynchronous, event-driven programming to the server side and provides a truly global variable scope across all connections. I&#8217;ll blog about it in more detail later, perhaps.</p>
<p>At <a href="http://www.publicreative.com/" target="_blank">Public</a> we do a lot of <a href="http://www.innocentkids.co.uk/" target="_blank">Flash work</a>, and regularly implement Flash remoting using a PHP AMF gateway. I wasn&#8217;t necessarily looking to replace this stock approach with node, but node offers proper socket connections that PHP can&#8217;t, so I was imagining the possibilities of using node as a free, and more flexible alternative to Flash Media Server. Not for streaming media, but for real-time messaging, for example in multi-player games. If I&#8217;m honest though, I did this mostly for fun, an academic exercise and as an excuse to work with node.</p>
<h3><span id="more-449"></span>node-amf</h3>
<p>node-amf is on GitHub as a <em>public</em> repository: <a href="http://github.com/timwhitlock/node-amf" target="_blank">http://github.com/timwhitlock/node-amf</a></p>
<p>The first step was to write a pure JavaScript AMF implementation. i.e. a library for serializing and deserializing AMF packets. If you&#8217;re not familiar with <a href="http://en.wikipedia.org/wiki/Action_Message_Format" target="_blank">AMF (Action Message Format)</a> &#8211; it&#8217;s a binary serialization and messaging format invented by Adobe for passing data back and forth between Flash and a remote server. I am not the only person to implement this in JavaScript: mid-way through my project I noticed <a href="http://www.jamesward.com/2010/07/07/amf-js-a-pure-javascript-amf-implementation/" target="_blank">amf.js</a> appear &#8211; just a little too late for me. This library is probably much better than my own, but mine is designed specifically for node, so I shall stick with it for now.</p>
<p>With a working AMF library all that remained was to create a HTTP gateway. There are many examples of AMF gateways in other languages, including <a href="http://framework.zend.com/download/amf" target="_blank">PHP</a>. The general approach is that a single request/response  exchange carries one or more messages, each one calling a web service  on the server and returning the result. AMF also has the ability to invoke methods in the Flash client on response &#8211; an underused feature.</p>
<p>Node makes it incredibly easy to implement an <a href="http://github.com/timwhitlock/node-amf/blob/master/node-amf/http-server.js" target="_blank">HTTP server</a>, all that I had to do was decide how to expose the web services to the gateway. I decided to do this by passing a user-defined JavaScript object when initializing the server &#8211; each property of the object is a function callable by name &#8211; <a href="http://github.com/timwhitlock/node-amf/tree/master/examples/http-server/" target="_blank">example AMF gateway here</a>. This suitably sandboxes the method calls, and ensures the client cannot execute arbitrary JavaScript functions &#8211; that would be bad.</p>
<p>This part of the project is largely complete and working. It has not been used in production yet, so if you&#8217;re brave enough to use it, please let me know how it&#8217;s going!</p>
<h3>node-rtmp</h3>
<p>node-rtmp is currently under the same project as node-amf because it&#8217;s dependant upon the AMF library. This <strong>incomplete</strong>, highly <strong>unstable</strong>, and <strong>experimental </strong>work is under the <a href="http://github.com/timwhitlock/node-amf/tree/master/node-rtmp/" target="_blank">node-rtmp subdirectory</a> with <a href="http://github.com/timwhitlock/node-amf/tree/master/examples/" target="_blank">examples here</a>.</p>
<p>If you&#8217;re not familiar with <a href="http://en.wikipedia.org/wiki/Real_Time_Messaging_Protocol" target="_blank">RTMP (Real Time Messaging Protocol)</a> it provides bi-directional streaming media and messaging over persistent socket connections. It&#8217;s the messaging I&#8217;m interested in. Flash talks to Flash Media Server over RTMP sockets and can securely call methods in both directions.</p>
<p>As it turns out the <a href="http://www.adobe.com/devnet/rtmp/" target="_blank">RTMP specification</a> is very badly written. (The <a href="http://en.wikipedia.org/wiki/Action_Message_Format#References" target="_blank">AMF specs</a> were quite easy to read, although possibly much simpler). If I was a cynic, I may even suggest that Adobe has purposefully written them badly to avoid third party developers being able to adhere to the usage license which insists in adequate conformance to the spec. However, it doesn&#8217;t seem to have stopped numerous projects such as <a href="http://sourceforge.net/projects/librtmp/" target="_blank">librtmp</a> from gluing the pieces together.</p>
<p>This is the point where I realised I might be out of my depth. I am currently in the process of glueing the pieces together myself. Armed with the dodgy specification, <a href="http://www.wireshark.org/" target="_blank">Wireshark</a>, and the fragmented information dotted around the Internet, I am making some slow progress. At the time of writing I have the RTMP handshake working correctly, and have just about deciphered the command messaging packets.</p>
<p>I may give up before this is at all useful.<em> </em></p>
<h3>librtmp and node add-ons</h3>
<p>As you may have noticed, I&#8217;m talking about implementing all of this in pure JavaScript, and you may be thinking that&#8217;s nuts. You are probably right. As libraries, these don&#8217;t really need to be written in JavaScript. In addition to pure JavaScript modules, node supports <a href="http://nodejs.org/api.html#addons-310" target="_blank">add-ons</a> &#8211; compiled libraries which can be built against C and C++ system libraries. A good example of this is <a href="http://github.com/vanillahsu/node-memcache" target="_blank">node-memcache</a>.</p>
<p>C and C++ is unfortunately outside my skill set, but I imagine it may be possible to build an RTMP node add-on using <a href="http://sourceforge.net/projects/librtmp/" target="_blank">librtmp</a>. Anyone fancy a crack at that?</p>
]]></content:encoded>
			<wfw:commentRss>http://web.2point1.com/2010/08/07/node-amf-and-node-rtmp/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Diaspora &#8211; are you an early rejector?</title>
		<link>http://web.2point1.com/2010/05/13/diaspora-are-you-an-early-rejector/</link>
		<comments>http://web.2point1.com/2010/05/13/diaspora-are-you-an-early-rejector/#comments</comments>
		<pubDate>Thu, 13 May 2010 20:59:36 +0000</pubDate>
		<dc:creator>tim</dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[diaspora]]></category>
		<category><![CDATA[facebook]]></category>
		<category><![CDATA[fomo]]></category>
		<category><![CDATA[open source]]></category>
		<category><![CDATA[privacy]]></category>

		<guid isPermaLink="false">http://web.2point1.com/?p=430</guid>
		<description><![CDATA[The four NYU students pledging to build Diaspora captured my imagination today, and I&#8217;m not the only one. There is so much to discuss around this and it&#8217;s not even out of the lab yet. In a rare display of focus, I&#8217;ll devote my first post on the topic to one of the more obvious [...]]]></description>
			<content:encoded><![CDATA[<p>The four NYU students pledging to build <a href="http://www.joindiaspora.com/project.html" target="_blank">Diaspora</a> captured my imagination today, and <a href="http://www.kickstarter.com/projects/196017994/diaspora-the-personally-controlled-do-it-all-distr/backers" target="_blank">I&#8217;m not the only one</a>.</p>
<p>There is so much to discuss around this and it&#8217;s not even out of the lab yet. In a rare display of focus, I&#8217;ll devote my first post on the topic to one of the more obvious questions &#8211; <strong>Can they (or do they need to) get 400 million people to migrate away from Facebook?</strong><span id="more-430"></span></p>
<p>The idea of a decentralized, open source social network where you truly own your data appeals to many a privacy-concerned geek, but I think perhaps the announcement of Diaspora and their <a href="http://www.kickstarter.com/projects/196017994/diaspora-the-personally-controlled-do-it-all-distr" target="_blank">rapid public funding</a> is timely more than anything. After the <a href="http://www.facebook.com/f8" target="_blank">F8 conference</a> Facebook are predictably under the spotlight again &#8211; this time there&#8217;s even <em>infoporn -</em> See: <a href="http://mattmckeon.com/facebook-privacy" target="_blank">Mat McKeon</a> and the <a href="http://www.nytimes.com/interactive/2010/05/12/business/facebook-privacy.html" target="_blank">New York Times.</a></p>
<p>So we&#8217;re all &#8216;concerned&#8217; about our privacy, and maybe even what Facebook are up to in general, but as <a href="http://fernandorizo.typepad.com/blog/2010/05/facebook-keeps-calling-our-bluff.html" target="_blank">Fernando Rizo muses</a> on his blog today, are you going to quit? No, of course not. Well, not without a decent alternative, because you don&#8217;t want to miss out. (See <a href="http://www.urbandictionary.com/define.php?term=fomo" target="_blank">FOMO</a>). Well let&#8217;s assume for a moment that Diaspora becomes that alternative &#8211; what then?</p>
<h3>Tipping the other way</h3>
<p>In theory I don&#8217;t see a reason the <a href="http://en.wikipedia.org/wiki/Network_effect" target="_blank">Network Effect</a> can&#8217;t work in reverse. It takes early adopters to populate a site like Facebook in the first place &#8211; perhaps a trend in rejection could result in a tipping point in the opposite direction. If you joined Facebook because your friends did, and they went somewhere else &#8211; you&#8217;d eventually go too. Somebody has to go first of course.</p>
<p><a href="../tag/facebook/">I grumble about Facebook</a> all the time,  but I use it as much as the next guy &#8211; in fact more  than most of my  friends. I don&#8217;t want to shut my account down. Going cold turkey would be a serious commitment. I think for this to happen for me there would have to be some kind of  transitional phase.</p>
<p>If Diaspora allowed me to view and publish content to and from Facebook, that would surely defeat its primary function. You could argue that it depends what the content was, but it would still mean keeping my Facebook account active. It might however be a way to soften the blow, and at the same time entice my peers into migrating too.</p>
<p>I don&#8217;t have the solution, (and I probably don&#8217;t understand the problem), but many of us are far too attached to our digital homes for this to be a clean break. As Fernando points out we&#8217;ve seen mass migration before (away from MySpace) but I&#8217;d say it&#8217;s a bigger deal this time. I remember quitting MySpace (~2007) and I really didn&#8217;t miss it. I had a handful of photos and about 30 friends. It was also incredibly annoying. Despite my moaning, I really like Facebook, it&#8217;s a very usable site and there&#8217;s <em>vastly</em> more content than I had access to three years ago.</p>
<h3>Would an exodus be necessary?</h3>
<p>Diaspora are proposing a hosted, turn-key option for their software (<a href="http://en.support.wordpress.com/com-vs-org/" target="_blank">a la WordPress</a>) and perhaps, as is <a href="http://www.gnu.org/philosophy/selling.html" target="_blank">common with open source products</a>, providers will be permitted to package up and sell the product themselves in a healthy, competitive fashion. To move 400 million people over to Diaspora, this would surely be essential &#8211; how many Facebook users know what a <a href="http://www.gnupg.org/" target="_blank">GPG</a> key is?</p>
<p><a href="http://twitter.com/timwhitlock/status/13927932016" target="_blank">I joked earlier</a> (complete with typo) that if  Diaspora took off, perhaps Facebook could move to a hosted-Diaspora  revenue model. Perhaps this wasn&#8217;t such a joke. Facebook need <a href="http://news.yahoo.com/s/afp/20100502/tc_afp/usitinternetrightscompanyfacebook" target="_blank">your data to profit</a>, if you&#8217;re going to abscond and  not give them any more data and not look at any more ads, then a  premium service where you can interact with your friends without getting  &#8216;graphed&#8217; seems reasonable to me. The privacy concerned few could pay, while the complacent masses continue to trade their personal lives for a free ticket.</p>
<p>I&#8217;m thinking out loud and probably sound like an idiot, but I&#8217;m hungry and need to go home&#8230;. just gotta check my Facebook.</p>
]]></content:encoded>
			<wfw:commentRss>http://web.2point1.com/2010/05/13/diaspora-are-you-an-early-rejector/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>OAuth 2.0</title>
		<link>http://web.2point1.com/2010/05/06/oauth-2/</link>
		<comments>http://web.2point1.com/2010/05/06/oauth-2/#comments</comments>
		<pubDate>Thu, 06 May 2010 20:52:16 +0000</pubDate>
		<dc:creator>tim</dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[facebook]]></category>
		<category><![CDATA[OAuth]]></category>
		<category><![CDATA[security]]></category>

		<guid isPermaLink="false">http://web.2point1.com/?p=421</guid>
		<description><![CDATA[Off the back of all the recent Facebook changes I just read the OAuth 2.0 spec &#8211; it&#8217;s currently in a draft state, and according to this page, Facebook is currently the only implementation in the wild. This new spec attempts to pull together various authentication journeys rather than just the typical web app model. [...]]]></description>
			<content:encoded><![CDATA[<p>Off the back of all the recent Facebook changes I just read the <a href="http://tools.ietf.org/html/draft-ietf-oauth-v2" target="_blank">OAuth 2.0 spec</a> &#8211; it&#8217;s currently in a draft state, and according to <a href="http://wiki.oauth.net/OAuth-2" target="_blank">this page</a>, Facebook is currently the only implementation in the wild. This new spec attempts to pull together various authentication journeys rather than just the typical web app model. This is a great news &#8211; It seems to accommodate many different situations across differing devices with different capabilities, while maintaining a good level of consistency.</p>
<p>You didn&#8217;t expect me to have only nice things to say, did you? There are a couple of things I have to question.<span id="more-421"></span></p>
<h3>It&#8217;s only a draft</h3>
<p>Despite this spec being a draft, Facebook (who are represented in the <a href="https://www.ietf.org/mailman/listinfo/oauth" target="_blank">working group</a>) have gone ahead and implemented it anyway. Although this is a step up from the non-standard methods they&#8217;ve employed to date, it does make me wonder. Will the spec be finalised according to their implementation? Will they change their implementation if the spec changes? Or will they end up going in separate directions? (think ECMAScript 4/ActionScript). As with my gripes about the <a href="http://web.2point1.com/2010/04/25/f8-and-the-open-graph/" target="_self">Open Graph</a>, how &#8220;open&#8221; are standards when we have self-interested corporations in the driving seat.</p>
<h3>Looser security for JavaScript clients</h3>
<p>The so-called <a href="http://tools.ietf.org/html/draft-ietf-oauth-v2-01#section-3.5.1" target="_blank">&#8220;user_agent&#8221; journey</a> serves the needs of front-end applications that don&#8217;t have access to a web server. (i.e. JavaScript only apps). This support comes at a cost to security because request signing is not required. (More to the point, signing would be redundant). The risk is a limited one &#8211; the &#8220;bearer tokens&#8221; must only be sent over SSL, so the worst you can do is take control of an app under the authentication of your own account. Still, I imagine it would be possible to post content that the app did not intend. (use your imagination!) My main gripe here is in justifying the trade off. The loosening of security is in favour of making apps easier to implement for more people &#8211; i.e. a Facebook business interest. I don&#8217;t think that&#8217;s a good enough reason to weaken the specification.</p>
]]></content:encoded>
			<wfw:commentRss>http://web.2point1.com/2010/05/06/oauth-2/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>
