Configuring Expression Engine for multiple servers

I recently mentioned that I’ve been using ExpressionEngine a little bit lately and alluded to the fact that the typical EE workflow involves editing your site on the live server rather than in a proper development environment. There are a few reasons for this and most can be worked around fairly easily. The one remaining problem is that, upon installing EE, it hard-codes your site URL and application installation path all over the place, from config files to options stored in the database. This is what makes Expression Engine so unportable — moving from one server to another, say from development to production, requires updating this URL and path information in literally about a dozen places. It’s clumsy, time-consuming, and error prone.

It’s actually a little ridiculous that this problem even exists. PHP provides two global variables that can be used to get the domain name and filesystem path to a site — $_SERVER['HTTP_HOST'] and $_SERVER['DOCUMENT_ROOT'] respectively — so Expression Engine asks you these things despite the fact that it can find them out for itself. The settings you give it are then used in multiple places, which is exactly what variables are for, to prevent having duplicate information. Look at WordPress for an example of an app that does this right.

In order to make this a bit easier, I’ve done some research and experimentation and come up with an Expression Engine configuration that addresses most of this. It’s not 100% perfect but it’s pretty close. There are still two places where manual configuration is needed but these are typically only done once. All the major stuff is fixed.

There are two files that need to be modified for this method to work, and both are outside the core application so future upgrades will not affect it. These files are path.php in the root directory of your EE-based site and config.php in the “system” directory (this file actually is touched during upgrades but customizations appear to be preserved, at least in my limited testing).

The first file to modify is path.php. Find the $site_url line and replace it with the following:

$site_url = "http://${_SERVER['HTTP_HOST']}/";

Second, you’ll need to add a handful of variables to config.php. This is what mine looks like now, minus the irrelevant stuff like my database configuration. The system_folder and cp_url variables are already in this file, the rest need to be added.

// Paths and URLs
$conf['system_folder'] = "cms";
 
$conf['site_url'] = "http://${_SERVER['HTTP_HOST']}/";
$conf['cp_url']   = "http://${_SERVER['HTTP_HOST']}/${conf['system_folder']}/index.php";
 
$conf['tmpl_file_basepath'] = "${_SERVER['DOCUMENT_ROOT']}/${conf['system_folder']}/templates";
$conf['theme_folder_path']  = "${_SERVER['DOCUMENT_ROOT']}/themes";
$conf['theme_folder_url']   = "http://${_SERVER['HTTP_HOST']}/themes";
 
$conf['captcha_path'] = "${_SERVER['DOCUMENT_ROOT']}/images/captchas";
$conf['captcha_url']  = "http://${_SERVER['HTTP_HOST']}/images/captchas";
 
$conf['avatar_path']  = "${_SERVER['DOCUMENT_ROOT']}/images/members/avatars";
$conf['avatar_url']   = "http://${_SERVER['HTTP_HOST']}/images/members/avatars";
 
$conf['photo_path']   = "${_SERVER['DOCUMENT_ROOT']}/images/members/photos";
$conf['photo_url']    = "http://${_SERVER['HTTP_HOST']}/images/members/photos";

This takes care of most of your portability problems. You can now dump your local database and import it on another server, copy your web site directory over (preferably by checking it out of your version control system), and be up and running, no headaches required.

Almost. That done, there are still two problems remaining. First, when creating new “weblogs” (a content section, in EE parlance), it hard-codes your domain name into all the path settings. Remove this and use just the URL path instead. Thus, http://www.example.com/news/ would become just /news/. This works just fine.

The second problem is trickier: In your file upload preferences you need to specify a filesystem path and URL for upload directories. No default is filled in, so there’s nothing to pre-set in the config file. Leaving the domain name off in the URL field works, but will result in broken images in your RSS feeds. I haven’t yet found a work-around for the filesystem path. Ideally, the filesystem path on your dev and production servers will be the same, which makes this a non-issue, but that isn’t always possible (I was using symlinks to simulate my server’s filesystem layout until I installed Leopard, in which OS X uses /home as an automount point, thus breaking this replication).

If any readers find a work-around for these last two issues, post them here!

Update

Thanks to Matt W. for his suggestion on improving the compatibility of my $conf['cp_url'] line.

Comments

kiliksun says:

thanks so much for writing this article. I always felt this was possible but just wasn’t exactly sure where to look. Great stuff

Kenn Christ says:

Thanks, glad I could help. I spent a long time banging my head against this stuff before realizing that there must be a better way.

If you’re able to add anything to this in your own work, let me know!

Ingmar Greil says:

