Easily host your own web sites | part 1: hardware

Contents


Web serversThere is no shortage of cheap web hosting companies, offering packages from pennies per month. If you’re looking for more control and flexibility and you’re not planning to host a mission-critical eCommerce website though, self-hosting is quite rewarding and not as difficult as it sounds.

This is the first in a series of posts where I outline some options for becoming a small-time web host. In this article, I discuss the hardware you’re going to need.


You’re best off coming to terms with the idea that you’ll be leaving your new web server switched on 24 hours a day. Whether we admit it or not, ultimately we’re hoping that whatever websites we host will become popular and reach a worldwide audience. That means your server must theoretically be available and reachable round the clock. In my view, as a bare minimum you should have:

  • A computer. Doesn’t need to be fancy or modern. Preferably less than five years old, but it won’t be a deal breaker, if not. We’ll call this box “the server”. It won’t need a monitor, keyboard and mouse attached full-time. You’ll only need to borrow these for the initial setup. We’ll be connecting to the server remotely as soon as possible and from that point onwards, we can run this server “headless” (i.e. with nothing attached other than the UPS).
  • An uninterruptible power supply (UPS). Your UPS protects your server from the vagaries of your household power supply. It doesn’t do a server much good to lose power suddenly. A UPS is a battery backup which can enable your server to shut down gracefully in the event of a power cut. The better UPSes also clean the incoming power, protecting the server from “bucks” and “boosts”.
  • A router capable of port forwarding. Shouldn’t be too much of a problem – most routers can do this. I’m assuming here that you’re on some kind of “always on” internet connection like broadband or cable.

The server

Unless you’re hosting a lot of websites, getting a lot of traffic, or building very complex websites, this machine won’t need much power. And it doesn’t need to break the bank. You could consider using a Raspberry Pi for example (although that will be harder to set up than an ordinary PC). I’ve used second-hand computers, old laptops and all sorts to host web sites. Currently I have an old IBM xSeries tower server in my loft, but you probably don’t need that kind of power or resilience when you start out with web hosting. You could even just use a virtual machine on your home computer, if you’re happy to leave that switched on all the time. I’m going to assume that you’re using a dedicated machine though. I’m also going to assume that we’ll be using typical PC hardware; you can self-host with Mac hardware quite easily, but that’s not where the majority of my experience lies.

The UPS

We’re going to be running Linux on this server, so the primary requirement is that your UPS is supported by Linux. APC UPSes used to be supported under Linux by the apcupsd program (a so-called ‘daemon’, which runs continuously on the server). In recent years however, APC short-sightedly changed their UPS range so they could no longer communicate with apcupsd (to the considerable anguish of the Linux community). Your best bet is either to source an old APC UPS – you can still easily find the replacement batteries – or buy any Eaton UPS. Eaton UPSes are supported by the Network UPS Tools daemon and I know that Eaton is commercially committed to the Linux platform for the foreseeable future.

The router

As long as your router supports port forwarding, you’ll be okay. A lot of routers are capable of being upgraded with aftermarket “firmwares” to provide previously unavailable capabilities. This is a good way of obtaining a near enterprise-class router on the cheap. Probably the most famous of these firmwares is DD-WRT. Have a look on that website for a list of supported routers if you want to go down this route (ahem).


So that’s it for this post. Short and sweet. While you’re off sourcing your hardware, I’ll be hard at work thinking about part 2, in which we’ll start to set up your new server’s operating system and supporting applications. See you soon!

Servers image copyright © Widjaya Ivan, licensed under Creative Commons. Used with permission.

Rackspace API for CodeIgniter

Logo_lockup_version-2 SPOTRackspace is a great email hosting company, providing, amongst other things, a handy API for creating bespoke email solutions. The exercise of integrating that API into your application is of course left to the end user. I’ve spent some time working on a Rackspace API library for the PHP programming framework, CodeIgniter. This is not functionally complete – I have only implemented the interfaces that I needed – but it should provide a useful springboard for your own projects.

Configuration

In /system/application/config/RackspaceAPI.php:

<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');

$config['user_key']   = 'your user key';
$config['secret_key']     = 'your secret key';
$config['user_agent']     = 'name of your app';
$config['api_version']    = 'v0'; // amend if necessary
$config['rackspace_host'] = 'api.emailsrvr.com'; // amend if necessary

/* End of file RackspaceAPI.php */
/* Location: ./system/application/config/RackspaceAPI.php */

Library

<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
/**
 * Uses curl and pecl_http
 */
class Rackspace_API {
    
  /**
   * Store recent http_message
   * @var object
   */
  protected $_http_message;
  
  /**
    * CI object
    * @var object
    */
  protected $_ci;

  /**
   * Rackspace config items
   */
  protected $_user_key;
  protected $_secret_key;
  protected $_user_agent;
  protected $_api_version;
  protected $_rackspace_host;
  
