Production installation of CakePHP without Apache

This tutorial will try to describe how to accomplish internal url redirections (knowns as url rewriting) by webserver other then apache. If You’re using so-called operating system which has to be turned off by click to button ‘Start’, You’re probably at wrong page.

I have nothing against apache webserver, I just think it loses it’s beauty somewhere on it’s way. One of my favours “wise saw’s” says (basically): less features tool have, better make it’s purpose. You know, if I try to imagine I will have to teach apache configuration someone or remotely help with configuration in not-known environment, I’m tired just in this moment. I don’t know how You guys, but when I have to configure apache from scratch, it allways takes a long time I have to spend with study of documentation or comments (I don’t like those easy-to-install apache+php+mysql packages as I could not peacefully sleep until I know how works things I’m using).

What forced me to find non-apache solution?

I was looking for some poor testing machine for CakePHP applications and only one which I can count on was my home firewall (Pentium 150MHz/ 96MB RAM), where I already had running Cherokee webserver with php 4.4.2 as CGI on LAN interface (I’m not afraid at all, as I’m pretty sure about my ipf, ipfw and nat rules). Don’t laugh on this hardware - I like simple tools and I just want to see performance of my applications on my eyes. Unfortunately I’m running bunch of services for local network on this computer already so I simply cannot run Apache + MySQL there (for those who knows: xntpd, tftpd, dropbear, dnsmasq, snmpd, pserver, tor, privoxy, every 5 minutes runs some perl scripts by mrtg...) and as I want clean URLs, I sucessfully configured redirections of Cherokee webserver. CakePHP works as I expected - there is nothing more to say about it. Just one day after it my friend asked me (I’m only one IT who he knows) how works remote calendars in Mozilla Sunbird, if there is some webinterface to them and if it is possible manage some synchronization between multiple copies on different computers of one calendar etc. He was fully satisfied with my answer, but I realized I had no personal experience with WebDAV yet so I decided change this fact :) Unfortunately Cherokee doesn’t offer WebDAV functionality, so I gave a chance to webserver LightTPD, which fully covers my current needs for this task. Where I was looking for new webserver? HERE ;-) If I will need SQL database (everything is a file) for my CakePHP applications there, I will try locally SQLite or remotely MySQL running on my workstation.

What You can learn here?

  1. how looks sample directory structure and necessary configuration changes for CakePHP production install
  2. how to configure Cherokee webserver for CakePHP friendly internal redirections
  3. how to configure LightTPD webserver for same thing
  4. how to accomplish some other nice additional features with lighttpd

This tutorial will be accomplished at FreeBSD 5.4 with PHP 4.4.2, Cherokee 0.5.3 and LightTPD 1.4.11. It will not cover installation of anything from it, as those products has their’s own documentation - I will assume You have (PHP && (Cherokee || LightTPD)) installed and functional somewhere and both webservers are configured for run under user account ‘www’. This tutorial will not answer any security questions, as this example will offer virtual hosts running under common account - it is on You how You want to solve this in case You will use this tutorial in dangerous environment. There are couple ways - jail (in FreeBSD), chroot, safe mode in PHP, especially for LightTPD this tutorial etc. I want to say: do what You want with this tutorial, but if You don’t know dependencies of Your actions then I’m definitely not right person for Your complains.

What, why and where: directory structure

mkdir /usr/local/lib/cake

and put CakePHP distributon (directories ‘app’, ‘cake’, ‘vendors’ and file VERSION.txt) into it. Files ‘index.php’ and ‘.htaccess’ aren’t needed, but they can’t bite You. You will not have to install CakePHP on some other place - in directory for every host will be copy of ‘app’ dir only. It means: ONE PLACE FOR CORE LIBRARIES ONLY, no symlinks, update/synchronization scripts etc. Sweet cake, huh?

mkdir -p /usr/local/lib/cake_local/models
mkdir /usr/local/lib/cake_local/views
mkdir /usr/local/lib/cake_local/controllers
mkdir /usr/local/lib/cake_local/components
mkdir /usr/local/lib/cake_local/helpers

