⚠️ Need a more specific guide? See https://medium.com/@murdercode/speed-up-your-laravel-application-up-to-1000x-with-fastcgi-cache-0135b11407e5
Using FastCGI cache allows you to speed up your website up to 1000x. In fact, the FastCGI cache (or Varnish) mechanism consists of putting a server-caching mechanism between a client and your web server. The whole page will be cached as an HTML output, and it will be delivered instead of using the PHP/MySQL/Redis stack, etc. for all users, but only for the first visit (and others after some specified time).
WARNING: This is not a take-away how-to. Please read it carefully and use it at your own risk.
This config is based on the ploi.io stack. We will not cover the FastCGI installation process, so please prepare FastCGI and adapt the next config if you need it.
To achieve significant improvements in speed and security, it's important to note that pages will be cached and shared among users. Therefore, it's crucial that sessions and cookies aren't cached, as doing so may result in shared sessions and security complications.
This caching method is cookieless and sessionless, and is ideal for websites without a login mechanism. However, it also -supports Laravel Nova authentication.
The first thing to do is to remove the middlewares that create and store sessions and cookies. You can move those middlewares to another group for reuse by modifying the following method in /app/Http/Kernel.php
:
protected $middlewareGroups = [
'web' => [
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
'cookie' => [
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\VerifyCsrfToken::class,
],
'api' => [
// \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
'throttle:api',
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
];
Please note that VerifyCSRF can pose a security issue if you don't know how to approach it.
As we mentioned earlier, we want to use sessions and cookies in Laravel Nova (although you can choose to use them elsewhere). So, edit /app/Providers/AppServiceProvider.php
as follows:
public function boot()
{
if(request()->hasCookie('YOURAPPNAME_session') || request()->is('cms/*') || request()->is('nova-api/*') || request()->is
('nova-vendor/*')) {
$this->app['router']->pushMiddlewareToGroup('web', \App\Http\Middleware\EncryptCookies::class);
$this->app['router']->pushMiddlewareToGroup('web', \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class);
$this->app['router']->pushMiddlewareToGroup('web', \Illuminate\Session\Middleware\StartSession::class);
$this->app['router']->pushMiddlewareToGroup('web', \Illuminate\View\Middleware\ShareErrorsFromSession::class);
$this->app['router']->pushMiddlewareToGroup('web', \App\Http\Middleware\VerifyCsrfToken::class);
}
Note: in our case we will use cms
as Nova path instead nova
. Change it with yours.
Note that nova-api
can be used from Laravel Nova Tools, so add it as shown.
We need to define some conditions, where FastCGI will be not enabled.
In fastcgi-cache.conf
:
# Create a variable to skip the cache
set $skip_cache 0;
# POST requests and urls with a query string should always go to PHP
if ($request_method = POST) {
set $skip_cache 1;
}
# Don't cache when there is a query string (e.g. ?search=query)
#if ($query_string != "") {
# set $skip_cache 1;
#}
# Don't cache if querystring
if ($query_string ~* "nocache") {
set $skip_cache 1;
}
if ($query_string ~* "query") {
set $skip_cache 1;
}
# Set here your NAME_session, you can take it from HTTP response
if ($http_cookie ~* "YOUR-SESSION-NAME_session") {
set $skip_cache 1;
}
# Don't cache uris containing the following segments
if ($request_uri ~* "/cms/|/telescope/|/horizon/|/nova-api/|/nova-vendor/|/feed|/.*sitemap.*\.(xml|xsl)") {
set $skip_cache 1;
}
Now it's time to ignore some headers for preventing misconfiguration.
In fastcgi-php-cache
, after add_header
add:
fastcgi_cache NAMECACHE;
fastcgi_cache_valid any 5s;
# Allow only 1 request to cache content
fastcgi_cache_lock on;
# Use old cache when it's updating
fastcgi_cache_use_stale updating;
fastcgi_cache_background_update on;
add_header X-FastCGI-Cache $upstream_cache_status;
add_header X-Frame-Options "SAMEORIGIN";
add_header X-XSS-Protection "1; mode=block";
add_header X-Content-Type-Options "nosniff";
#Custom Laravel
fastcgi_cache_key "$request_method $scheme://$host$request_uri";
fastcgi_cache_use_stale error timeout invalid_header http_500;
#fastcgi_pass_header Set-Cookie;
fastcgi_pass_header Cookie;
fastcgi_ignore_headers Set-Cookie Cache-Control Expires Vary;
fastcgi_hide_header Expires;
fastcgi_hide_header Pragma;
fastcgi_hide_header Vary;
fastcgi_cache_bypass $skip_cache;
fastcgi_no_cache $skip_cache;
Note that this config will use a microcaching mechanism. Please update with your values if you need it.