  function __construct() {
    $this->_ci =& get_instance();
    $this->_ci->config->load('RackspaceAPI', TRUE);
    $this->_user_key = $this->_ci->config->item('user_key', 'RackspaceAPI');
    $this->_secret_key = $this->_ci->config->item('secret_key', 'RackspaceAPI');
    $this->_user_agent = $this->_ci->config->item('user_agent', 'RackspaceAPI');
    $this->_api_version = $this->_ci->config->item('api_version', 'RackspaceAPI');
    $this->_rackspace_host = $this->_ci->config->item('rackspace_host', 'RackspaceAPI');
  }


  /**
   * Get info about a domain
   * @param string $domain
   * @return stdClass Object ( 'error'  => bool,
   *                           'result' => string (error message) | stdClass Object
   */
  public function getDomainInfo($domain) {
    return $this->genericGet('/customers/me/domains/'.$domain);
  }

  
  /**
   * Get all domain names
   * @return stdClass Object ( 'error'  => bool,
   *                           'result' => string (error message) | array (domains)
   */
  public function getDomains() {
    $obj = $this->genericGet('/customers/me/domains');
    if(!$obj->error){
      // Reformat into an array of domains
      foreach($obj->result->domains as $domain) {
        $domains[]=$domain->name;
      }
      $obj->result = $domains;
    }
    return $obj;
  }


  /**
   * Get info about a mailbox ([email protected]$id)
   * @param string $domain
   * @param string $id
   * @return stdClass Object ( 'error'  => bool,
   *                           'result' => string (error message) | stdClass Object
   */
  public function getMailboxInfo($domain, $id) {
    return $this->genericGet('/customers/me/domains/'.$domain.'/rs/mailboxes/'.$id);
  }
   
 
  /**
   * Used by Get functions above - generalised use case
   * @param string $url - see the API; constructed by the calling function
   * @return stdClass Object ( 'error'  => bool,
   *                           'result' => string (error message) | stdClass Object
   */
  private function genericGet($url) {
    $this->get(
        $url,
        'application/json');
    if($this->_http_message->getResponseCode() == 200) {
      // Call worked.  JSON is missing enclosing brackets, apparently needed by json_decode
      $json = '['.$this->_http_message->getBody().']';
      if(is_string($json)) {
        $obj = json_decode($json);
        $result->error = false;
        $result->result = $obj[0];
      } else {
        // JSON failure
        $result->error = true;
        $result->result = 'Failed to parse JSON';
      }
    } else {
      // API call failed
      $result->error = true;
      $result->result = $this->_http_message->getHeader("x-error-message");
    }
    return $result;
  }
  

  /**
   * Create a mailbox ([email protected]$id)
   * @param string $domain
   * @param string $id
   * @param string $first: First name
   * @param string $last: Last name
   * @param string $name: Display as
   * @param string $office: Name of office/profit centre
   * @param string $locno: Office/profit centre number
   * @param string $password
   * @param string $fwd: comma-separated forwarding address(es) - max 4 off domain
   * @param string $save: save forwarded email - 'true' or 'false'
   * saveForwardedEmail
   * @return stdClass Object ( 'error'  => bool,
   *                           'result' => string (error message) | stdClass Object
   */
  public function addMailbox($domain, $id, $first, $last, $name, $office,
          $locno, $password, $fwd, $save='true') {
    $fields = array(
        'password' => $password, 
        'emailForwardingAddresses' => $fwd,
        'firstName' => $first,
        'lastName' => $last,
        'displayName' => $name,
        'saveForwardedEmail' => $save,
        'organization' => $office,
        'organizationUnit' => $locno);
    return $this->genericPost( '/customers/me/domains/'.$domain.'/rs/mailboxes/'.$id, $fields);
  }


  /**
   * Used by Post functions above - generalised use case
   * Note: Rackspace API suggests use POST to add, PUT to edit
   * @param string $url - see the API; constructed by the calling function
   * @param array $fields - data to be POSTed
   * @return stdClass Object ( 'error'  => bool,
   *                           'result' => string (error message) | stdClass Object
   */
  private function genericPost($url, $fields) {
    $this->post(
        $url,
        $fields,
        'application/json');
    if($this->_http_message->getResponseCode() == 200) {
      $result->error = false;
      $result->result = $this->_http_message->getBody();
    } else {
      // API call failed
      $result->error = true;
      $result->result = $this->_http_message->getHeader("x-error-message");
    }
    return $result;
  }


