How to: Multi-site CodeIgniter Set-up
A few people have asked me recently about setting up CodeIgniter to run accross multiple domains based on the same codebase. This can be handy for sites than run different databases for different geographical areas, all of which need the same code but different content.
To get this working I took a little code from PyroCMS and modded a previous article "How to: Support multiple production environments in CodeIgniter" and found a relatively simple solution.
Setting the base URL
The first step of getting CodeIgniter working anywhere automatically is curing it of it's most pointless configuration setting. It seems CodeIgniter would like to be told where it is, which really doesn't need to happen. We could solve this in many ways, but instead of extending or replacing any core code, I would preffer to put a little snippet of code into the main application/config/config.php. Enter this code into the file and it will automatically support pretty much any kind of URL.
<?php if (!defined('BASEPATH')) exit('No direct script access allowed');
/*
|--------------------------------------------------------------------------
| Base Site URL
|--------------------------------------------------------------------------
|
| URL to your CodeIgniter root. Typically this will be your base URL,
| WITH a trailing slash:
|
| http://www.your-site.com/
|
*/
if(isset($_SERVER['HTTP_HOST']))
{
$config['base_url'] = isset($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) == 'on' ? 'https' : 'http';
$config['base_url'] .= '://'. $_SERVER['HTTP_HOST'];
$config['base_url'] .= str_replace(basename($_SERVER['SCRIPT_NAME']), '', $_SERVER['SCRIPT_NAME']);
}
else
{
$config['base_url'] = 'http://localhost/';
}
Setting a SITE constant
So the website URL is now set and links are fully working around the site. Next we need a way to work out throughout our code which site is currently being used. Amongst other things, this will help us with selecting the right database settings later.
/*
|--------------------------------------------------------------------------
| Site
| Set a constant for whichever site you happen to be running, if its not here
| it will fatal error.
|--------------------------------------------------------------------------
*/
switch($_SERVER['HTTP_HOST'])
{
case 'example.com':
case 'www.example.com':
define('SITE', 'example');
break;
case 'example2.com':
case 'www.example2.com':
define('SITE', 'example2');
break;
default:
define('SITE', 'default');
break;
}
Domain based database settings
Now that CodeIgniter has its links working and it knows what site it is trying to run, it needs to know the database configuration for this domain. To do that, we can break down our config into domain specific "Database groups".
<?php if (!defined('BASEPATH')) exit('No direct script access allowed');
/*
| -------------------------------------------------------------------
| DATABASE CONNECTIVITY SETTINGS
| -------------------------------------------------------------------
| This file will contain the settings needed to access your database.
|
| For complete instructions please consult the "Database Connection"
| page of the User Guide.
|
| -------------------------------------------------------------------
| EXPLANATION OF VARIABLES
| -------------------------------------------------------------------
|
| ['hostname'] The hostname of your database server.
| ['username'] The username used to connect to the database
| ['password'] The password used to connect to the database
| ['database'] The name of the database you want to connect to
| ['dbdriver'] The database type. ie: mysql. Currently supported:
mysql, mysqli, postgre, odbc, mssql
| ['dbprefix'] You can add an optional prefix, which will be added
| to the table name when using the Active Record class
| ['pconnect'] TRUE/FALSE - Whether to use a persistent connection
| ['db_debug'] TRUE/FALSE - Whether database errors should be displayed.
| ['active_r'] TRUE/FALSE - Whether to load the active record class
| ['cache_on'] TRUE/FALSE - Enables/disables query caching
| ['cachedir'] The path to the folder where cache files should be stored
|
| The $active_group variable lets you choose which connection group to
| make active. By default there is only one group (the "default" group).
|
*/
$active_record = TRUE;
$db['default']['hostname'] = "localhost";
$db['default']['username'] = "";
$db['default']['password'] = "";
$db['default']['database'] = "";
$db['default']['dbdriver'] = "mysql";
$db['default']['dbprefix'] = "";
$db['default']['pconnect'] = TRUE;
$db['default']['db_debug'] = TRUE;
$db['default']['cache_on'] = FALSE;
$db['default']['cachedir'] = "";
$db['default']['char_set'] = "utf8";
$db['default']['dbcollat'] = "utf8_general_ci";
// example
$db['example']['hostname'] = "localhost";
$db['example']['username'] = "root";
$db['example']['password'] = "";
$db['example']['database'] = "example";
$db['example']['dbdriver'] = "mysql";
$db['example']['dbprefix'] = "";
$db['example']['active_r'] = TRUE;
$db['example']['pconnect'] = TRUE;
$db['example']['db_debug'] = TRUE;
$db['example']['cache_on'] = FALSE;
$db['example']['cachedir'] = "";
$db['example']['char_set'] = "utf8";
$db['example']['dbcollat'] = "utf8_general_ci";
// Example 2
$db['example2']['hostname'] = "localhost";
$db['example2']['username'] = "root";
$db['example2']['password'] = "root";
$db['example2']['database'] = "testfoo";
$db['example2']['dbdriver'] = "mysql";
$db['example2']['dbprefix'] = "";
$db['example2']['active_r'] = TRUE;
$db['example2']['pconnect'] = TRUE;
$db['example2']['db_debug'] = TRUE;
$db['example2']['cache_on'] = FALSE;
$db['example2']['cachedir'] = "";
$db['example2']['char_set'] = "utf8";
$db['example2']['dbcollat'] = "utf8_general_ci";
// Check the configuration group in use exists, if not use the default
$active_group = (defined('SITE') && array_key_exists(SITE, $db)) ? SITE : 'default';
?>
The little snippet of code at the bottom will check to see if the SITE constant you have set matches up with a database group. If it doesn't, it will use the default configuration group.
Your CodeIgniter set-up should now work with any domain you happen to point to it. You even run simple little if(SITE == 'example2') checks anywhere within your code to do special code for a certian site, although I would not reccomend you doing this too heavily.

