During my recent work with Lighttpd (version 1.4.67), I encountered a particularly stubborn caching behavior where modified static files weren't being served with their updated content despite having new modification timestamps and changed file sizes. The web server would persistently return outdated versions until I renamed files, which clearly indicated an aggressive caching mechanism at play.
Through network analysis and server logs, I confirmed:
- Browser requests were reaching the server (200 OK responses)
- ETag and Last-Modified headers weren't reflecting disk changes
- Content-Length headers showed correct new sizes but served old content
- The issue didn't affect files processed by mod_compress
Here are the most effective approaches to solve this:
Option 1: Disable sendfile Kernel Optimization
Add to your lighttpd.conf:
server.network-backend = "writev"
This prevents Lighttpd from using the Linux sendfile() system call which can cause caching issues.
Option 2: Force Stat Checking
Configure Lighttpd to check files more frequently:
server.stat-cache-engine = "simple"
server.max-stat-cache-size = 128
server.max-worker = 2
Option 3: Add Cache-Control Headers
For specific directories (e.g., /images):
$HTTP["url"] =~ "^/images/" {
setenv.add-response-header = (
"Cache-Control" => "no-cache, must-revalidate",
"Pragma" => "no-cache"
)
}
Create a simple test case:
# Create test file
echo "version1" > /var/www/html/test.txt
# After config changes
curl -I http://localhost/test.txt
# Should show current timestamp
# Modify file
echo "version2" > /var/www/html/test.txt
# Verify
curl http://localhost/test.txt
# Should immediately show "version2"
For Linux systems, you can implement a more robust solution using inotify:
# Install inotify-tools
apt-get install inotify-tools
# Create monitoring script
#!/bin/bash
while inotifywait -r -e modify,attrib,close_write,move,create,delete /var/www/html; do
lighty-enable-mod expire
sleep 1
lighty-disable-mod expire
done
Remember that disabling caching entirely will impact performance. For production systems, consider:
- Implementing versioned filenames (file_v123.jpg)
- Using query strings (?v=timestamp)
- Setting appropriate Cache-Control headers
When deploying Lighttpd as a static file server, many developers encounter unexpected caching behavior where modified files aren't served with updated content. This occurs even when:
- File modification timestamps change
- Content length differs
- Browser cache is cleared
The key indicators of this issue include:
# Typical problematic response headers
HTTP/1.1 200 OK
Content-Type: image/png
Last-Modified: Wed, 01 Jan 2020 00:00:00 GMT # Stale timestamp
Content-Length: 1024 # New file size
Option 1: Disable Kernel-level Caching
Add to lighttpd.conf:
server.stat-cache-engine = "disable"
Option 2: Force ETag Validation
etag.use-mtime = "enable"
etag.use-inode = "enable"
static-file.etags = "enable"
Option 3: Cache Control Headers
For specific directories:
$HTTP["url"] =~ "^/dynamic-content/" {
setenv.add-response-header = (
"Cache-Control" => "no-cache, must-revalidate",
"Pragma" => "no-cache"
)
}
Verify your configuration with:
lighttpd -tt -f /etc/lighttpd/lighttpd.conf
curl -vI http://yourserver/static/file.png | grep -iE 'last-modified|etag'
While disabling caching improves development workflow, consider these production alternatives:
- Implement versioned filenames (file_v123.jpg)
- Use query string versioning (file.jpg?v=123)
- Configure proper Cache-Control max-age headers
For an image gallery that updates frequently:
# lighttpd.conf snippet
$HTTP["url"] =~ "^/gallery/" {
server.stat-cache-engine = "disable"
etag.use-mtime = "enable"
setenv.add-response-header = (
"Cache-Control" => "public, max-age=60"
)
}