  /**
   * Edit user's forwarding
   * @param string $domain
   * @param string $id
   * @param string $fwd: comma-separated forwarding address(es) - max 4 off domain
   * @return stdClass Object ( 'error'  => bool,
   *                           'result' => string (error message) | stdClass Object
   */
  public function changeForwarding($domain, $id, $fwd) {
    $fields = array(
        'emailForwardingAddresses' => $fwd
        );
    return $this->genericPut( '/customers/me/domains/'.$domain.'/rs/mailboxes/'.$id, $fields);
  }
  
    
  /**
   * Edit user's location
   * @param string $domain
   * @param string $id
   * @param string $office: Name of office/profit centre
   * @param string $locno: Office/profit centre number
   * @return stdClass Object ( 'error'  => bool,
   *                           'result' => string (error message) | stdClass Object
   */
  public function changeLocation($domain, $id, $office, $locno) {
    $fields = array(
        'organization' => $office,
        'organizationUnit' => $locno);
    return $this->genericPut( '/customers/me/domains/'.$domain.'/rs/mailboxes/'.$id, $fields);
  }
  
    
  /**
   * Edit user's name
   * @param string $domain
   * @param string $id
   * @param string $first: First name
   * @param string $last: Last name
   * @param string $name: Display as
   * @return stdClass Object ( 'error'  => bool,
   *                           'result' => string (error message) | stdClass Object
   */
  public function changeName($domain, $id, $first, $last, $name) {
    $fields = array(
        'firstName' => $first,
        'lastName' => $last,
        'displayName' => $name);
    return $this->genericPut( '/customers/me/domains/'.$domain.'/rs/mailboxes/'.$id, $fields);
  }
  
    
  /**
   * Edit user's password
   * @param string $domain
   * @param string $id
   * @param string $password
   * @return stdClass Object ( 'error'  => bool,
   *                           'result' => string (error message) | stdClass Object
   */
  public function changePassword($domain, $id, $password) {
    $fields = array(
        'password' => $password);
    return $this->genericPut( '/customers/me/domains/'.$domain.'/rs/mailboxes/'.$id, $fields);
  }
  
    
  /**
   * Used by Put functions above - generalised use case
   * Note: Rackspace API suggests use PUT to edit, POST to add
   * @param string $url - see the API; constructed by the calling function
   * @param array $fields - data to be PUT
   * @return stdClass Object ( 'error'  => bool,
   *                           'result' => string (error message) | stdClass Object
   */
  private function genericPut($url, $fields) {
    $this->put(
        $url,
        $fields);
    if($this->_http_message->getResponseCode() == 200) {
      $result->error = false;
      $result->result = $this->_http_message->getBody();
    } else {
      // API call failed
      $result->error = true;
      $result->result = $this->_http_message->getHeader("x-error-message");
    }
    return $result;
  }


  /**
   * Delete a mailbox
   * @param string $domain
   * @param string $id
   * @return stdClass Object ( 'error'  => bool,
   *                           'result' => string (error message) | stdClass Object
   */
  public function deleteMailbox($domain, $id) {
    return $this->genericDelete("/customers/me/domains/$domain/rs/mailboxes/$id");
  }
  
  
  /**
   * Used by Get functions above - generalised use case
   * @param string $url - see the API; constructed by the calling function
   * @return stdClass Object ( 'error'  => bool,
   *                           ['result' => string (error message)]
   */
  private function genericDelete($url) {
    $this->delete($url);
    if($this->_http_message->getResponseCode() == 200) {
      // Call worked.
      $result->error = false;
    } else {
      if($this->_http_message->getResponseCode() == 500) {
        // Internal server error
        $result->error = true;
        $result->result = 'An internal server error occurred deleting  object.  Url: '.$url;
      } else {
        // API call failed
        $result->error = true;
        $result->result = $this->_http_message->getHeader("x-error-message");
        
      }
    }
    return $result;
  }
  

  
  // The remainder of this file is mostly lifted from Rackspace's examples: http://api-wiki.apps.rackspace.com/api-wiki/index.php/PHP_Examples_(Rest_API)
  private function get($url_string, $format) {
      $headers = array("Accept: $format");
      $curl_session = self::construct_session($url_string, $headers);
      $this->_http_message = self::send_request($curl_session);
  }

  private function post($url_string, $fields, $format) {
      $headers = array("Accept: $format");
      $curl_session = self::construct_session($url_string, $headers);
      curl_setopt($curl_session, CURLOPT_POST, true);
      curl_setopt($curl_session, CURLOPT_POSTFIELDS, $fields);
      $this->_http_message = self::send_request($curl_session);
  }

  private function put($url_string, $fields) {
      $curl_session = self::construct_session($url_string, array());
      curl_setopt($curl_session, CURLOPT_CUSTOMREQUEST, 'PUT');
      curl_setopt($curl_session, CURLOPT_POSTFIELDS, $fields);
      $this->_http_message = self::send_request($curl_session);
  }
  
  private function delete($url_string) {
      $curl_session = self::construct_session($url_string, array());
      curl_setopt($curl_session, CURLOPT_CUSTOMREQUEST, 'DELETE');
      $this->_http_message = self::send_request($curl_session);
  }

  private function send_request($curl_session) {
      $response = curl_exec($curl_session);
      curl_close($curl_session);
      /* Reponse string may contain two HTTP sessions, if there was an initial
         "HTTP/1.1 100 Continue" response.  So strip that first response out.  Eg:
                  HTTP/1.1 100 Continue
                  Via: 1.1 [proxy]

                  HTTP/1.1 400 Bad Request
                  Via: 1.1 [proxy]
                  Connection: Keep-Alive
                  Proxy-Connection: Keep-Alive      
                  ...     
       * 
       */
      $response = preg_replace('|HTTP/1.1 100.*HTTP/1.1|isU', 'HTTP/1.1', $response);
      return new HttpMessage($response);
  }

