Production style on a shared host
28 Mar 2007
Most websites written in cake will inevitably end up installed on a shared host. Shared hosts are a great compromise between freedom and cost but one of the things that you typically can't do is change the DocumentRoot (the physical directory on the server that corresponds to the url /). The manual explains how to change between a development (extract your cake files and go) style and a production style (nothing except files that should be directly accessible from the web are in the DocumentRoot) install but how you can apply this to a shared host may not be obvious; and this is what I'll try to explain here.
Why bother
It's unlikely to be a problem to use a development style install on a live site - but I stress the unlikely. That said it does mean that some files that should never ever be directly accessible can be accessed via a url. For any php file this is not a problem, you can't see the file only the output from it which means for example if you tried the url /app/config/database.php would just show at most a blank page. However, depending on the server settings this could mean that some potentially sensitive files (anything in the tmp folder) can be web-accessible effectively to anyone. So before you start logging "Bob logged in", "Bob changed his password to x" make absolutely sure that a curious user can't simply access your debug log and then log in as Bob and change all the prices for your products :) (a preemptive reply: no. I just have an active imagination).
The standard development install
So to start at the beginning, once upon a time.. no wait - wrong beginning :D. Ahem: Consider a new clean site on a shared host; where the DocumentRoot is on the server is 100% unimportant, as only relative paths will be used in this post (as I would recommend for reality as well), however it will be assumed that the server has a top level folder named DocumentRoot for simplicity.
A development install would therefore look something like this:
-
DocumentRoot-
app-
webroot (1)-
.htaccess (2) -
index.php (3)
-
-
.htaccess -
index.php
-
-
.htaccess -
index.php
-
The 'important' folder, index and .htaccess file has been marked. If you own the server, you could just change the DocumentRoot to point to the webroot folder, but if you don't have that option...
Production file locations
The goal here is to maintain a easy means of upgrading your cake app, and make only the files in or under the webroot folder directly accessible from the web. The truth is it's not very difficult to do :).
First, it is necessary to move some files around, create a folder to hold your files outside the DocumentRoot. Where it is, and what it is called is again, 100% unimportant.
In the example below I have created a folder named 'website_files' to house everything, and moved everything that was previously in the DocumentRoot into it. The second and last step is to copy the contents of the webroot folder back into the DocumentRoot so that there is a tiny cake presence to receive and process those url requests.
-
DocumentRoot (1)-
.htaccess (2) -
index.php (3)
-
-
website_files-
app-
views
-
-
vendors
-
Editing the index file
As might be obvious from the last dir layout, the index and .htaccess files that are no longer web accessible can be deleted. This leaves only the index (2) and .htaccess (3) file that were previously residing in the weboot folder. If you only move files and folders around, you will be unsurprised to discover that cake will not be able to find various files and it doesn't work; however with a single change to your index.php file to tell cake where your ROOT is - you're good to go again. Below is an example index file, with the definition for the ROOT constant modified. It is worth noting that a relative path has been used to define the root, which is good practice to make the files location independent - quite useful if your development machine file locations don't match your server, or runs a different operating system.
{
<?php
/* SVN FILE: $Id: index.php 29 2007-02-08 21:53:21Z Andy $ */
/**
* Short description for file.
*
* Long description for file
*
* PHP versions 4 and 5
*
* CakePHP : Rapid Development Framework <http://www.cakephp.org/>
* Copyright (c) 2006, Cake Software Foundation, Inc.
* 1785 E. Sahara Avenue, Suite 490-204
* Las Vegas, Nevada 89104
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @filesource
* @copyright Copyright (c) 2006, Cake Software Foundation, Inc.
* @link http://www.cakefoundation.org/projects/info/cakephp CakePHP Project
* @package cake
* @subpackage cake.app.webroot
* @since CakePHP v 0.2.9
* @version $Revision: 29 $
* @modifiedby $LastChangedBy$
* @lastmodified $Date: 2007-02-08 22:53:21 +0100 (jue, 08 feb 2007) $
* @license http://www.opensource.org/licenses/mit-license.php The MIT License
*/
/**
* Do not change
*/
if (!defined('DS')) {
define('DS', DIRECTORY_SEPARATOR);
}
/**
* These defines should only be edited if you have cake installed in
* a directory layout other than the way it is distributed.
* Each define has a commented line of code that explains what you would change.
*
*/
if (!defined('ROOT')) {
//define('ROOT', 'FULL PATH TO DIRECTORY WHERE APP DIRECTORY IS LOCATED DO NOT ADD A TRAILING DIRECTORY SEPARATOR';
//You should also use the DS define to seperate your directories
//define('ROOT', dirname(dirname(dirname(__FILE__))));
define('ROOT', dirname(dirname(__FILE__)) . DS . "website_files");
}
if (!defined('APP_DIR')) {
//define('APP_DIR', 'DIRECTORY NAME OF APPLICATION';
define('APP_DIR', 'app');
}
/**
* This only needs to be changed if the cake installed libs are located
* outside of the distributed directory structure.
*/
if (!defined('CAKE_CORE_INCLUDE_PATH')) {
//define ('CAKE_CORE_INCLUDE_PATH', FULL PATH TO DIRECTORY WHERE CAKE CORE IS INSTALLED DO NOT ADD A TRAILING DIRECTORY SEPARATOR';
//You should also use the DS define to seperate your directories
define('CAKE_CORE_INCLUDE_PATH', ROOT);
}
///////////////////////////////
//DO NOT EDIT BELOW THIS LINE//
///////////////////////////////
if (!defined('WEBROOT_DIR')) {
define('WEBROOT_DIR', basename(dirname(__FILE__)));
}
if (!defined('WWW_ROOT')) {
define('WWW_ROOT', dirname(__FILE__) . DS);
}
if (!defined('CORE_PATH')) {
if (function_exists('ini_set')) {
ini_set('include_path', ini_get('include_path') . PATH_SEPARATOR . CAKE_CORE_INCLUDE_PATH . PATH_SEPARATOR . ROOT . DS . APP_DIR . DS);
define('APP_PATH', null);
define('CORE_PATH', null);
} else {
define('APP_PATH', ROOT . DS . APP_DIR . DS);
define('CORE_PATH', CAKE_CORE_INCLUDE_PATH . DS);
}
}
require CORE_PATH . 'cake' . DS . 'bootstrap.php';
if (isset ($_GET['url']) && $_GET['url'] === 'favicon.ico') {} else {
$Dispatcher=new Dispatcher();
$Dispatcher->dispatch($url);
}
echo "<!-- " . round(getMicrotime() - $TIME_START, 4) . "s -->";
?>
<?php/* SVN FILE: $Id: index.php 29 2007-02-08 21:53:21Z Andy $ *//*** Short description for file.** Long description for file** PHP versions 4 and 5** CakePHP : Rapid Development Framework <http://www.cakephp.org/>* Copyright (c) 2006, Cake Software Foundation, Inc.* 1785 E. Sahara Avenue, Suite 490-204* Las Vegas, Nevada 89104** Licensed under The MIT License* Redistributions of files must retain the above copyright notice.** @filesource* @copyright Copyright (c) 2006, Cake Software Foundation, Inc.* @link http://www.cakefoundation.org/projects/info/cakephp CakePHP Project* @package cake* @subpackage cake.app.webroot* @since CakePHP v 0.2.9* @version $Revision: 29 $* @modifiedby $LastChangedBy$* @lastmodified $Date: 2007-02-08 22:53:21 +0100 (jue, 08 feb 2007) $* @license http://www.opensource.org/licenses/mit-license.php The MIT License*//*** Do not change*/if (!defined('DS')) {define('DS', DIRECTORY_SEPARATOR);}/*** These defines should only be edited if you have cake installed in* a directory layout other than the way it is distributed.* Each define has a commented line of code that explains what you would change.**/if (!defined('ROOT')) {//define('ROOT', 'FULL PATH TO DIRECTORY WHERE APP DIRECTORY IS LOCATED DO NOT ADD A TRAILING DIRECTORY SEPARATOR';//You should also use the DS define to seperate your directories//define('ROOT', dirname(dirname(dirname(__FILE__))));define('ROOT', dirname(dirname(__FILE__)) . DS . "website_files");}if (!defined('APP_DIR')) {//define('APP_DIR', 'DIRECTORY NAME OF APPLICATION';define('APP_DIR', 'app');}/*** This only needs to be changed if the cake installed libs are located* outside of the distributed directory structure.*/if (!defined('CAKE_CORE_INCLUDE_PATH')) {//define ('CAKE_CORE_INCLUDE_PATH', FULL PATH TO DIRECTORY WHERE CAKE CORE IS INSTALLED DO NOT ADD A TRAILING DIRECTORY SEPARATOR';//You should also use the DS define to seperate your directoriesdefine('CAKE_CORE_INCLUDE_PATH', ROOT);}/////////////////////////////////DO NOT EDIT BELOW THIS LINE/////////////////////////////////if (!defined('WEBROOT_DIR')) {define('WEBROOT_DIR', basename(dirname(__FILE__)));}if (!defined('WWW_ROOT')) {define('WWW_ROOT', dirname(__FILE__) . DS);}if (!defined('CORE_PATH')) {if (function_exists('ini_set')) {ini_set('include_path', ini_get('include_path') . PATH_SEPARATOR . CAKE_CORE_INCLUDE_PATH . PATH_SEPARATOR . ROOT . DS . APP_DIR . DS);define('APP_PATH', null);define('CORE_PATH', null);} else {define('APP_PATH', ROOT . DS . APP_DIR . DS);define('CORE_PATH', CAKE_CORE_INCLUDE_PATH . DS);}}require CORE_PATH . 'cake' . DS . 'bootstrap.php';if (isset ($_GET['url']) && $_GET['url'] === 'favicon.ico') {} else {$Dispatcher=new Dispatcher();$Dispatcher->dispatch($url);}echo "<!-- " . round(getMicrotime() - $TIME_START, 4) . "s -->";?>
Wrapping up
By moving some folders around, it is possible to make a shared-hosted website more secure without introducing any complexity. Even if you have the option to change your DocumentRoot it may be desirable for one reason or another to modify the cake folder structure. A clear separation is made between the files that can be directly accessed, and those that can only be accessed via cake. If you can think of an improvement to this approach (although how something so simple can be improved I don't know :D), or do something slightly different, I'd be interested to know.
Bake on!
Daniel Hofstetter, on 28/3/07
Hm, it seems your trees run a bit amok under FF2 ;-) The respective areas are full of expand/unexpand images...
Andy, on 28/3/07
Hi Daniel, so often you are the first to comment ;).
I use the same css for this as the tree demo which I updated last night. At a guess you just need to refresh the page to update the (browser) cached css file.
Daniel Hofstetter, on 28/3/07
Ah, that did the trick.
othman ouahbi aka CraZyLeGs, on 1/4/07
you can also change CAKE_CORE_INCLUDE_PATH to be different than root in case you have multiple applications running on the server ( shared account ). That's also a good thing if they require different cake versions.
website_files/cakes/1.1/core
website_files/cakes/1.2/core
website_files/apps/website
website_files/apps/demoX
website_files/apps/demoZ
website_files/apps/clientpanel
of course APP_DIR has to be changed for each application
Andy, on 2/4/07
Hi Othman.
It was things such as that I was considering in the article when writing "one reason or another".
On a related note, with a few sites on the same machine in parallel, I changed the defenition of the constant 'APP' to be the name of the containing folder (for localhost development) or the domain (when deployed).
So many ways to simplify life with just a little thought. Thanks for the comment :)
overeat, on 11/11/07
Andy, on 13/11/07
Hi Overeat,
The way things are described here are designed for when you only have a cake app on your domain (or more correctly, the root of your domain is your cake app). If you want to have an existing php/html/whatever application run in your document root, the best thing to do would be to run cake from a sub folder (everything is the same, just change the paths to point to the right place in the cake index.php).
That said, if what you want is that your old index and old application is accessible in the document root AND cake handles any urls that don't map to real files (which is effectively what you are asking, I hope it /is/ what you mean & want) you would just need to change your .htaccess file to add a rule just for / to go to oldindex.php. Any urls your old app generates that point to real files will work; any urls that don't will be processed by cake.
hth
Corey, on 9/2/08
I've setup my server as your tutorial stated, but the pages are not appearing. I am completely new to the cake framework. I was working on a basic login system where I created a user.php under the model directory, a views/users/register.thtml under the views directory. I typed in mydomainname.com/users/register and the page did not display. I'm sure I'm doing something very wrong and your assistance is greatly appreciated.
Thorpe Obazee, on 13/3/09
This is what I've been looking for for a long time. I've successfully set up Cake now.
By the way, .htaccess would be enough to keep them away from 'app' and 'cake', right?