Very cool. I did some more work on this, on an old 1.5.2 site: Creating a new weblog always used the site_url variable to prefill the weblog path settings, but that behavior might have changed in recent versions, I’ll check that out.

I believe to have a workaround for the image upload filesystem path issue: I always use a relative path, eg “../images/uploads/”, ie relative to the “system” directory.

Also, you have omitted a few config variables that were in my 1.5.2 config.php, not sure if they are important/needed/supported in 1.6.x, but here’s a list:

$conf['cp_image_path']
$conf['member_images']
$conf['emoticon_path']
$conf['calendar_thumb_path']
$conf['sig_img_url']
$conf['sig_img_path']
$conf['prv_msg_upload_path']
$conf['tag_module_js_directory']
Cocoaholic says:

Great article!

I have taken this a bit further and moved all variables to a file named “config.inc.php” which I include in my “config.php”.

I set the permissons of “config.php” to 644 so it won’t be overwritten… but even if it is, I only need to replace the contents with one line:

require 'config.inc.php';

It also contains a list of (known) hidden variables.

I haven’t added Ingmar’s variables (yet), but feel free to download the file here:
http://elwinzuiderveld.nl/downloads/config_inc.zip

Adrian Westlake says:

In my case I had the expression engine folder in a subfolder from the root of my server, so I amended the above for this to work in my case:

$conf['rel_path'] = "projects/expressionengine";
 
// paths
$conf['site_url'] = "http://${_SERVER['HTTP_HOST']}/${conf['rel_path']}/";
$conf['cp_url']   = "${conf['site_url']}/${conf['system_folder']}/";
 
// template files
$conf['tmpl_file_basepath'] = "${_SERVER['DOCUMENT_ROOT']}/${conf['rel_path']}/${conf['system_folder']}/template_files";
 
// themes
$conf['theme_folder_path'] = "${_SERVER['DOCUMENT_ROOT']}/${conf['rel_path']}/themes";
$conf['theme_folder_url']  = "${conf['site_url']}/themes";
 
// capchas
$conf['captcha_path'] = "${_SERVER['DOCUMENT_ROOT']}/${conf['rel_path']}/images/captchas";
$conf['captcha_url']  = "${conf['site_url']}/images/captchas";
 
// avatars
$conf['avatar_path'] = "${_SERVER['DOCUMENT_ROOT']}/${conf['rel_path']}/images/members/avatars";
$conf['avatar_url']  = "${conf['site_url']}/images/members/avatars";
 
// photos
$conf['photo_path'] = "${_SERVER['DOCUMENT_ROOT']}/${conf['rel_path']}/images/members/photos";
$conf['photo_url']  = "${conf['site_url']}/images/members/photos";

Oh my goodness, thank you so much for sharing this knowledge! I am working on my first EE site, and was astounded when I realised I had to manually edit dozens of paths scattered throughout the CMS after moving from a dev to live environment.

IMO this is incredibly archaic. All of these paths should be centralised in the config file, as would be the case in any other CMS.

I commend you for taking the initiative and doing it yourself!

@Ingmar – I don’t know about all the config paths you mentioned, but certainly the emoticons doesn’t need changing. Kenn’s config variables seem to magically fix the emoticons path too :)

And thanks for the awesome tip about setting a relative path for the file uploads. Seems to work a treat.

Brilliant. Just what I’ve been looking for.

[...] Configuring Expression Engine for multiple servers The one remaining problem is that, upon installing EE, it hard-codes your site URL and application installation path all over the place, from config files to options stored in the database. This is what makes Expression Engine so unportable — moving from one server to another, say from development to production, requires updating this URL and path information in literally about a dozen places. [...]

Martin Smith says:

Thanks for this…

In the paragraph starting …. “Almost. That done, there are still two problems remaining……………etc”, where do I remove the domain name from the path settings?

Cheers

Kenn says:

Martin: You remove this in the weblog settings for each weblog you create. In the Admin app, go to Weblog Administration and edit the preferences for each, removing the domain and leaving only the URL path.

Travis says:

I took a different approach to this and came up with a tool that helps you migrate by changing paths easily:

http://www.hopstudios.com/software/deeploy_helper/

I hope it helps.

TTFN
Travis

Brian Mulloy says:

thanks for writing this up. it’s a big help.

a few months ago i found a fix for the /home as an automount point issue on mac leopard and it’s been working fine for me.

here are the steps:

1. edit the file: /etc/auto_master
2. comment out this line with a #: # /home auto_home -nobrowse
3. save & reboot

a few more details here .