  private function construct_session($url_string, $existing_headers) {
      $headers = array_merge(
              self::authorization_headers(), $existing_headers);
      $url = self::construct_uri($url_string);
      $curl_session = curl_init($url);
      curl_setopt($curl_session, CURLOPT_HEADER, true);
      curl_setopt($curl_session, CURLOPT_HTTPHEADER, $headers);
      curl_setopt($curl_session, CURLOPT_RETURNTRANSFER, true);
      return $curl_session;
  }

  private function authorization_headers() {
      $time_stamp = date('YmdHis');
      $data_to_sign = $this->_user_key . $this->_user_agent .
          $time_stamp. $this->_secret_key;
      $signature = base64_encode(sha1($data_to_sign, true));
      $headers = array();
      $headers[] = "User-Agent: " . $this->_user_agent;
      $headers[] = 'X-Api-Signature: ' .
          $this->_user_key . ":$time_stamp:$signature";
      return $headers;
  }

  private function construct_uri($url_string) {
      $url = 'http://' .  $this->_rackspace_host . '/' . $this->_api_version . $url_string;
      return $url;
  }
}

?>

Example

Example usage:

function testRackspace() {
    $this->load->library('Rackspace_API');
    $client = new Rackspace_API();
    $obj = $client->getMailboxInfo('somedomain.com', 'test.user');
    if($obj->error) {
      echo 'Error: '.$obj->result;
    } else {
      var_dump($obj);
    }
  }

Image copyright © Rackspace Ltd. All rights acknowledged.

Connecting to Windows/MSSQL 2008 from Linux/CodeIgniter/PHP

Update: I’ve written a new article, covering CodeIgniter 3 and Ubuntu 14/16. Read it here.

Microsoft SQL Connecting to Microsoft SQL Express 2008 from Linux/PHP is a lot trickier than I expected. These notes are really for my own benefit so I can reproduce the setup, but maybe they’ll help you too. One of the problems is that many existing PHP drivers for MS SQL have difficulty talking to SQL 2008. Here’s a workaround using FreeTDS and ODBC.

My web application is built using CodeIgniter, the PHP application framework. It resides on an Ubuntu Server box, running Apache. Prerequisites on that Ubuntu Server (which I installed using Aptitude, but your favourite package manager will do):

  • unixODBC
  • FreeTDS
  • FreeTDS development package/(header files and libraries)

To my freetds.conf file (in /etc/freetds on my server) I added a section that looks something like this:

[my-server]
host = my.server.local
port = 1433
tds version = 9.0

Note: TDS version 9.0 should work with SQL 2008.

In /etc/odbcinst.ini, add the following ODBC driver (32-bit):

[TDS]
Driver = /usr/lib/odbc/libtdsodbc.so
Description = FreeTDS driver
Setup = /usr/lib/odbc/libtdsS.so

or 64-bit:

[TDS]
Driver = /usr/lib64/libtdsodbc.so
Description = FreeTDS driver
Setup = /usr/lib64/libtdsS.so

(You may need to check the precise location of the driver and setup files.)

And to /etc/odbc.ini, I inserted a DSN similar to the following:

[my-server]
Driver = TDS
Description = My Server
ServerName = my-server
Database = my-db

Generally within CodeIgniter, I am connecting to MySQL databases and that’s how my default connection is configured. I therefore added a second configuration to my database.php configuration file, like this:

$db['my_server']['hostname'] = "dsn=my-server;uid=myusername;pwd=mypassword";
$db['my_server']['username'] = '';
$db['my_server']['password'] = '';
$db['my_server']['database'] = '';
$db['my_server']['dbdriver'] = 'odbc';
$db['my_server']['dbprefix'] = '';
$db['my_server']['pconnect'] = TRUE;
$db['my_server']['db_debug'] = TRUE;
$db['my_server']['cache_on'] = FALSE;
$db['my_server']['cachedir'] = '';
$db['my_server']['char_set'] = 'utf8';
$db['my_server']['dbcollat'] = 'utf8_general_ci';

Now the ODBC driver within CodeIgniter can produce queries that MS SQL doesn’t like. We can fix this with a hack. You really REALLY shouldn’t do it this way (!) but to get things working and as described >here<, I edited the CodeIgniter core file system/database/drivers/odbc_driver.php. The function _from_tables() has a line reading:

return '('.implode(', ', $tables).')';

I changed it to this:

return implode(', ', $tables);

(In other words, we’re removing the spurious parentheses.)

I created a database method m_my_server.php like this:

/**
 * NOTE: We're using a feature-incomplete driver here.  Don't attempt to use
 * CodeIgniter's ActiveRecord Class or num_rows().  Use bare queries instead.
 */
class M_my_server extends Model {

  var $my_server;

  function M_my_server() {
      parent::Model();
      $this->my_server = $this->load->database('my_server', TRUE);
  }

  function get() {
    $query = $this->my_server->query('SELECT TOP(100) * FROM dbo.tblUserSummary');
    $result = $query->result_array();  // note ->num_rows() doesn't work with this driver
    if(count($result) > 0) {
      return $result;
    } else {
      return false;
    }

  }
}