Those directories are supposed for models, views, controllers, components and helpers, which are mentioned to be shareable across Your vhosts/applications.

mkdir -p /usr/local/www/servers
chown www:www /usr/local/www/servers

This will be parent directory for all virtual hosts.

mkdir /usr/local/www/servers/www.example.com
cp -R /usr/local/lib/cake/app /usr/local/www/servers/www.example.com/

Domain www.example.com is our first virtual host we will play with. Files ‘app/index.php’, ‘app/.htaccess’ and ‘app/webroot/.htaccess’ aren’t needed anymore.

Changes in app configuration:

<?php
// file /usr/local/www/servers/www.example.com/app/config/bootstrap.php
$modelPaths = array('/usr/local/lib/cake_local/models/');
$viewPaths = array('/usr/local/lib/cake_local/views/');
$controllerPaths = array('/usr/local/lib/cake_local/controllers/');
$componentPaths = array('/usr/local/lib/cake_local/components/');
$helperPaths = array('/usr/local/lib/cake_local/helpers/');
?>

Example of benefits of this configuration change: You have done some views and You don’t want to copy those files to host’s ‘app/views’ directories again and again - so You will put Your ‘shared’ views in proper subdirectory of ‘/usr/local/lib/cake_local/views’ and they will be transparently available for Your applications. Note: You don’t have to make this change in bootstrap.php file, if application of Your vhost will not use those common model/view/controller/component/helper files.

<?php
// file /usr/local/www/servers/www.example.com/app/webroot/index.php
...
define('CAKE_CORE_INCLUDE_PATH', '/usr/local/lib/cake'); 
...
?>

Find definition of constant CAKE_CORE_INCLUDE_PATH in this file (line 66 in rev. 2918) and change it as above. I hope You know what this change causes ;-) As You can plain see in this file, You can play with directory structure more agresively, but question is if it is usable/valuable in our case.

Cherokee configuration

Configuration file for our first virtual host:

# file /usr/local/etc/cherokee/sites-available/www.example.com
Server example.com, www.example.com {
    DirectoryIndex index.php
    DocumentRoot /usr/local/www/servers/www.example.com/app/webroot
    Extension php {
        Handler phpcgi {
            Interpreter /usr/local/bin/php-cgi
        }
    }
    Log combined {
        AccessLog /var/log/cherokee.www.example.com.access
        ErrorLog  /var/log/cherokee.www.example.com.error
    }
    Directory /icons {
        Handler file
        DocumentRoot /usr/local/share/cherokee/icons/
    }

# our configuration
    Directory /css {
        Handler common
    }
    Directory /files {
        Handler common
    }
    Directory /img {
        Handler common
    }
    Directory /js {
        Handler common
    }
    Directory / {
         Handler redir {
            Rewrite "/favicon.ico$" "/favicon.ico"
            Rewrite "/css.php$" "/css.php"
            Rewrite "/(.*)$" "/index.php?url=$1"
        }
    }
}

Our ‘rewrite configuration’:

  • ensures directories ‘css’, ‘files’, ‘img’ and ‘js’ aren’t translated (if You want to put into webroot some directory You want to visit with browser, You have to create record for it here)
  • ensures files ‘favicon.ico’ and ‘css.php’ aren’t translated
  • internally rewrites URL so it is CakePHP friendly

As You can plain see, it is configured with PHP as CGI module, as I configured FastCGI in LightTPD only. To be honest, I tried to configure Cherokee with FastCGI PHP on this machine, but without success - few weeks ago was some changes in PHP (the old PHP slave ports phpN-cli, phpN-cgi and mod_phpN were removed in favour of unified PHP ports that allow building any combination of PHP SAPIs - cli, cgi and apache module, the PHP CGI binary was renamed to php-cgi...) and it looks to me Cherokee source code doesn’t reflect those changes yet (but it hasn’t to be true, maybe I’m stupid here).

Then we can turn this host on by

