Server Configuration
This document covers production server expectations for Capell Frontend, static artifact generation, and local cache settings.
Overview
Section titled “Overview”Capell Frontend serves public page requests through Laravel. The package can also generate static HTML artifacts with metadata for deployment pipelines, CDNs, or static export tooling:
php artisan capell:generate-htmlBy default, generated artifacts are written under storage/framework/capell-static-artifacts. Set CAPELL_FRONTEND_STATIC_ARTIFACTS_PATH when a deployment needs those artifacts written to a different writable directory.
This package no longer assumes a public page-cache directory. Do not configure Apache or Nginx to serve one unless another installed package explicitly owns and documents that directory.
The optional capell-app/html-cache package is such a package: it owns public/page-cache and documents the rules that serve it. If you have installed it, add those rules from Serving the static HTML cache. If you have not, there is no page-cache directory to serve and the instruction above stands.
Web Server
Section titled “Web Server”Configure the web server with the normal Laravel public root and fallback behavior:
server { listen 80; server_name example.com; root /var/www/html/public;
index index.php;
# Media uploads pass through this limit before PHP sees them. client_max_body_size 32m;
location / { try_files $uri $uri/ /index.php?$query_string; }
location ~ \.php$ { try_files $uri =404; fastcgi_pass unix:/run/php/php8.4-fpm.sock; fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name; fastcgi_param HTTPS $https if_not_empty; include fastcgi_params; }
location ~ /\.(?!well-known).* { deny all; }}This block listens on port 80 for brevity. Production sites terminate TLS; see Terminate TLS for the 443 block, the port-80 redirect, and certificate renewal.
Two lines above are easy to leave out and expensive to get wrong:
try_files $uri =404;inside the PHP location. Without it, a host withcgi.fix_pathinfo=1can be persuaded to hand a request such as/media/photo.jpg/x.phpto PHP-FPM, executing an uploaded file. Capell accepts media uploads, so treat this line as required rather than defensive.client_max_body_size. nginx defaults to1mand rejects anything larger with a413before PHP runs, so editors see an upload fail with no application error. Set it at least as high as PHP’supload_max_filesizeandpost_max_size, and keep all three in step.
Enable text compression for public HTML and text assets in the same server or proxy layer. Lighthouse’s uses-text-compression audit expects compressed responses for HTML, CSS, JavaScript, SVG, JSON, and XML:
gzip on;gzip_vary on;gzip_min_length 1024;gzip_types text/plain text/css text/xml application/javascript application/json application/xml application/rss+xml image/svg+xml;If Brotli is available in the production proxy, enable it for the same MIME types. Do not audit through an uncompressed local PHP server when comparing Lighthouse scores for Capell frontend pages.
Release-safe Vite assets
Section titled “Release-safe Vite assets”Do not serve /build/assets/* exclusively through a current/public symlink when HTML can be cached beyond a deployment. A cached page from release A can request A’s content-hashed CSS after current points at release B; deleting or hiding A’s build directory then turns a normal zero-downtime switch into a site-wide unstyled response.
The host deployment must:
- attest every regular file under the release’s
public/build/assetsdirectory; - publish those files into shared, append-only storage before switching the live release;
- fail if an existing hashed filename has different bytes;
- serve
/build/assets/from that shared store with immutable cache headers; - atomically publish direct CSS entries under
/build/fallback/{entry}withno-cacheheaders; - verify shared delivery before and after the switch, and republish the rollback candidate’s stable fallback before rollback.
Retain old hashes for at least the longest HTML max-age, surrogate cache, stale-while-revalidate, browser history, and rollback window. A monotonic store with no automatic deletion is the safe initial policy; add garbage collection only when it can prove that no retained release or cache window still references a file.
This contract covers JavaScript chunks, CSS, fonts, and other Vite outputs—not only the stylesheet that first exposed the problem. Edge-cache purging remains useful for fresh HTML, but it is not a substitute for retaining immutable assets.
Static Artifacts
Section titled “Static Artifacts”Generate artifacts for all published page URLs:
php artisan capell:generate-htmlGenerate artifacts for one site or selected URLs:
php artisan capell:generate-html --site=1php artisan capell:generate-html --url=/ --url=/aboutThe generated manifest is written to:
storage/framework/capell-static-artifacts/manifest.jsonEach manifest entry includes the output file path, response headers, dependency fingerprints, runtime fingerprints, asset fingerprints, and generation time. Deployment tooling should read the manifest instead of guessing paths from URLs.
Capell refuses to write a static artifact 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, or package output rather than trying to force artifact generation.
Cache Management
Section titled “Cache Management”After bulk content changes or a database restore, clear Laravel’s runtime caches and regenerate static artifacts:
php artisan optimize:clearphp artisan capell:generate-htmlCapell automatically invalidates model-aware render data and listing caches when content changes are published. The following changes trigger targeted invalidation:
- Publishing a page invalidates that page’s render data.
- Updating a page’s slug invalidates the page, descendants, and listing pages.
- Updating site settings, translations, themes, or media invalidates cached render data that used those records.
- Site setting changes also match URLs by configured domains, so root pages such as the homepage are covered.
- Changes to global navigation invalidate pages that render navigation.
Development Environment
Section titled “Development Environment”To skip frontend cache reads and writes in development, add to your .env:
DEBUG_SKIP_CACHE=trueCAPELL_HTML_CACHE=falseCAPELL_WRITE_HTML_CACHE=falseCAPELL_PUBLIC_RENDER_DATA_CACHE=falseCAPELL_MINIFY_HTML=falseDEBUG_SKIP_CACHE=true bypasses cache reads and writes on every request without disabling the cache system globally. This is the simplest option for local debugging.
Performance Optimisations
Section titled “Performance Optimisations”- Enable HTTP/2 or HTTP/3 on the production server or proxy.
- Enable gzip or Brotli for HTML, CSS, JavaScript, SVG, JSON, and XML.
- Set long-lived cache headers for versioned CSS, JavaScript, images, and fonts.
- Use a CDN in front of Laravel or in front of the generated static artifacts.
- Use OPcache for PHP to speed up the dynamic fallback path.
- Consider a reverse-proxy cache only when it respects Capell’s public safety and authenticated-rendering headers.
Further Reading
Section titled “Further Reading”- Page & Site Loading - how the frontend request pipeline works
- Testing Frontend - public rendering and cache-safety checks
- Presentation Delivery - renderer and layout behavior
- Artisan Commands - command reference