/* End of file m_my_server.php */
/* Location: ./application/models/m_my_server.php */

At the SQL Server end, I set up a new standard SQL user (myusername/mypassword) rather than attempting to get Windows authentication to work (I bet it wouldn’t).

My SQL instance wasn’t listening to TCP/IP connections by default. I fired up SQL Server Configuration Manager and browsed to SQL Server Network Configuration –> Protocols for [my db instance]. Then you have to right-click TCP/IP and click Enable.

With all that in place, the following controller produces successful results:

  function SQLtest() {
    $this->load->model('m_my_server');
    $result = $this->m_my_server->get();
    if($result) {
      print_r($result);
    } else {
      echo 'nada';
    }
    exit;
  }

It’s not ideal; for one thing, bare SQL queries involve learning Microsoft’s particular dialect of SQL (whereas I’m used to MySQL). The tables I’m querying are generated by Microsoft Forefront TMG though, so I’m basically stuck with MSSQL. At least now I can query those tables from my favourite PHP application framework.

Image copyright © Microsoft. Used with permission from Microsoft.

Job Done

Steve Jobs by acaben: http://www.flickr.com/photos/acaben/541420967/sizes/l/in/photostream/Business legend Steve Jobs died late last night. I heard about it through that most modern of news outlets: Facebook. I read the story on my company-supplied iPhone (which, by the way, I didn’t want; I’d rather use the Android that I keep in my drawer – long story).

The death of Steve Jobs follows the release of the much-anticipated iPhone 4S, the successor to the iPhone 4. Perhaps that ‘S’ should stand for ‘swan song’?

This morning, I mentioned Jobs’ death to a friend, who said, “Who’s Steve Jobs?”

Who’s Steve Jobs? I guess if you’re indifferent to technology and design, you could be forgiven for not knowing his name. But whether you’ve heard of him or not, his influence has almost certainly had an impact on you. The number of modern innovations associated to his name is impressive:

  • First successful personal computer with a graphical user interface (the Macintosh)
  • First WWW (World Wide Web) server
  • Pioneering in rich content email
  • Through Pixar, the first entirely CGI film, Toy Story
  • iTunes: simple access to large online catalogue of music, incorporating digital rights management
  • iPod: user-friendly range of media players
  • iPhone: user-friendly smart phone. When asked to recommend a phone to colleagues, I suggest Android for the technophiles and iPhones for the technophobes. The success of this approach tells me everything!
  • iPad: a device that “experts” claimed was superfluous but which has shipped in phenomenal numbers, battering all manufacturers’ competition in the process
  • Obsessively well-designed low voltage power supplies (built in cable management, magnetic quick-release plugs)
  • Multi-touch mouse

Given the number of patents that bear his name, I have inevitably missed some…

I am not an Apple fanboy. In fact one of my favourite sports is baiting Apple fanboys. But I simply can’t help admiring this charismatic man who for so long helmed one of the most successful companies of all time simultaneously bringing design genius and technical excellence to the masses. Steve Jobs, one time living legend, your legacy will live on.

Meanwhile, someone somewhere just patented the iHarp.

Steve Jobs image copyright © Ben Stanfield, licensed under Creative Commons. Used with permission.

Don’t all faiths lead to God? Why is yours so special?

Assuming we’ve satisfied ourselves on the question of the existence of God and accept that He is real, the next logical question is which God and what is He like? In fact some would say, “Don’t all faiths lead to God? Why is yours so special?” And this is the issue I will attempt to address in this podcast.

Note to broadcasters: please do contact us to obtain higher quality audio and a licence to broadcast any of these podcasts.

podcast iconHow can a good God allow the innocent to suffer?

The Message: Translation, Paraphrase, Truth or Heresy?

bible

Cards on the table. Growing up as a child, I read The Living Bible, a paraphrase of the Bible that was easy to read and understand.  This was my main Bible from the ages of 4 to about 15.  I gradually transitioned to the NIV, requesting a hefty leather-bound, commentary-laden edition for my 18th birthday.

19 years and many Bible studies later, slightly the worse for wear, this remains my main (printed) Bible.  The advent of the internet and the easy accessibility of multiple versions has somewhat relegated the printed word, but my old Bible still brings with it a sense of comfort, peace and tradition – in a good way.

Of course there now exist many different versions of the Bible, all rendered with different objectives and varied levels of scholarship.   If your faith rests on the word of God (faith comes by hearing and hearing by the word of God, says Paul in Romans 10:17) it is important to know where that word may be found.

Many Christians today refer to their Bibles as “the word of God” and here we come to the heart of our discussion: In a recent sermon, I quoted some passages from The Message.  My reasoning was that I was reading a familiar passage and it is sometimes helpful to hear that passage in unfamiliar language, to ensure we don’t “switch off”.

I had not anticipated that one of my friends and someone whose spiritual integrity I trust, would question my use of The Message and further, question whether The Message even deserved the right to be called “the Bible”.  The fundamental objection is that “The Message is a paraphrase”.