ln -s /usr/local/etc/cherokee/sites-available/www.example.com /usr/local/etc/cherokee/sites-enabled/www.example.com

then start/restart cherokee, ensure Your DNS is capable properly resolve domain www.example.com and try open Your vhost in browser. Everything should works fine, but You can off course customize Your configuration much more, just read Cherokee documentation.

LightTPD configuration

mkdir /usr/local/www/servers/www.example.com/webdav

We will turn on LightTPD WebDAV on this vhost, so we have to make directory for it. We will not use this feature for source codes of our application, just for calendar files - so it is outside of webroot directory (files aren’t accesible by browser), app files aren’t linked inside of this directory etc. But: You will have access to files in this directory by some webdav client, or You can find some (or write Your own) web application for parsing calendars etc.

mkdir -p /tmp/lighttpd/cache/compress/default
mkdir /tmp/lighttpd/cache/compress/www.example.com
chown -R www:www /tmp/lighttpd

We wil turn on LightTPD output compression on this vhost, so we need prepared directory for cache of this host.

Configuration file:

# file /usr/local/etc/lighttpd.conf

server.modules = (
    "mod_alias",
    "mod_rewrite",
    "mod_access",
    "mod_fastcgi",
    "mod_simple_vhost",
    "mod_compress",
    "mod_webdav",
    "mod_accesslog"
)

server.document-root = "/usr/local/www/data/"

server.errorlog = "/var/log/lighttpd.error.log"

index-file.names = ( "index.php", "index.html", "index.htm" )

server.event-handler = "freebsd-kqueue" # needed on OS X

mimetype.assign             = (
  ".pdf"          =>      "application/pdf",
  ".sig"          =>      "application/pgp-signature",
  ".spl"          =>      "application/futuresplash",
  ".class"        =>      "application/octet-stream",
  ".ps"           =>      "application/postscript",
  ".torrent"      =>      "application/x-bittorrent",
  ".dvi"          =>      "application/x-dvi",
  ".gz"           =>      "application/x-gzip",
  ".pac"          =>      "application/x-ns-proxy-autoconfig",
  ".swf"          =>      "application/x-shockwave-flash",
  ".tar.gz"       =>      "application/x-tgz",
  ".tgz"          =>      "application/x-tgz",
  ".tar"          =>      "application/x-tar",
  ".zip"          =>      "application/zip",
  ".mp3"          =>      "audio/mpeg",
  ".m3u"          =>      "audio/x-mpegurl",
  ".wma"          =>      "audio/x-ms-wma",
  ".wax"          =>      "audio/x-ms-wax",
  ".ogg"          =>      "application/ogg",
  ".wav"          =>      "audio/x-wav",
  ".gif"          =>      "image/gif",
  ".jpg"          =>      "image/jpeg",
  ".jpeg"         =>      "image/jpeg",
  ".png"          =>      "image/png",
  ".xbm"          =>      "image/x-xbitmap",
  ".xpm"          =>      "image/x-xpixmap",
  ".xwd"          =>      "image/x-xwindowdump",
  ".css"          =>      "text/css",
  ".html"         =>      "text/html",
  ".htm"          =>      "text/html",
  ".js"           =>      "text/javascript",
  ".asc"          =>      "text/plain",
  ".c"            =>      "text/plain",
  ".cpp"          =>      "text/plain",
  ".log"          =>      "text/plain",
  ".conf"         =>      "text/plain",
  ".text"         =>      "text/plain",
  ".txt"          =>      "text/plain",
  ".dtd"          =>      "text/xml",
  ".xml"          =>      "text/xml",
  ".mpeg"         =>      "video/mpeg",
  ".mpg"          =>      "video/mpeg",
  ".mov"          =>      "video/quicktime",
  ".qt"           =>      "video/quicktime",
  ".avi"          =>      "video/x-msvideo",
  ".asf"          =>      "video/x-ms-asf",
  ".asx"          =>      "video/x-ms-asf",
  ".wmv"          =>      "video/x-ms-wmv",
  ".bz2"          =>      "application/x-bzip",
  ".tbz"          =>      "application/x-bzip-compressed-tar",
  ".tar.bz2"      =>      "application/x-bzip-compressed-tar"
)