Comments
Shane
2009-06-26
Your 'goto' post popped up when googling new php 5.3 functions ... then I saw this.
I have a long comment on this so I put it into a post on my new wordpress site shaneontheweb.co.uk which is basically just my spin on this subject.
Artemis
2009-11-23
I see that you have hard coded the databases names of each site..
How about dynamicly load the db name based on the url? and what if the DB doesn't exist?
How can we display our own customised db error if we are auto-loading the db library?
Thank you..
Phil Sturgeon
2009-11-30
@Artemis: Normally you hard-code one database config group, now you hardcode several. It is based on the URL in the sense that your URL specifies the value for SITE, and SITE then selects the appropriate group.
If the DB doesn't exist, you should really be entering it into your config files now should you! :-)
Taner Ozdas
2010-03-29
I use this technic for a long time. It really help me to deploymont easier.
Giancarlo Corzo
2010-05-16
Another way could be like this:
1. change the database name to the host name (ie. subdomain_domain_com)
2. Use the host variable or the SITE variable to setup the database name in the default connection.
$db['default']['database'] = (defined('SITE') && array_key_exists(SITE, $db)) ? SITE : 'default';
I'm assuming you are using the same user name and password for each database, this way you won't need to change the database file everytime you want to add a new host / database
Luk
2010-10-13
Hello there!
I'm new with CI and I'm a beginner..
I'd like to solve a problem with codeigniter config.php file.
I've got in the same host 2 domains
ex. www.1.com and www.2.com .
www.1.com --> the config file $config['base_url'] = 'http://www.1.com/'; WORK OK!
www.2.com --> the config file $config['base_url'] = 'http://www.2.com/'; doesnt WORK !
Someone can help me plz?
I tried something like
$config['base_url'] = "http://".$_SERVER['HTTP_HOST'] . '/www.2.com/'; BUT NOTHING HAPPEN
Jua Velandia
2010-12-02
Does the search engines takes this as duplicated data?, I've bough a new domain for my CI website and i've been reading that one should be really careful with this issue.. thanks!
Sheldon
2011-03-31
Will this setup also work for urls such as
example.in/app1
example.in/app1/admin
example.in/app2
example.in/app2/admin
I guess a little more URL manipulation will be required here
David
2011-04-25
This is a great article, one that I wish I had found ages ago! I assume though that some form of server config would need to be done to get the different domains all pointing at the same codebase? Probably the http.conf file? What if accessing that config were not possible on a shared hosting solution?
Phil Sturgeon
2011-04-26
David: Your server ideally needs to be set ready to send multiple domains to the same directory via the Apache config yes but it's not the only way to make this work. If you cannot change your server config you can CNAME a domain over the top via DNS settings which should be available via your domain provider instead.
Anyway, steps one and two are no longer required as I coded this feature into CodeIgniter 2.0.0. If you leave base_url blank (which it is by default) then CodeIgniter will guess the right URL to work with.
Jatazoulja
2011-09-09
I kept getting
Notice: Constant SITE already defined in ../../ci/application/config/constants.php on line 52
Phil Sturgeon
2011-09-09
That means the SITE is already defined somewhere. Look for it ;-)
Steward
2011-12-23
Just a heads up.
I found $_SERVER['HTTP_HOST'] is not set for CLI (ie cron jobs)
Happily for me I could get the same info from the current path name.
For an approach that covers CLI, compare with Magento.
They use htaccess to put the site code into the server environment.
Andy Platt
2012-03-02
Will the techniques described here still work with CI 2.1?