CakePHP 1.1 and Lighttpd 1.5 Background
In October 2007, software developer Brendon Crawford published “Enabling CakePHP 1.1 on Lighttpd 1.5” at blog.aphexcreations.net/2007/10/enabling-cakephp-11-on-lighttpd-15.html on the Aphex Creations engineering blog.
At the time, CakePHP 1.1 was one of the fastest-growing MVC frameworks for PHP, while Lighttpd (pronounced “lighty”, across stable 1.4.x and the experimental 1.5.0 branch) was the preferred event-driven, low-memory alternative to Apache 2’s prefork worker model on memory-constrained Linux VPS instances.
However, CakePHP 1.1 shipped exclusively with Apache mod_rewrite .htaccess files across three directories (/, /app/, and /app/webroot/). Because Lighttpd does not read Apache .htaccess files and lacked an equivalent to Apache’s RewriteCond %{REQUEST_FILENAME} !-f file-existence check inside url.rewrite-once, developers deploying CakePHP on Lighttpd repeatedly encountered a classic failure cited on the official CakePHP mailing list: “CakePHP - Not serving css or js”.
URL Rewriting: Apache .htaccess vs Lighttpd mod_rewrite
In Apache, CakePHP 1.1 relied on filesystem conditional checks before routing a request to the front controller (app/webroot/index.php?url=$1):
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php?url=$1 [QSA,L]
</IfModule>In Lighttpd 1.4 and 1.5, mod_rewrite evaluates regular expressions purely against the request URI string in memory before touching the filesystem. If a developer wrote a naive catch-all rewrite rule ("^/(.*)$" => "/index.php?url=$1"), Lighttpd rewrote every request for /css/cake.generic.css, /js/prototype.js, and /img/cake.power.gif into CakePHP’s PHP dispatcher—causing CakePHP to look for a nonexistent CssController or JsController and return HTML 404 pages instead of stylesheets and scripts.
Static Asset Handling in Lighttpd 1.4 & 1.5
To solve the “Not serving CSS or JS” issue in CakePHP 1.1 on Lighttpd 1.5, the document root had to be pointed directly at /path/to/cakephp/app/webroot, and url.rewrite-once had to explicitly match and pass through static asset directories (css, files, img, js, stats, and root favicon.ico) before falling back to the CakePHP front controller regex.
You can test and inspect this exact regular expression in our interactive JavaScript Regex Tester using the Lighttpd Static Asset Rule preset.
server.modules += ( "mod_rewrite" )
$HTTP["host"] =~ "^(www\.)?example\.com$" {
# Point document-root directly to CakePHP's app/webroot directory
server.document-root = "/var/www/cakephp/app/webroot"
# First rule passes static asset folders untouched;
# Second rule forwards controller/action paths + query strings to index.php?url=
url.rewrite-once = (
"^/(css|files|img|js|stats)/(.*)$" => "/$1/$2",
"^/favicon\.ico$" => "/favicon.ico",
"^([^?]*)(\?(.*))?$" => "/index.php?url=$1&$3"
)
}For applications that served arbitrary static files from the root of app/webroot, Lighttpd also offered mod_magnet with a lightweight Lua script (magnet.attract-physical-path-to) that checked lighty.stat(lighty.env["physical.path"]) on disk and only rewrote to /index.php?url=... when the physical file did not exist.
Troubleshooting Lighttpd 1.5 & PHP FastCGI
Lighttpd 1.5.0 introduced a major architectural change over Lighttpd 1.4: it replaced mod_fastcgi with the unified mod_proxy_core and mod_proxy_backend_fastcgi modules. When troubleshooting historical Lighttpd 1.5 + CakePHP 1.1 deployments, four configuration details were critical:
server.modules += (
"mod_rewrite",
"mod_proxy_core",
"mod_proxy_backend_fastcgi"
)
$PHYSICAL["existing-path"] =~ "\.php$" {
proxy-core.balancer = "round-robin"
proxy-core.protocol = "fastcgi"
proxy-core.backends = ( "unix:/var/run/php-fastcgi.sock" )
proxy-core.max-pool-size = 4
}cgi.fix_pathinfo = 1inphp.ini: Required so PHP’s FastCGI SAPI populated$_SERVER['SCRIPT_FILENAME']and$_GET['url']accurately after Lighttpd rewrote the request.- Query String Preservation: In
url.rewrite-once, using^([^?]*)(\?(.*))?$ => /index.php?url=$1&$3ensured that pagination and filter query parameters were appended rather than overwritten by?url=$1. app/tmpWrite Permissions: CakePHP 1.1 cached model schemas and session files inapp/tmp/cache/modelsandapp/tmp/cache/persistent; if owned byrootinstead of thelighttpd/www-datauser, CakePHP failed silently or degraded performance on every request.
Compatibility & Security Risks of Legacy Stacks
Both CakePHP 1.1 (released 2006) and the Lighttpd 1.5.0 pre-release branch are historical software artefacts and must not be exposed to untrusted production traffic without isolation:
- Lighttpd 1.5 Branch Retirement: The experimental Lighttpd 1.5 branch was never promoted to a stable release; its improvements were instead merged back into the actively maintained Lighttpd 1.4.x series.
- End-of-Life PHP Runtimes: CakePHP 1.1 targeted PHP 4 and PHP 5.x, which no longer receive security patches and are incompatible with modern PHP 8.3/8.4 type systems.
- Path Info & FastCGI Vulnerabilities: Historically, enabling
cgi.fix_pathinfo = 1without strict.phpfile existence validation allowed attackers to execute arbitrary uploaded files (e.g.,/img/avatar.jpg/index.php) as PHP code.
Modern Migration Recommendations (CakePHP 5 & Nginx)
In modern CakePHP 4 and CakePHP 5, the front controller lives in webroot/index.php and reads the request path directly from $_SERVER['REQUEST_URI'] via PSR-7 ServerRequest objects—eliminating the legacy ?url=$1 query parameter rewrite altogether.
When migrating a legacy CakePHP application to Nginx + PHP-FPM (or modern Lighttpd 1.4.76+ with mod_magnet), use Nginx’s native filesystem-aware try_files directive so static CSS, JavaScript, and media assets are served directly from disk without fragile folder-name regex exclusions:
server {
listen 443 ssl http2;
server_name example.com;
root /var/www/cakephp/webroot;
index index.php;
# Serve static files directly; fallback to CakePHP PSR-7 front controller
location / {
try_files $uri $uri/ /index.php?$args;
}
location ~ \.php$ {
# Mitigate pathinfo execution exploits by verifying script existence
try_files $uri =404;
include fastcgi_params;
fastcgi_pass unix:/run/php/php8.3-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
location ~* \.(?:css|js|mjs|jpg|jpeg|gif|png|ico|svg|webp|avif|woff2)$ {
expires 1y;
add_header Cache-Control "public, immutable";
access_log off;
}
}For more historical developer tutorials and interactive tools preserved by Web Dev Awards, visit the Aphex Creations Historical Archive, explore the AJFORM AJAX Toolkit Reference, or test your server rewrite patterns in our JavaScript Regex Tester.