Configure Apache and Mysql the easy way

Posted July 18th, 2011 in Php by Florentin

This is a simple way to setup a LAMP environment after you have just installed a Linux (i.e. Ubuntu)
or if you’d like to replicate the setup of another machine (i.e. duplicate your desktop’s environment to your laptop)
The key is to keep all your customizations in separate files and directories.
We start by creating a new folder where all our custom settings will live.

1. prerequisites

Create a directory named "lamp" with the following structure:

├── apache
│   └── elmo.conf
├── mysql
│   └── elmo.cnf
├── php
│   └── elmo.ini
└── virtualhosts
├── 000-localhost.conf
└── phpmyadmin.conf

2. configure Apache 2

The default apache2.conf (/etc/apache2/apache2.conf) is setup to include every settings file it can find inside the "conf.d" directory (/etc/apache2/conf.d)
so make sure this line is included:
Include conf.d/

We will sym link our Apache customizations into this directory:
sudo ln -s /lamp/apache/elmo.conf /etc/apache2/conf.d/

You may now add your own Apache settings into the elmo.conf file.
The files under "conf.d" are loaded in order of their file names i.e. aaa.conf loads before bbb.conf
All the files inside "conf.d" are loaded at the end of the apache2.conf so your custom settings may override the defaults.

After the settings are in place, you may want to automatically configure some virtual hosts.
Optionally, you could delete the default/old virtual hosts:
rm /etc/apache2/sites-enabled/*

Now new hosts are ready to be enabled:
ln -s /lamp/virtualhosts/000-localhost.conf /etc/apache2/sites-enabled/

3. configure Mysql 5

Mysql does the same configuration loading as Apache.
The last my.cnf directive is "!includedir /etc/mysql/conf.d/" which loads every settings file from the "conf.d" directory.
Let’s do the symbolic linking:
sudo ln -s /lamp/mysql/elmo.cnf /etc/mysql/conf.d/

Place all your Mysql customizations inside the elmo.cnf file.

4. configure Php / Zend Server CE 5.2

My Php environment is provided by Zend Server Community Edition.
The php.ini file located under /usr/local/zend/etc/ uses this directive to include the settings file from inside "conf.d":

Obviously, we will create a symbolic link to our custom Php settings:
sudo ln -s /lamp/mysql/elmo.ini /usr/local/zend/etc/conf.d/

5. other

If you wish to automate things further add all the commands inside a bash script:

# USAGE: sudo ./


# mysql
ln -s $ROOT/mysql/elmo.cnf /etc/mysql/conf.d/

# apache
ln -s $ROOT/apache/elmo.conf /etc/apache2/conf.d/

# remove old virtual hosts
rm /etc/apache2/sites-enabled/*

# add my virtual hosts
ln -s $ROOT/virtualhosts/000-localhost.conf /etc/apache2/sites-enabled/
ln -s $ROOT/virtualhosts/phpmyadmin.conf /etc/apache2/sites-enabled/

# php configuration
ln -s $ROOT/php/elmo.ini /usr/local/zend/etc/conf.d/

Here you can download a sample

Searching for Django help and inspiration

Posted July 18th, 2011 in Python by Florentin

The most important resource which will answer most of your questions is the manual.
1. You can either use the built in search:
2. Or search the documentation though Google (my preference):

This is the second biggest resource of information regarding Django development.
There are several ways to search for answers:
1. Use the search form and look for the terms "django" and the topic you are interested in (e.g. "forms"):
2. Search for the tag "django" and your topic of interest (e.g. "forms")[django]+forms

The first form yields many more results than the second, but the relevance of the second type of search is higher.
Furthermore, you can sort your results by "relevance", "newest", "votes" and "active". I recommend using "votes" when searching for a high level topic like "forms".


If the first 2 methods don’t help, you may need to ask the big boss:

You may have to remember to use "+" or "*" inside your queries if you are looking for something very specific.

Small fragments of code that you can use or get inspiration from.

Search for Python modules. Try your search with and without the "django" term added to the query.
A nicer list of Django packages with details about usage, contributions and others is


If you are used to IRC channels, mailing lists or forums this page gives some indications:

search with firefox shortcuts

One last trick for Firefox users, "Add a keyword for this search" improves your query rate a lot. Some of my settings:

Keyword: so

Keyword: dj

Keyword: djsnip

Keyword: pip

Host based PHP settings

Posted July 18th, 2011 in Php by Florentin

How do you deploy a php settings file on multiple hosts which require different configurations ?
Let’s use the wp-config.php (WordPress configuration file) as an example.
The following snippets are going to be used inside your project’s config file (wp-config.php in this case)

Solution 1


if($_SERVER[‘HTTP_HOST’]==’’ || $_SERVER[‘HTTP_HOST’]==’’) {
# settings for the host
} else {
# default settings


if(strpos($_SERVER[‘HTTP_HOST’], ‘’)!==false) {
# settings for
} else {
# default settings

If you need to define settings for multiple hosts, use a "switch" statement instead of "if"

Instead of "HTTP_HOST" one can also use "SERVER_NAME"

Alternatively to HTTP_HOST one can set the following in the apache’s virtual host
SetEnv APPLICATION_ENV "development"
then check for $_SERVER[‘APPLICATION_ENV’]

- light on the CPU and no disk access

- only works when the PHP file (wp-config.php in our example) runs though a web server environment, i.e. $_SERVER[‘HTTP_HOST’] is available.
- all settings live in the same file, if the file is added to a version control system everyone can view those settings.

Running the code though command line won’t work as expected.

Solution 2

if($_SERVER[‘REMOTE_ADDR’]==’′) {
# localhost settings, host1
} else {
# any other settings, host2

- only works for 2 hosts, a localhost host (host1) and a remote host (host2)
- the settings for the host considered remote (host2) only work when the visitors come from a non-local IP.
If one uses SSH or VCN to access the remote machine (host2) then load the site/script locally, the host1’s settings will get loaded.

Solution 3

Create a file named "wp-config-local.php" in the same directory as wp-config.php then add the following to wp-config.php

if ( file_exists( dirname( __FILE__ ) . ‘/wp-config-local.php’ ) ) {
# the current host’s settings
} else {
# default settings

Every host would then manage it’s own wp-config-local.php without the need to share it though a version control system.

- privacy, it remains private to the host’s users
- works fine even if the script is called though the command line

- disk access

NiftyUrls – A Django powered Popurls script

Posted March 21st, 2011 in Python by Florentin

Hello and welcome

Niftyurls is a popurls-style script built entirely with Django.

Get NiftyUrls from GitHub

View some examples
From the popurls site:

… is the dashboard for the latest web-buzz, a single page that encapsulates up-to-the-minute headlines from the most popular sites on the internet.


Unique features

  • Powered by Django
  • No tooltips by default, there are better ways of reading the text
  • Read the news in a Facebook-style lightbox (“pop” layout)
  • Read the news in a clean page (“page” layout)
  • Easy editable feed settings, titles, urls, positions in the page
  • Javascript assisted by jQuery
  • Grid templates provided by Yui3 Grids
  • Fast text replacement with Cufon


Upcoming features

  • remember visitor’s last viewed links, mark new/old links
  • show new links only
  • videos support
  • admin interface for feed configuration, more config options
  • multiple domain support
  • site search with database support
  • usability improvements
  • user accounts, openid support
  • code comments, svn support

Installation (linux, localhost)

    • 1. Make sure you have the following Python packages available: Django – Pil – Feedparser – You may install these with the “pip” tool ( $ pip install “django>=1.3″ $ pip install pil $ pip install feedparser
    • 2. Add “niftyurls” to the INSTALLED_APPS tuple. The Niftyurls application depends on the following Django packages: ‘django.contrib.staticfiles’ ‘django.contrib.admin’ To make sure every app is enabled, add the following line to your project’s “” file: INSTALLED_APPS += (‘django.contrib.staticfiles’, ‘django.contrib.admin’, ‘niftyurls’, )
    • 3. Synchronize the database $ python syncdb
    • 4. To add the “niftyurls” in your templates, use the following:

{% load niftyurls_tags %} {% niftyurls_media “js,css” %} {% niftyurls_content %}

  • 5. Please check the available Niftyurls settings in niftyurls/ You may add custom values to NIFTYURLS_SETTINGS (please see niftyurls/ and retrive them inside your templates with: {% niftyurls_settings title %} {% niftyurls_settings h1 %}
  • 6. Add some feeds in the admin interface Here are some feed urls examples: – –
  • 7. Run the following command so that fresh entries are added to the database. $ python niftyurls_feeds
  • 8. Niftyurls templatetags depend on the existing of the “request” inside the templates, in case of errors verify that you have passed the “RequestContext” to the templates. Make sure the TEMPLATE_CONTEXT_PROCESSORS contains the following: (‘django.core.context_processors.request’, ‘django.contrib.auth.context_processors.auth’,)

NiftyUrls’s page on GitHub

GTranslator – In place web page translation tool with Google Translate

Posted October 13th, 2010 in Javascript by Florentin

What is GTranslator

If you have ever spent more time browsing though non English web page with the help of Google Translate you most noticed some downsides, most common being the one where Google Translate don’t work on some pages.
To make translations easy and on the fly, I wrote this GreaseMonkey (a Firefox addon) script called GTranslator. It uses Google Translate to replace the text inside the web pages with the appropriate translated versions.


In order to use this tool you’ll be needing Firefox with the GreaseMonkey addon installed.
You just have to open a Firefox instance, visit the tool’s page GTranslator and click on the “Install” button.
After installation, you will have to access the GreaseMonkey menu “Manage User Scripts” and include some pages for which the translation tool will be available.
This “included pages” codes enable the tool for all Swedish, Danish or German, pages

How it works

There are a couple of shortcuts available:
F8 redirects the loaded url to
F9 translates the current page
F10 enables/disables the auto translation. When automatic translations are enabled the tool translates the text without any user intervention.

Make sure you have enabled the tool for the current TLD (e.g. *.de/*) or specific websites by accessing the “Manage User Scripts” of the GreaseMonkey extension.

If you like the script don’t forget to rate and comment on :)

NiftyArticles – extract articles from any webpage with Python, Webkit and Readability

Posted September 2nd, 2010 in Python by Florentin

What is NiftyArticles

NiftyArticles is a small Python script which lets you identify and save articles from inside webpages. It is based on Readability.

Update 10.02.2011

I have made 2 versions of the script, one is using QT4 and the other is based on GTK.
The QT4 version is slightly better.


Each version depends on readability.js, please download that file and place it in the same directory as the niftyarticle script.

The installation details for each version is located inside the script file.

Usage (QT4 version)

To get a full list of options, run:
python –help
OR if you made it executable,
/path/to/ –help

# save an article from
python -u

Help for the QT4 version

The script has been developed and tested on Python 2.6.6 / Ubuntu Maverick

Install the required packages: python-qt4 libqt4-webkit
Ubuntu or Debian
sudo apt-get install python2.6 python-qt4 libqt4-webkit

(Optional) Mark the script as executable
chmod +x

Usage Examples:
python --help

# save an article from
python -u

# show the browser window, load images, enable java applets
python -b -i -v -u

# to run the script on a server with no GUI available, you must install xvfb
sudo apt-get install xvfb
# then you can do
xvfb-run -a python -u

Webkit Reference

Download the NiftyArticles from GitHub

HtmlClipper – save html content from any website

Posted August 26th, 2010 in Javascript by Florentin

What is HtmlClipper

HtmlClipper is a bookmarklet which lets you copy html sections of any web pages together with the attached css styles. After the script is enabled inside a web page, you may select and extract any html element together with all it’s children and computed css styles. What you get is a new html document made up of an inline stylesheet and html code needed to render the element as close as possible to what you’ve seen in the source web page.
The bookmarklet only works in Firefox and Google Chrome.

Download HtmlClipper from GitHub

Firefox Installation

  • Make sure the “Bookmarks Toolbar” is visible. If it is not, go to menu View > Toolbars.
  • Drag this link: Html Clipper up to your Bookmarks Toolbar.

How to use it

  • click the bookmarklet from your Bookmarks Toolbar
  • click inside the html page to select an element
  • press “w” to select the parent element
  • press “q” to undo the selection of parent element
  • press “r” to remove an element
  • press “s” to clip the element
  • press ‘esc’ to exit the ‘clipping’ window
  • press ‘x’ to exit HtmlClipper

Here are some screenshots of webpage clippings created with HtmlClipper:

Easy deployment with Python and Fabric

Posted August 26th, 2010 in Python by Florentin


This article is about writing tools in Python to easily deploy your web projects.
A well know deployment library in Python is Fabric. While it’s not really mature (version 0.9.1), it is easy to understand and work with it. The best place to start is the Fabric tutorial.

The Challenge

You develop and maintain many projects. You backup and restore databases several times a day during the development phase or you need to upload or download files from the hosting server often. How would you improve these processes instead using Ftp, mysql/mysqldump or phpmyadmin ?

Quick Fabric Introduction

Fabric gives you instruments to run commands on different hosts and copy/download files to/from remote hosts. In order to do that, you have to prepare a file of available commands named which will be placed in the project’s directory. Having some methods in that file allows you to run the commands like that:

fab hello

where hello is one function defined in
Fabric installation process.
sudo easy_install fabric
sudo pip install fabric

The Solution

Having a lot of projects to maintain and deploy makes difficult to write one for each of them.
Also using remote hosts or writing database queries require you to put sensitive information in the (or pass them as parameters but that’s a different talk)
My thought is to have one location available where I place a and configuration files of all the sensitive information required for deployments, i.e. remote host addresses and maybe passwords, database connection information, etc. If you care more about security than speed of development, don’t store sensitive information there.
I have created a directory /work/fabric with the following structure:
├── projects
│   ├──
│   ├──
│ ├── contains the deployment code based on Fabric store configuration details of the localhost database
projects/* store configuration details of specific projects
The project name is the same with the file name used for the configuration.

Instead of placing a inside the project’s directory, we will instruct Fabric where to find the fabfile.
Create a file ~/.fabricrc and write the following line:
fabfile = /path/to/your/
I have mine placed in /work/fabric/

There are more details on fabfile discovery here.

Now we can run “fab” in any location. Here are some examples:
fab c:localhost c:localdb e:db_name=test q:clean
fab e:db_name=test_elgg e:db_file=elgg.dump.sql q:export

Commands Supported

The available for download in the end of this article gives you the power to run several commands useful in deploying projects or databases. Many commands require some parameters to exist, for example a database “clean” command which deletes all the tables from one database would require some connection details i.e. host,user,pass,db_name

Several commands may use the same parameters. To make these parameters available they are loaded from configuration files or passed to the “fab” command. All parameters are stored inside in a dictionary called “env” (environment). The environment is a big dictionary like variable (associative array for the Php users) which may store connection parameters for remote hosts, database connection properties or other information.

Most of the time you will need several params available for one command, e.g. a database command cannot function with only host name and no user provided. To make things easy, configuration files can be written where you define groups of parameters. Such a configuration file is /work/fabric/projects/ which is loaded by default. Configurations are simple Python dictionaries defined in Python files under the “projects” directory. It’s up to you to choose the names and the purpose of those settings, i.e., some might refer to database settings and other to remote hosting details. If you want to enable a set of parameters from a config file, first you need to load the file then enable the params.

Let’s take for example:
fab c:localhost c:localdb e:db_name=test q:clean

q:clean is the command and it means: delete all tables from the database define before
e:db_name defines the database
c:localdb loads the localhost database configuration, i.e. host, user, password, etc
c:localhost loads the localhost host details, i.e. host name, port, etc

Example of /work/fabric/projects/ file:
config = {
‘localdb': { # configuration name
‘db_user': ‘root’,
‘db_pass': ‘betterprogramming rules’,
‘db_host': ‘localhost’,
‘db_name': ‘test’, # default db_name if none is givven
‘db_file': ‘dump.sql’, # default dump file

“l” loads a configuration file located under “projects” directory (see the tree structure above)

fab l:ajaxdaddy

# not needed because default is loaded
fab l:default

“c” enables a configuration

# “localhost” is hardcoded into the because it’s mandatory
fab c:localhost

# enables a database configuration
fab c:localdb
fab l:default c:localdb

It’s possible to enable one configuration for a command then enable a different config for the next command.

# the second configuration “secondlocaldb” would overwrite the first one, “localdb”
fab l:default c:localdb c:secondlocalddb

After you enable custom configuration, it is possible to change specific parameters by using the “e” command.

# after i load and enable ajaxdaddy’s parameters, i.e. db_user, db_pass, db_host, db_name i can change the previously stored db_name value by using “e”
fab l:ajaxdaddy c:ajaxdaddydb e:db_name=db2_ajaxdaddy e:db_user=ajaxuser

In conclusion, there are 3 ways to set the parameters which will be used by your commands:
– by writing configuration files and place them under “projects” directory, load the config file (e.g. “l:ajaxdaddy”) and enable a specific group (e.g. “c:ajaxdaddydb”)
– by passing single parameters to the “fab” command (e.g. “e:db_user=gigi”)
– by passing parameters to the command itself (you will see how it works later)

Datase Commands

Database commands starts with “q” and are followed by an action.
The available actions are:
clean: delete all the tables inside the “db_name” database
export: export the database “db_name” to the file “db_file” (db_file may be provided or created programmatically by the from db_name)
import: import “db_file” into “db_name”
show: list all the databases where the “db_user” has access
create: create a new database called “db_name”
grant: grant all on “db_name_new” to “db_user_new” identified by “db_pass_new”

You may define your own actions in the configuration files. You just have to create a class named “DbAction”+actionname , e.g. class DbActionCreate(DbAction) or class DbActionClean(DbAction)
When loading a configuration file, your action class will also load.

# enables localhost (it’s enabled by default anyway), enables localdb so that “q” knows where to operate, sets the environment variable “db_name” to “test” then execute command
fab c:localhost c:localdb e:db_name=test q:clean
same with
fab c:localdb e:db_name=test q:clean

# selects the “test” db and export that db into “dump.sql” file
fab c:localhost c:localdb e:db_name=test e:db_file=dump.sql q:export

# create a new database “test_2″ and grant access to the user defined in “localdbnew”
fab c:localhost c:localdb c:localdbnew e:db_name=test_2 q:create q:grant

# delete all tables from “test” db and import the “test_elgg.sql” file
fab c:localdb e:db_name=test e:db_file=test_elgg.sql q:clean q:import

The list of all parameters used by the database commands:

File commands

# zip the temp directory, temp must be located under the current directory, it will create “”
fab zp:temp

# zip the “temp” directory and create the archive named “”
fab e:file=temp, zp

# zip “temp” directory’s content, i.e. do not include the “temp” parent directory in the archive
fab zpi:temp

# unzip “” into the “dest” directory
# same with
fab e:file=filename uzp:,dest
# same with
fab e:file=filename,dest=dest uzp

# load the “temp” config file and enable dreamhost parameters (“c:dreamhost”) then upload into the “stuff” directory located on the remote host inside the base dir. The base directory is defined in “base_dir” parameter, if base_dir=/var/www then the uploaded file will be located in /var/www/stuff/
fab l:temp c:dreamhost,stuff

# download /var/www/ to the current directory if base_dir=/var/www
fab l:temp c:dreamhost

List of file commands:
zp: zip a “file” (file or directory) to “dest”
zpi: zip a directory’s contents, exclude the directory itself from the archive
uzp: unzip a “file” to “dest”
up: upload a “source” (local host) to “dest” (remote host)
dl: download a “source” (remote host) to “dest” (local host)
cl: delete a “file”

Complex Commands

# exports “test_elgg” database into “dump.sql” and upload it to “dreamhost”. “up:e.db_file” means that the value of “db_file” located in the environment should be uploaded.
fab c:localhost c:localdb e:db_name=test_elgg e:db_file=dump.sql q:export l:dreamhost c:dreamhost up:e.db_file
# same with
fab c:localdb e:db_name=test_elgg e:db_file=dump.sql q:export l:dreamhost c:dreamhost up:dump.sql
# similar but different dump name “test_elgg.sql” created by default from “db_name” + “.sql”
fab c:localdb e:db_name=test_elgg q:export l:dreamhost c:dreamhost up:test_elgg.sql

# same as above, but upload a zip file which will be called by default “”
fab c:localdb e:db_name=test_elgg e:db_file=dump.sql q:export zp:dump.sql l:dreamhost c:dreamhost up

# same but unzip on destination
fab c:localdb e:db_name=test_elgg e:db_file=dump.sql q:export zp:dump.sql l:dreamhost c:dreamhost up uzp

# same but delete “cl” the dump.sql from localhost and delete “cl” dump.sql from the remote host
fab c:localdb e:db_name=test_elgg e:db_file=dump.sql q:export zp:dump.sql cl:dump.sql l:dreamhost c:dreamhost up uzp cl:dump.sql

Download and a few examples

Filter your video collection with Python and IMDbPY

Posted August 23rd, 2010 in Python by Florentin

If you have a large collection of movies (documentaries, dvd rips, etc) and you would like to decide on what worth watching next, this script may come in handy.
It’s a small Python script which scans your movie collection, collects data about each one from and allows you to filter the movies by genres, actors or publishing studio.

The movies are collected from subdirectories (of indefinite depth) of a single parent directory which is either the default path (defined in the DEFAULT_MOVIES_PATH variable inside the script) or specified by the “-p” (or –path) parameter. is looking for directories which contain at least one movie file (a file having the extension .avi, .mkv or .mpeg) The name of the movie is extracted from the directory name, not the file name.

├── temp
│   ├── Capitalism.A.Love.Story
│   │   └── cd1
│   │   └── movie.avi
│   ├── Home.tt1014762
│   │   ├── imdb.html
│   │   ├──
│   │   └── movie.dvdrip.avi
│   ├── Religuous.tt0815241
│   │   ├── imdb.html
│   │   ├──
│   │   └── moviefile.avi
│   ├── stuff
│   │   └── nothinghere.txt
│   └── Tapped.tt1344784
│   ├── file.avi
│   ├── imdb.html
│   └── -p temp will identify the following directories as movies: “Home.tt1014762″, “Religuous.tt0815241″, Tapped.tt1344784 and “Cd1″
“Cd1″ is only a subdirectory but is seen as a movie because there is one movie file inside it.
You will have to move the movie.avi file from inside “Cd1″ to it’s parent, so that “Capitalism.A.Love.Story” will be recognized as a movie name.
If your movie is not properly identified on imdb, you may rename the directory and add the imdb movie id to it, e.g., “Capitalism.A.Love.Story.tt1232207″ or “Capitalism.A.Love.Story.1232207″

In order to use, you will need a couple of things:
1. Python 2.6 on a Linux machine (I have Ubuntu 10.04)
2. imdbpy library available
sudo pip install imdbpy
sudo easy_install imdbpy
3. prettytable library
sudo pip install prettytable
sudo easy_install prettytable

Download the script on your machine and execute:
# A) this will make your script executable
chmod +x yourusername
# B1) use an alias to run the ‘movies’ script from anywhere
alias movies=”/your/path/to/”
# B2) alternatively, you can make use of symbolic links
sudo ln -s /your/path/to/ /usr/local/bin/

Examples of how to use the script, in case you have put somewhere in your PATH (method B2)

scan and refresh movies from inside the path “/home/elmo/Movies”. In case you don’t use “-p”, the default path is stored in the script variable DEFAULT_MOVIES_PATH (defined inside the script code) -p “/home/elmo/Movies” -s -r

show movies with “Andy Serkis” but not with “Brad Pitt” -l -a “+andy serkis,-brad pitt”

movies with at least one of these actors playing -l -a “?andy serkis,?angelina jolie”

movies with at least one favorite actor playing -l -o actor

comedy movies but no dramas -l -g “+comedy,-drama”

movies made by “lionsgate” production company -c “lionsgate”

movies made by any of the favorite production companies -o company

There are a couple of ‘predefined’ filters.
For example, in the script’s code you will see a large list of (good) actors. If you want to find movies where at least one favorite actor is playing, run: -o actor
The same is true for production companies -o company

Example of output: -l -g “+documentary,-drama”
| Imdb ID | Movie | Genres | Rate | Basename |
| 1014762 | Home | documentary | 8.4 | Home.tt1014762 |
| 0815241 | Religuous | documentary,comedy | 7.8 | Religuous.tt0815241 |
| 1344784 | Tapped | documentary | 6.8 | Tapped.tt1344784 |

View the whole list of options using: -h
OR –help

I hope you will enjoy the script and stay tuned for updates :)

Download here

Ubuntu Lucid VPS hosting

Posted July 16th, 2010 in Ubuntu by Florentin

Virtual Private Server (VPS) vs Shared web hosting

Virtual Private Server (VPS)

Shared Hosting


high level of control, root access, has it’s own IP(s) and system libraries

faster than the counterpart shared host (same price category)

install and configure any software and service (as long as you respect the seller’s terms of service)

guaranteed and configurable hardware resources, upgrades are possible

unlimited number of domains, sql databases, services, etc

resell hosting services

cheap unmanaged VPS providers are available (2)

several operating system to choose from

simplicity and easy to use, suitable for small sites

control panels availables, easy to setup domains, emails, user and ftp accounts, mysql databases

some hosts offer automatic backups, a necessity for the web businesses

usually the number of domains allowed is limited, number of sql databases restricted

if purchasing an unique IP is not possible, your sites will be found on the same IP as many more others which might affect SEO if you are in a ‘bad neighborhood’

cheap (3)


often hacker attacks, daily port scans

requires more time and energy from you

Managed VPS

UnManaged VPS

you are responsible for the server administration and security, installing security updates, upgrading your software

usually bad support,

overselling happen often, which means too many hosts sharing the same CPU power, too many using the same connection, etc

less resources available even if the hosting have ‘unlimited resources’ advertised (1)

low level of control, pre-configured services

usually no ssh access which prevents you from using softare versioning systems, install custom libraries, etc

difficult to secure completely because multiple users access the same system

quite a few bits of downtime

(1) Unlimited bandwidth is actually limited to the type of connection you have. On a 10baseT port, if you sustained 10 mbps for 30 days you would move 3200 GB’s of data. Shared hosts will probably limit you to a much lower port speed.
Unlimited disk space has it’s own limitations. Most hosts won’t let you store files which have nothing to do with your sites, like backup files, your private photos, etc.
Your CPU access is limited, speed and processes CPU usage and time is also limited. For example, Dreamhost sometimes doesn’t let me zip some larger directories because the zip process use too much CPU.
(2) My recommendation is I have tried (which seems to be a reseller) and before.
(3) I have been a Dreamhost client for 3 years. It stands out by allowing ssh access and python/django + ruby/rails support along with Php and Mysql.

Good to know when buying a VPS

  • Xen virtualization is better than OpenVz
  • test the server’s IP from the area where you get the most traffic on your sites
  • get as much RAM as your budget allows
  • 10Mbps unmetered or 3200GB bandwidth? Choose the 3200GB package if it’s on a 100baseT port. If it’s a 10baseT port either way, 10Mbps allows a maximum of 3200GB transfered in a month.
  • search for special offers on forums, is very good
  • there are free alternatives to control panels like CPanel and Plesk. I am using
  • find some reviews on the service/company you are interested in. Stay away from those who generally made a bad impression to users.
  • don’t go with the cheapest VPS, i learned that from experience :) A well established company will offer higher uptime, better support, more services.
  • i like HyperVM better than SolusVM
  • see if you can find out details about the CPU power offered with the package, unamanged VPS sellers usually advertise only ‘equally shared CPU’
    My first VPS had an AMD Opteron 270 which gave low benchmark scores. Currently, dmehosting is offering me i7 CPU 920 @ 2.67GHz, 4 cores
  • 32 bit operating system consumes less memory than the 64 bit equivalent.

My setup

  • I went with after trying a reseller and
  • my hardware setup is similar to VPS 3, with the few customizations.
  • the operating systems selection is large, I went with Ubuntu Lucid 10.04 32 bit because I use Ubuntu for both my desktop and laptop computer, 32 bit consumes less memory and Ubuntu Lucid is Long Term Support (LTS)
  • control panel, allows you to control most aspects of the VPS (apache, mysql, postfix, logs, etc)
  • for managing the domains and users
  • was my chosen firewall because of the integration with webmin and easy to use interface
  • zend server community edition (Php 5.2) because some of my sites don’t work with Php 5.3 (which comes default with Ubuntu Lucid 10.04)
  • server hardening operations.
    Find good server hardening here:

Why dmehosting worked fine for me

  • affordable prices
  • use their own DNS servers
  • choose from several server locations
  • great CPU power, uptime, connection speed for the price you pay
  • good customer support so far (only used twice, other people complain about the support)
  • hardware configuration flexibility
  • good presence on the webhostingtalk forum

Cheap unmanaged VPS services

  • – I am happy customer there :)

Find the latest VPS offers


Find VPS benchmark scores