Broadly we divide Bible versions into two categories: translation and paraphrase.  Doing so, we may be forgiven for thinking that there is a clear distinction between the two approaches, or that one is “superior” to another.  But I do not think that the differences are as black and white as they might appear.

As I understand it, the objective of a translator is to take a text and render it in as nearly accurate a form as possible from the source language to the destination language.  With paraphrasing, the author may start with the source language or with a pre-existing translation and then seeks to render it into a modern idiom – that is, using expressions that are particularly meaningful in a certain time and place.  (Note, the foreword to The Message states that Peterson wrote “straight from the original text”.)

It is hopefully clear that paraphrasing intrinsically involves interpretation.  The author of the paraphrase has to attempt to understand the gist of the source and predict how the source could best be understood in modern (colloquial) language.  In this case, if the author’s understanding is faulty, the paraphrase will be equally faulty.  The author considers that risk to be worth taking: If the author’s understanding is accurate, the target audience should be able to understand the paraphrase with no further assistance.  The weakness of course is that, as language develops, the paraphrase becomes outdated quickly.  Furthermore, a paraphrase into American English, say, may not result in a completely intelligible read for an Australian or British English speaker.

What may not be obvious at first glance is that translation also involves an element of interpretation, especially when the source text is an ancient language and no native speakers are alive to verify the accuracy of the translation.  In all likelihood, the source text, regardless of its age, will contain idioms and colloquialisms that would be difficult to understand without background knowledge.  A literal translation could in fact do damage to the text.  For example, a literal translation into other languages of the expression “it’s raining cats and dogs” would be unlikely to leave the reader with the impression that it’s raining heavily.  More likely, they would wonder what strange phenomenon has occurred to cause domestic pets to fall from the sky.

One further problem of translation arises: the rendering will typically require interpretation and understanding on the part of the reader.  Since the objective has not been to create a colloquial version of the text, the reader is left to apply her own understanding to the work.  With translations (as opposed to paraphrases) of ancient texts, the risk of misunderstanding the text must consequently be greater.

Where does this leave us?

Regardless of the method of rendering, it would be a mistake, I think, to describe any English version of the Bible as “God’s word”.  At best, it is a translation of God’s word.  Fortunately we have the great benefit of the Holy Spirit, who communicates with us through and in addition to our English versions of God’s word, helping us to understand the text rightly.  Is it acceptable though to refer to paraphrases such as The Message as “Bibles”?  Given the inherent difficulties of translations and paraphrases, I would not personally withhold the title “Bible” from either.  By analogy, hammers and spanners are both “tools”.  The Message and the KJV are both “Bibles”.  Which is better, a hammer or a spanner?  Neither: they are different and have different strengths and weaknesses.  Which is better, The Message or the KJV? Neither: they are different and have different strengths and weaknesses.

All translations and paraphrases share a common divine heritage blended with a human (therefore flawed) understanding.  Let us not elevate any particular version to the state of deification. Rather let us thank God for the gift of His Word and the gifts he has given his servants in translating and paraphrasing for our benefit. And further let us thank him for his Holy Spirit who will guide us into all truth (John 16:13).

Practical note: due to the strengths and weaknesses of each version, when attempting to understand a passage, it is prudent to consult a range of Bible versions and to ask the Holy Spirit to guide us in our understanding.  Also, it is helpful to be mindful of the credentials of the authors of the versions.  In the case of The Message, as with many other versions, those credentials are impressive (many scholars contributed to the final text).  This is also the reason why I would dismiss a translation such as the Jehovah’s Witness’ version of the Bible, the New World Translation – the translators’ credentials are reputedly either poor or hidden.

Bible image copyright © David Campbell, licensed under Creative Commons. Used with permission.

How to Remember the Ten Commandments

Do you struggle to remember the Ten Commandments? Would you find it tricky to remember them in order? As part of a teaching series on the Ten Commandments, I prepared some relatively easy mnemonics. You may find they help! Click on the images to see larger versions.

1. You shall have no other Gods before me.
Commandment 01
Imagine the number 1 – One God.
2. You shall not make … an idol.
Commandment 02
Remember two major “Idol” shows: Pop Idol, in the UK and American Idol in the states.
 
3. Don’t take the Lord’s name in vain.
commandment_03
Imagine the three wise monkeys, all determined not to blaspheme.
4. Remember the Sabbath day and keep it holy.
commandment_04
Visualise a four poster bed, with the words “rest” written in it. Note also there are four letters in each of the words, Holy Abba Rest.
 
5. Honour your mother and father.
commandment_05
Remember five gold rings (from The Twelve Days of Christmas) – rings being a symbol of marriage and thus parenthood. Also there are five letters in each of the words, Value Mater & Pater. (Yes I know! If it’s silly, you’re more likely to remember it!)
6. Do not murder.
commandment_06
Think of a grenade, roughly in the shape of a number 6.
 
7. Do not commit adultery.
commandment_07
007 is one of the most prolific adulterers in fiction!
8. Do not steal.
commandment_08
A bit of a stretch, I admit – imagine the 8 as part of a burglar’s mask.
 
