A Drupal Hosting Adventure

    I've been looking into hosting options for Drupal lately, and I really haven't found anything that looked amazing that was also in my price range. I know how to administer a server, but that doesn't mean I really want to. However, once I found that there were no suitable shared hosting services, I decided to explore other options.

    The Situation

    One thing I've noticed is that a lot of new Drupal users use a shared hosting provider such as GoDaddy or Site5 (which is probably the best shared hosting provider I've EVER had the pleasure of doing business with). In most cases, this is a bad idea - Drupal doesn't perform well on these sorts of hosts (Site5 wasn't bad, but I could do better with root access and a VPS). My theory is that users select these hosting providers primarily based on price.

    While I disagree with that criteria for choosing a web host (your website isn't important to spend $20/month on? Skip a couple more morning coffees every month!), I can empathize with it. Money is tight, and everyone is looking to cut costs where possible.

    An Alternative

    I spent some time over the last few days trying to find an alternative for these inexpensive hosting services. Most of what I've found has been VPS providers or Managed Server providers, which are usually above the preferred price point of website owners.

    Then, I found Rackspace Cloud Servers. You get full root access starting at just $10.95/month (estimated cost).

    256MB of RAM is not a lot to work with, so I had to do some thinking about how to set things up. My result was pretty surprising, especially for such a limited amount of RAM.

    Measurement Value
    Nodes 645
    Users 52
    Comments 1792
    Document Path /index.php (Drupal front page)
    Document Length 29.841 kb
    Concurrency Level 10
    Requests Per Second 35
    Mean Time Per Request 80ms (including network latency)

    Okay, so it's not quite Project: Mercury, but it's pretty decent performance out of a cheap VPS.

    So, you're probably asking: why would I ever do this? The answer is that you probably wouldn't. This tutorial is for people that:

    • Are considering a new web host, but don't want to pay more than $11.
    • Currently host their site on GoDaddy or similar and are tired of the performance problems
    • Want a reasonably performant site on cheap hosting

    This tutorial is not for people that:

    • Get more than 30 requests per minute (one every two seconds) (seriously, if you have that much traffic, suck it up and get a bigger server).
    • Aren't familiar with the Linux command line (In the future, I may automate this installation process, but it currently requires a fair bit of configuration (I walk you through it, though...it's not too difficult))
    • Don't know how to troubleshoot problems that may come up (with shared hosting, you have a support department you can call. Rackspace might help with your problem, but you better know what's up when you call.)
    • Are going to email me and ask a million questions about it. I wrote this tutorial so I didn't have to deal with people that chose to use crappy hosting providers. (Sorry if that sounds harsh, but that's how it is.)
    • Have more than 512MB of RAM available (some of the concepts may apply, but a some of the configuration will need to change to take advantage of more memory).

    Initial Setup

    First off, sign up for a Rackspace Cloud server. You want the one with 256MB of RAM. If I remember correctly, they require that you do a little verification thing to enable server creation, so work with their support people to make that happen if necessary.

    When you create your server, choose Ubuntu 11.04 for the operating system. Name the server whatever you'd like.

    When you click Create, you will be given a root password. Make a note of this password, because you'll need it in a few seconds.

    When the server is up and running, find the IP address. This should be listed on the server status page in the Rackspace control panel. For the duration of this tutorial, I'm going to use 1.2.3.4 as the IP address.

    Open a terminal and type ssh root@1.2.3.4 (making sure to substitute your server's IP address). If asked about an SSH fingerprint, type yes.

    Next, you'll be prompted for a password. Type in the password you were given by the Rackspace control panel. As you type, there will be no feedback, but the password is being received. Just type carefully and press enter.

    Basic Configuration and Software Installation

    First off, run the following two commands to ensure that all the preinstalled software is up to date:

    apt-get update
    apt-get upgrade

    Install all of the software we'll need (except nginx):

    apt-get install php5-cli php5-cgi php5-dev php-pear php-apc php5-mcrypt php5-gd psmisc php5-sqlite sqlite3 drush

    We're not installing the php5 package, since that's a metapackage that pulls in Apache, and we're not installing mysql because we're not using MySQL! Instead, we'll be using nginx and sqlite.

    Next, we'll need to install Nginix. Unfortunately, the version of Nginx that is included in the default Ubuntu repositories is a bit old. Nginx provides their own repositories, so we can just use those!

    echo "deb http://ppa.launchpad.net/nginx/stable/ubuntu natty main" >> /etc/apt/sources.list
    apt-key adv --keyserver keyserver.ubuntu.com --recv-keys C300EE8C
    apt-get update

    Now that we've added the Nginx repository, we can go ahead and install it:

    apt-get install nginx-light

    Nginx Configuration

    The stock configuration of Nginx is pretty good, but we'll need to make a few tweaks.

    First, edit /etc/nginx/nginx.conf and change worker_connections 768; to worker_connections 1024;.

    Next, edit /etc/nginx/sites-available/default. Make it look like this, but make sure to change the server_name value to your domain:

    server {
            root /var/www;
            index index.html index.htm index.php;
            server_name cweagans.net;
     
            location / {
                    try_files $uri $uri/ @drupal;
            }
     
            location @drupal {
                    rewrite ^/(.*)$ /index.php?q=$1 last;
            }
     
            location ~ \.php$ {
                    fastcgi_pass   127.0.0.1:9000;
                    fastcgi_index  index.php;
                    fastcgi_param  SCRIPT_FILENAME  /var/www$fastcgi_script_name;
                    include /etc/nginx/fastcgi_params;
            }
    }

    Set up PHP FastCGI

    The PHP CGI software is already available, but we need it to start on boot. To do that, create the file /etc/init.d/php-fastcgi and put this in it:

    #!/bin/bash
    RETVAL=0
    export PHP_FCGI_MAX_REQUESTS=20
    export PHP_FCGI_CHILDREN
     
    BIND=127.0.0.1:9000
    USER=www-data
    PHP_FCGI_CHILDREN=5
     
    PHP_CGI=/usr/bin/php5-cgi
    PHP_CGI_NAME=`basename $PHP_CGI`
    PHP_CGI_ARGS="- USER=$USER PATH=/usr/bin PHP_FCGI_CHILDREN=$PHP_FCGI_CHILDREN PHP_FCGI_MAX_REQUESTS=$PHP_FCGI_MAX_REQUESTS $PHP_CGI -b $BIND"
     
    case "$1" in
        start)
          echo "Starting PHP FastCGI..."
          start-stop-daemon --quiet --start --background --chuid "$USER" --exec /usr/bin/env -- $PHP_CGI_ARGS
          RETVAL=$?
          echo "$PHP_CGI_NAME."
      ;;
        stop)
          killall -9 php5-cgi
          RETVAL=$?
      ;;
        restart)
          killall -9 php5-cgi
          start-stop-daemon --quiet --start --background --chuid "$USER" --exec /usr/bin/env -- $PHP_CGI_ARGS
          RETVAL=$?
      ;;
        *)
          echo "Usage: php-fastcgi {start|stop|restart}"
          exit 1
      ;;
    esac
    exit $RETVAL

    Next, make it executable, start the process, and instruct the system to run it on startup:

        chmod +x /etc/init.d/php-fastcgi
        /etc/init.d/php-fastcgi start
        update-rc.d php-fastcgi defaults

    Lastly, restart Nginx and the PHP CGI processes to make sure all configuration options have been loaded:

    service nginx restart
    service php-fastcgi restart

    Test

    Now for the moment of truth: let's see if this setup actually works!

    Create the directory /var/www (if it doesn't already exist), then create /var/www/index.php with this in it:

      <?php echo phpinfo(); ?>

    Open a browser and point it at 1-2-3-4.static.cloud-ips.com (remember to replace the first part of that URL with your IP address). You should see the PHP info page right away. Check to make sure SQLite is available, as well as APC. If that's the case, then we can move on. If not, do not continue until you figure out what went wrong.

    Once this is working, keep this browser window open - you'll need it in the next step.

    Install Drupal 7

    It's much easier to direct this process using shell commands instead of English, so do all of this stuff:

    cd /var/www
    drush dl drupal
    cd drupal-7.9    # This directory name may be different for you depending on when you're following this guide
    mv * ..
    mv .gitignore ..
    mv .htaccess ..
    cd ..
    rmdir drupal-7.9
    cd sites/default
    mkdir files
    cp default.settings.php settings.php
    chmod 777 settings.php files/

    Next, go back to your browser window and refresh the page. You should be greeted with the Drupal 7 install screen.

    When installing Drupal, make sure you select the sqlite option and NOT the MySQL/MariaDB option. This server is not running MySQL, but installing Drush through apt-get unfortunately also installs the PHP MySQL database driver.

    Use your new Drupal site!

    This is the end of the tutorial. You can go play with your shiny new Drupal site now.

    If you have any ideas on how to improve or automate this process, please contact me. I'm very interested in keeping this guide up to date. Enhancement suggestions should keep in mind that this guide is targeted at VPSes that have very small amounts of memory (somewhere in the neighborhood of 256MB).

    Comments

    mig5's picture
     

    mig5 (not verified) says:

    Hey Cameron,

    The best way to go about automating this? Check out Puppet :)

    http://puppetlabs.com

    Bit of a learning curve trying to 'template' your server for re-use via Puppet later, but it is *well* worth the effort.

    I've written about (and am in the business of) automating even the provisioning of Drupal-friendly servers and then puppetising them, but I'm not here to self-promote. Happy to help if you want to ping me about it down the track.

    Also - just a minor nitpick: as a fulltime sysadmin, I'd encourage you to avoid 'mid' releases like Ubuntu 11.04 - stick to a Long Term Support or LTS release such as 10.04 - your server will stop receive security patches much sooner otherwise, which is generally Not Good.

    Cheers!

    mig5
    http://mig5.net

    cweagans's picture
     

    cweagans says:

    Yeah, I thought about Puppet. Also looked into bcfg2 and chef. My main concern was getting this out the door so people could start using it - it really does beat shared hosting :)

    I didn't use an LTS because I didn't think it would really be a concern for the audience this tutorial is written for - honestly, if somebody isn't willing to put a little bit of money into their site, it probably won't be around long enough for an LTS release to do any good.

    Also, even if the site is around for a while, upgrading Ubuntu is really easy...there's no reason not to do it. And as I said, I intend to keep this guide updated (or create new versions of it for new Ubuntu releases), so I can test the upgrade path and whatnot as needed.

    If you'd be interested in helping to automate this installation, it'd be much appreciated!

    mike's picture
     

    mike (not verified) says:

    You should use PHP 5.3.x and use PHP-FPM. +1 on suggesting nginx.

    I think Ubuntu 11.04 ships PHP 5.3 now... you should be able to install "php5-fpm" I believe and skip the hacky php-fastcgi script. That's so 2003 :)

    cweagans's picture
     

    cweagans says:

    Oh, good call! I'll have to play with that. Is that just a drop-in replacement for php5-cgi in this case? That is, should I have to do any tweaking of the nginx configuration?

    fschaap's picture
     

    fschaap (not verified) says:

    apt-add-repository will add a repository to your sources list and fetches the key for you in one fell swoop :-)

    Capi Etheriel's picture
     

    Capi Etheriel (not verified) says:

    And it is as easy as sudo apt-add-repository ppa:nginx/stable

    Gys's picture
     

    Gys (not verified) says:

    I do not understand your measurement/value table. I hope you explain this for me:

    - Why are none of the numbers rounded ? Like '50 users', 'doc length 30Kb'. Seems more appropriate as nobody will ever have a website with exactly the same specifications ?

    - 52 users is a very small number of (registered ?) users for a website ? Maybe that is the max number of active users at any time ?

    - Why is the document path of importance to the amount of memory ?

    - What does concurrency level mean ? Does it have a relation with the number of users ?

    - 'Requests Per Second' is 35. But then you write this tutorial is not for websites having more then 30 requests per MINUTE. Even if the first number was meant to be 'Requests Per MINUTE', this does not make sense to me ?

    Thank you !

    cweagans's picture
     

    cweagans says:

    The idea was to report information about my test environment, not to specify users' environments.

    It is a pretty small site, but it's also a pretty small server. If you have a ton of users, you need a bigger server.

    The document path is important because it's telling you that I'm loading the front page in my load test - with 10 nodes + a pager on the home page, there's a pretty fair amount of work to do to render it.

    The concurrency level is the value I used with apache bench - basically, 10 concurrent connections hitting the site at the same time

    If you have more than 30 requests per minute, you should also be willing to spend more than $11/month on your server. The setup I describe is CAPABLE of handling 35 requests per second, but just because you can do something doesn't mean you should. The point I was trying to convey was that this setup is for people that would normally use shared hosting for their site. When you have more than 30 requests per minute or so, you should probably be thinking about moving to a better server setup with more dedicated resources, not trying to string along a tiny VPS with minimal memory and hard drive space.

    30 requests per minute is roughly 43000 hits per day (or 1,296,000 hits per month). Like I said, if you're getting that much traffic, suck it up and pay for a bigger server.

    Add new comment

    Filtered HTML

    • Web page addresses and e-mail addresses turn into links automatically.
    • Allowed HTML tags: <a> <em> <strong> <cite> <blockquote> <code> <ul> <ol> <li> <dl> <dt> <dd>
    • Lines and paragraphs break automatically.

    Plain text

    • No HTML tags allowed.
    • Web page addresses and e-mail addresses turn into links automatically.
    • Lines and paragraphs break automatically.
    By submitting this form, you accept the Mollom privacy policy.