accesslog.filename          = "/var/log/lighttpd.access.log"

url.access-deny             = ( "~", ".inc" )

$HTTP["url"] =~ "\.pdf$" {
  server.range-requests = "disable"
}

server.bind                = "192.168.0.1"

server.pid-file            = "/var/run/lighttpd.pid"

server.username            = "www"
server.groupname           = "www"

fastcgi.server             = ( ".php" => ((
                                "socket" => "/tmp/php-fastcgi.socket",
                                "bin-path" => "/usr/local/bin/php-cgi",
                                "bin-environment" => (
                                        "PHP_FCGI_CHILDREN" => "1",
                                        "PHP_FCGI_MAX_REQUESTS" => "100"
                                ),
                                "bin-copy-environment" => (
                                        "PATH", "SHELL", "USER"
                                ),
                                "broken-scriptfilename" => "enable",
                                "max-procs" => 1,
                                "idle-timeout" => 20
                            )))

simple-vhost.server-root   = "/usr/local/www/servers/"
simple-vhost.default-host  = "www.example.com"
simple-vhost.document-root = "/app/webroot/"

compress.filetype          = ("text/plain", "text/html", "text/javascript", "text/css")
compress.cache-dir         = "/tmp/lighttpd/cache/compress/default/"

url.rewrite-once = (
    "/(.*)\.(.*)" => "$0",
    "/(css|files|img|js|stats)/" => "$0",
    "^/([^.]+)$" => "/index.php?url=$1"
)

$HTTP["host"] == "www.example.com" {
    server.errorlog = "/var/log/lighttpd.www.example.com.error.log"
    accesslog.filename = "/var/log/lighttpd.www.example.com.access.log"
    $HTTP["url"] =~ "^/webdav($|/)" {
        alias.url = ( "/webdav/" => "/usr/local/www/servers/www.example.com/webdav/" )
        webdav.activate = "enable"
    }
    compress.cache-dir         = "/tmp/lighttpd/cache/compress/www.example.com/"
}

This is my whole LightTPD configuration file, which just perfectly cover my needs. If You will use it at more powerful computer, You will surely adjust many things - first one will be fcgi (as I have it configured for minimalistic device). We will walk through it now (I will step over self-explanatory items):

  • server.modules - less modules is more - You will save memory, adjust performance etc
  • fastcgi.server - take a look to examples in documentation here
  • simple-vhost.* - configuration of simple virtual hosts (there are 2 others modules for such a thing - enhanced virtual hosting and MySQL virtual hosting)
  • compress.* - options for output compression
  • url.rewrite-once - rewrite options - first line manages ‘not-translate’ files in webroot, second line manages ‘not-translate’ directories in webroot (You will have to customize this if You will put some accessible dir into webroot - in this case will be better put this rule into proper host section.
  • last section just customizes default values for our vhost - some path changes and activation of webdav.

So, start/restart Your LightTPD webserver - it should work well. Adress for webdav is www.example.com/webdav/ - it has to run under authorization, so if You will expose such a service in internet, I hope You will protect it some way. Output compression is not necessary, but I’m sometime using large javascript files (in case of JS GUI toolkit) and if I send proper (compressed/uncompressed in dependency of browser) JS file by php, I am not sure which rules drives caching, You know ;-) And I’m pretty sure webserver is able to send file faster and with less resources consumed then PHP.

Post Scriptum

First of all: many thanks to developers of all mentioned software projects.

Messages for any visitor of this page:

  • If You know how to manage url redirections on another webserver, let us now here, please.
  • If You think Your English is better then mine, You’re 100% right and feel free to any reasonable changes. Thank You.
  • You’re more then welcome if You have something to say to this tutorial, as every Your experience could save some other people’s time

Last note: many thanks to developers of all mentioned software projects :)

 
tutorials/url_rewrite_without_apache.txt · Last modified: 2006/06/20 06:39 by truster