9. Do not bear false witness.
commandment_09
Imagine someone lying down in a tennis court, holding a number 9 instead of a racquet. No lying in court! Get it? (Groan.)
10. Do not covet.
commandment_10
Hard to explain, this one. Start with the letters “NO NV” (no envy). Take the last upright part of the first N and add put it next to the O to get 10. Then take the slant and last upright of the second N to get V and place it next to the V, for VV. In Roman numerals, V plus V is 10.

Why did God bless Jacob, the deceiver?

5369725815_9db3016c6c_b_d[1]

In the story of Jacob and Esau, Jacob, the younger twin, uses fraud and cunning to take Esau’s birthright from him. The significance of the birthright in Old Testament times cannot be overemphasised. The end result was Jacob becoming the ancestor of the Israelite people, blessed by God and Esau becoming the ancestor of some of their mortal enemies, rejected by God. On the face of it, this preferential treatment might seem unjust, if it derives from Jacob’s use of subterfuge.

But perhaps therein lies the mistake, assuming that the blessing flows from the deceitful act, rather than from a prior or independent choice of God’s. If we look back in the story, even before the birth, God had said to the boys’ mother, Rebekah:

23 …Two nations are in your womb,
and two peoples from within you will be separated;
one people will be stronger than the other,
and the older will serve the younger.

Genesis 25:23 (New International Version – UK)

And why did God choose Jacob over Esau? We may never know the full reasons, but here are a few thoughts:

  • God’s decision to bless Jacob is made prior to the children’s birth and prior to their ability to commit a sinful act. In this way, God provides an early demonstration of the principle that his favour is not based on our works.
  • God foreknew the events that would unfold. Remember that prior to Jacob deceiving his father, it is said of Esau that he “despised his birthright” (Genesis 25:34). He had sold it to his brother for some stew (probably not realising that Jacob was in earnest about taking the birthright).
  • It is possibly implied that Esau would not have honoured his bargain pertaining to the transfer of the birthright, hence Jacob’s need to take it by deception.

Whatever the real reason behind God’s choice, there are a few scriptures that cast light on his mode of operation. Firstly, the divine right of God to dispense special grace as He sees fit:

19 … I will have mercy on whom I will have mercy, and I will have compassion on whom I will have compassion.

Exodus 33:19 (New International Version – UK)

Secondly, the attitude we are expected to maintain with respect to God’s grace:

21 … The LORD gave and the LORD has taken away; may the name of the LORD be praised.

Job 1:21 (New International Version – UK)

Amd thirdly, lest we be in any doubt, our position in respect of deserving God’s favour:

10 … There is no-one righteous, not even one;

Romans 3:10 (New International Version – UK)

In short, Jacob could not have earned God’s blessing. Furthermore, we can take some comfort from the fact that God blessed him despite his behaviour. And finally, we can see that in His glorious timescale, God’s purposes will be fulfilled, even though we and our enemy try our hardest at times to defeat those purposes.


Scripture taken from the HOLY BIBLE, NEW INTERNATIONAL VERSION®. Copyright © 1973, 1978, 1984 Biblica. Used by permission of Zondervan. All rights reserved.

The “NIV” and “New International Version” trademarks are registered in the United States Patent and Trademark Office by Biblica. Use of either trademark requires the permission of Biblica.

Isaac – Brancoveanu Monastery image copyright © Fergal of Claddagh, licensed under Creative Commons. Used with permission.

A Holiday Message From Rob Pomeroy: Why I’m not an Atheist

Ricky Gervais

This year, Ricky Gervais strayed some distance from his usual field of comedy, posting a Christmas message for the Wall Street Journal, entitled Why I’m an Atheist. Within a week, the article had attracted nearly 6,000 comments.

A colleague brought my attention to the article and I’m glad he did. It was an interesting read. I commend Ricky for his honesty in expressing the reasons for his belief system at a time where personal belief seems an increasingly taboo subject.

Concerning belief, he makes a good point: “People who believe in God don’t need proof of his existence, and they certainly don’t want evidence to the contrary.” He’s right in observing the tendency to become entrenched in one’s beliefs and fearful of challenge to those beliefs. That is profoundly disappointing to me. I do not want to believe in something false, even if (as Plato observed) some good might come from that belief. No, I want to believe in something real and true, so far as such can be established. Therefore I welcome challenge to my faith. If the things I believe are true, they will stand up to any scrutiny and to the extent that I might be wrong or misguided, I want to be corrected.

Not all Christians feel the same way.

Where Ricky misses his own point is in neglecting to observe its application to him. In my experience, it is just as true to say, “People who don’t believe in God don’t need proof of his non-existence and they certainly don’t want evidence to the contrary.” Vast swathes of literature reporting miracles and the transforming effect of a personal relationship with God are dismissed out of hand. Let’s be clear: God, if He exists, is a spirit. What kind of evidence are you expecting?

