Server Configuration
This document covers web server configuration for serving Capell’s static HTML cache, recommended settings for production, and development environment setup.
Overview
Section titled “Overview”Capell’s frontend generates static HTML files for every published page and stores them in public/page-cache/. For maximum performance, configure your web server to check for and serve these files directly — bypassing PHP entirely. This means TTFB (time to first byte) is determined by disk I/O and your server, not PHP execution time.
If no cached file exists (e.g. for a page that hasn’t been generated yet, or after a cache purge), the request falls through to PHP as normal and Capell generates the page dynamically, then queues a job to save the cached version.
Capell refuses to write a public HTML cache file when the rendered response contains explicit authoring markers, field paths, model IDs, or signed admin editor URLs. Those responses are sent with Cache-Control: private, no-store and X-Frontend-Cache: BYPASS. Treat this as a deployment blocker: fix the Blade/theme/package output rather than trying to force the cache write.
Apache Configuration
Section titled “Apache Configuration”Add these rules to your .htaccess file, before the standard Laravel rewrite rules:
# Serve static HTML cache if the file existsRewriteCond %{DOCUMENT_ROOT}/page-cache%{REQUEST_URI}.html -fRewriteRule ^ page-cache%{REQUEST_URI}.html [L]Full .htaccess example:
<IfModule mod_rewrite.c> RewriteEngine On
# Serve cached HTML if it exists RewriteCond %{DOCUMENT_ROOT}/page-cache%{REQUEST_URI}.html -f RewriteRule ^ page-cache%{REQUEST_URI}.html [L]
# Standard Laravel rewrite RewriteCond %{REQUEST_FILENAME} !-d RewriteCond %{REQUEST_FILENAME} !-f RewriteRule ^ index.php [L]</IfModule>Nginx Configuration
Section titled “Nginx Configuration”Add the static HTML check to your location / block:
location / { try_files $uri $uri/ /page-cache$uri.html /index.php?$query_string;}Full server block example:
server { listen 80; server_name example.com; root /var/www/html/public;
index index.php;
location / { try_files $uri $uri/ /page-cache$uri.html /index.php?$query_string; }
location ~ \.php$ { fastcgi_pass unix:/run/php/php8.3-fpm.sock; fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name; include fastcgi_params; }
location ~ /\.(?!well-known).* { deny all; }}Cache Management
Section titled “Cache Management”Clearing the cache
Section titled “Clearing the cache”After making bulk changes or restoring from a database backup:
# Clear just the HTML page cachephp artisan capell:html-cache:clear
# Clear everything (config, views, routes, page cache)php artisan optimize:clearFrom the admin panel, use the Clear Cache button in the top navigation bar.
Selective cache invalidation
Section titled “Selective cache invalidation”Capell automatically purges cache entries when content changes are published. The following events trigger targeted invalidation:
- Publishing a page purges that page’s cached HTML.
- Updating a page’s slug purges the page, all its descendants, and any listing pages.
- Updating site settings, translations, themes, or media purges cached URLs that used those records.
- Site setting changes also match cached URLs by the site’s configured domains, so root pages such as the homepage are cleared even if the model index missed an explicit
Sitedependency. - Changes to global navigation purge pages that render navigation.
Regenerating the cache
Section titled “Regenerating the cache”After a full clear, regenerate the cache:
# Regenerate all sitesphp artisan capell:static-site
# Regenerate for one sitephp artisan capell:static-site --site=1Lockdown cache swap
Section titled “Lockdown cache swap”Lockdown is designed for incidents where PHP middleware alone is not enough because the web server may serve public/page-cache directly. When Lockdown is enabled, Capell renames the live page cache directory to a preserved sibling, creates a fresh page-cache directory, and writes Lockdown HTML into the same cached paths. When Lockdown is disabled, the temporary Lockdown cache is removed and the preserved live cache is moved back.
Do not clear public/page-cache during Lockdown unless you are deliberately accepting a cold cache rebuild after recovery. See Lockdown for the operator runbook.
Filesystem Disk
Section titled “Filesystem Disk”The page cache uses a dedicated storage disk. Ensure it is configured in config/filesystems.php:
'disks' => [ 'page_cache' => [ 'driver' => 'local', 'root' => public_path('page-cache'), 'throw' => false, ],],The public/page-cache/ directory must be writable by the web server process.
Development Environment
Section titled “Development Environment”To skip caching in development, add to your .env:
DEBUG_SKIP_CACHE=trueCAPELL_HTML_CACHE=falseHTML_MINIFY=falseDEBUG_SKIP_CACHE=true bypasses cache reads and writes on every request without disabling the cache system. This is the simplest and safest option for local development.
Performance Optimisations
Section titled “Performance Optimisations”- Enable HTTP/2 on your server to allow multiplexed requests.
- Set appropriate cache headers for static assets (CSS, JS, images) — these should be long-lived.
- Consider a CDN in front of your server to serve cached HTML from edge locations.
- Use
opcachefor PHP to speed up the dynamic fallback path. - For very high-traffic sites, consider a Varnish or Nginx proxy cache in front of the origin as a second caching layer.
Further Reading
Section titled “Further Reading”- Guide — HTML cache internals, cache invalidation, Tailwind setup
- Installation Guide — queue setup, filesystems disk, logging
- Artisan Commands —
capell:static-site,capell:html-cache:clear - Page & Site Loading — how the frontend request pipeline works