But I agree with Ricky. When Christians (indeed believers of any persuasion) utter post-modern mantras like, “This is true for me,” or, “This is my reality – show me yours,” I cringe inwardly. Truth is not like that. In fact no one believes that, deep down. No one believes that the sofa that I’m sitting on has the capability of disappearing into non-existence in Schroedinger’s world between sofa and non-sofa. With the exception of a few very esoteric thinkers, we do all believe in the factual absolute truth that the sofa is not in my head.

If Jesus existed (and no serious historian now doubts that) then He was either truly God’s son or a lunatic. Let’s not be wishy-washy about that. There is overwhelming support for the fact that He made this claim. He had a reputation of performing miracles – this reputation was not confined to sympathetic or “Christian” writers. Jesus claimed to be the only way to God. There is no room in that view for half-hearted truth claims. Either Christ is the way for everyone or He’s the way for no one.

As an aside, this is where an accusation of intolerance is falsely levelled at Christianity. All world views have similar truth claims. Crusading atheist Richard Dawkins for example famously believes that parents teaching their children the truth of the Gospel are effectively committing child abuse. There’s tolerance for you. But I digress.

Let’s address the central point in Ricky’s world view: “I don’t believe in God because there is absolutely no scientific evidence for his existence and from what I’ve heard the very definition is a logical impossibility in this known universe.” This reveals that he has bought into the “enlightened” spirit of the age which wants us to believe that the only route to truth is through science. Since when did science acquire the monopoly on truth? For instance, ethics can tell us a lot about how we should practise science, but science can tell us nothing about how we should practise ethics. Science is a study of the observable universe, so it stands to reason (yes reason!) that it is in no position to comment on something unobservable or non-corporeal. If God exists, He is spirit.

I’ve recently been hearing about the Kalām cosmological argument which briefly states:

  • Everything that begins to exist has a cause.
  • The universe began to exist.
  • Therefore the universe has a cause.

Modern science does not take issue with this line of reasoning. Most cosmologists, Stephen Hawking included, believe that the universe is not eternal, that it “started” at some point in time. But we know from experience (don’t we?) that things do not just spring into existence out of nothing. It never happens. Why should the universe be any exception?

This then leads us to account for the existence of the universe: at this point we have a choice which faith statement to accept since it becomes impossible by any known method (including scientific method) to prove something beyond the sphere of our own universe. Do we believe in magic? A supreme being? Or some other idea which science is bound to hit upon eventually? At this metaphysical level the most elegant and yes, logical, account for the existence of the universe is an eternal being with will and intent. That being has to be eternal since the being cannot itself have come into existence (that would stick us with an infinite regression). That being can’t simply be matter since we know that matter has a beginning.

So the definition of God, far from being a “logical impossibility in this known universe” is a logical necessity and remains the best explanation we have to date of the fact of existence.

“Arrogance is another accusation. Which seems particularly unfair. Science seeks the truth. And it does not discriminate.” Here Ricky is confusing science with scientists. Science is practised by scientists and, I flatter myself, I have enough experience of them to detect a tendency towards arrogance, bias and discrimination. That is not unique to scientists; we all are like this.

I don’t follow why Ricky believes the burden of proof for God’s existence is on the believer. Be that as it may, believers have been demonstrating the existence of God for millennia and can hardly be blamed if non-believers refuse to accept that demonstration.

Keeping it real, Ricky’s account of the loss of his faith is poignant and saddening. He felt that his mother’s imposition of faith upon him was a sham to encourage him to behave “properly”. Darkly ironic. You see the biggest hurdle for belief in God, for many, is the poor way that believers behave. This is inconsistent with the stated underpinnings of love. Jesus when asked what the greatest commandment was replied, “Love God. And love people.”

But far more serious than Christians failing to comply with their own requirements is atheists following through the logical consequences of their belief system. If the universe is impersonal and amoral, there can be no logical defence of an absolute moral standard. Atheists can defend a moral consensus as much as they wish, but there can be no particular logical reason why a Stalin, Mussolini, Hitler or Genghis Khan should not rise up again and genocidally attempt to accelerate evolution.

If it doesn’t suit me for you to live, why should you live? The universe doesn’t care. If I’m stronger than you, why should your genetic material be given a chance to outlast mine? No moral reason. The universe doesn’t care. We all die anyway.

You say you’re trying to live a moral life. Good for you. But why should your morals have any impact on me? You’re in my space. So I’m going to kill you. That this reasoning is perfectly legitimate in the absence of an absolute moral standard cannot be disputed. You may not like it, but we’re not talking about like/dislike. We’re talking about right/wrong.

In my life I have experienced God’s intervention and known his love in a way that has surpassed coincidence and landed firmly in the realm of truth. I have tested this belief system and it has stood up to every challenge. When Christians talk about standing on a rock, this is what they mean. I embrace my faith and I embrace science. There is one important proviso: where my faith and science disagree, I have learnt to let faith preside over science. Experience has shown so far that science eventually catches up with faith, a trend I fully expect to continue, if science is indeed as honest as Ricky likes to believe.

Ricky Gervais photo copyright © Nadja von Massow, licensed under Creative Commons. Used with permission.