terminal42 / contao-litespeed-cache
This package integrates the LiteSpeed WebServer HTTP Cache with the Contao Open Source CMS
Installs: 0
Dependents: 0
Suggesters: 0
Security: 0
Stars: 5
Watchers: 3
Forks: 0
Open Issues: 0
Type:contao-bundle
pkg:composer/terminal42/contao-litespeed-cache
Requires
- php: ^8.1
- contao/core-bundle: ^5.3
Requires (Dev)
- contao/manager-plugin: ^2.0
- contao/test-case: ^5.0
- phpunit/phpunit: ^9.6
- terminal42/contao-build-tools: dev-main
This package is auto-updated.
Last update: 2025-09-30 12:54:44 UTC
README
Caution
Work in progress
This bundle integrates LiteSpeed Cache with your Contao setup and thus provides even faster HTTP caching than Contao already provides out of the box.
Abstract
The Contao Open Source CMS is already highly optimized for HTTP caching and fully adheres
to the standards. Out of the box, it ships with a caching proxy written in PHP built on top of Symfony's HttpCache.
In other words: Contao can already cache and serve cached responses pretty fast without installing and
configuring any caching proxy at all. More than just that, actually! Thanks to the integration of the
FOSHttpCacheBundle it provides support for cache tagging
and cache tag invalidation. For example, Contao automatically tags the generated HTTP responses with IDs of all
sorts of things you placed on that page: content elements, articles, forms, news, page structure info etc. As soon
as you edit any of the affected elements in the backend, Contao will automatically inform the caching proxy about
which cache tags should be invalidated and thus, the respective cached responses are removed from the cache and your
visitors will get your updated content on the next visit!
As already mentioned, all of this is built on top of Symfony's HttpCache (and a lot of other components) written
in PHP. Now, PHP can be operated with an array of different so-called SAPIs (server APIs). The most popular amongst
them probably being php-fpm. If you operate PHP using php-fpm, you need a webserver (Apache, Nginx, Caddy etc.)
that converts the HTTP request to CGI then passes the data to php-fpm and back. So you have two processes involved
which makes things slower. In case of LiteSpeed, though, it uses its own litespeed SAPI eliminating the need for a
separate process. Serving the HTTP response and running PHP happens in the same process. There are other projects
with similar approaches, such as frankenphp, swoole and others.
Long story short: LiteSpeed by nature should already be faster than your regular php-fpm setup. In fact, it
is a lot faster.
However, in order to serve a cached response in the standard Contao setup, it still needs to run through the entire
logic of its litespeed SAPI to serve a PHP request. Creating the superglobals, loading OPcache symbols, etc.
Let's visualize this real quick (notice the PHP Process which is always triggered):
sequenceDiagram
participant Client
participant LiteSpeed
box PHP Process
participant ContaoCache as Contao Cache
participant Contao
end
Client->>LiteSpeed: HTTP Request
LiteSpeed->>ContaoCache: Boot PHP and forward request
alt Cache Hit
ContaoCache-->>LiteSpeed: Return cached content
else Cache Miss
ContaoCache->>Contao: Forward request
Contao-->>ContaoCache: Generate content
ContaoCache-->>LiteSpeed: Cache and return generated content
end
LiteSpeed-->>Client: HTTP Response
Loading
Enter LiteSpeed Cache. LiteSpeed Cache provides all the features we need. We can configure it to ignore irrelevant query parameters or Cookies, make it only cache HTML responses, and it provides support for cache tagging and cache invalidation!
So if we don't have a cache hit, it of course still has to spawn PHP and ask Contao to generate the response but if
we have a cache hit, there's no need for this additional step, and it all happens within LiteSpeed itself (notice
how the PHP Process is only triggered in case of a cache miss):
sequenceDiagram
participant Client
participant LiteSpeed
box PHP Process
participant Contao
end
Client->>LiteSpeed: HTTP Request
alt Cache Hit
LiteSpeed-->>Client: Return cached content
else Cache Miss
LiteSpeed->>Contao: Boot PHP and forward request
Contao-->>LiteSpeed: Generate content
end
LiteSpeed-->>Client: Cache and return generated content
Loading
That's the entire reason why this bundle exists.
🚀⚡ More speed for cached responses! ⚡🚀
Configuration
To use this bundle, you need to configure both, the LiteSpeed webserver and Contao so they play well together.
LiteSpeed configuration
These are all the steps necessary to configure LiteSpeed Cache. It all happens via editing your .htaccess in public:
- First of all, we need configure LiteSpeed to enable LiteSpeed Cache for public responses on the entire domain (
/). - Then, we want to make sure we ignore forced cache reloads on requests that send
Cache-Control: no-cache. - Then, we want to optimize the cache key so it ignores all the query parameters that are not relevant to our
application. Typically, these are marketing parameters like
utm*etc. - Then, we want to optimize it so it ignores all the cache if a relevant cookie is present. If you
configured a
COOKIE_ALLOW_LISTin your environment variables for the PHP caching proxy of Contao, this is what you want to migrate. - Finally, we want to ensure, it only caches HTML responses that contain
text/htmlin theContent-Typeheader to prevent it from caching files etc. which are already highly optimized in LiteSpeed anyway.
Here's an example of how your .htaccess could look like. Check the LiteSpeed Cache docs
for more information:
<IfModule LiteSpeed>
# Enable LiteSpeed Cache
CacheEnable public /
# Ignore requests (!) that try to force cache reloading sending a no-cache header
CacheIgnoreCacheControl On
# Remove irrelevant query parameters from the cache key. Use * as placeholder
CacheKeyModify -qs:gclid,dclid,fbclid,zanpid,cx,ie,cof,siteurl,gclsrc,utm*
RewriteEngine On
# Bypass cache if any of these cookies are present on the request
RewriteCond %{HTTP_COOKIE} PHPSESSID|csrf_https-contao_csrf_token|trusted_device|REMEMBERME [NC]
RewriteRule .* - [E=Cache-Control:no-cache,E=t42_ls_bypass:1]
# Skip cache if response is not HTML
RewriteCond %{RESP_CONTENT_TYPE} !^text/html
RewriteRule .* - [E=Cache-Control:no-cache,E=t42_ls_bypass:1]
</IfModule>
As you can see, we set two environment variables when we want to bypass the cache: Cache-Control = no-cache and
t42_ls_bypass = 1. The first one is for LiteSpeed to bypass the cache completely (= it disables the module
entirely) and the second one is to inform this bundle that the cache is completely disabled. In this case, it needs
to remove the X-LiteSpeed-Tags header from the response because LiteSpeed does not do that if the module is
disabled entirely.
Contao configuration
To make Contao work well with our LiteSpeed Cache, we need to do two things:
- Disable the built-in cache proxy. Open your
.env.localand add:
DISABLE_HTTP_CACHE=true
- Adjust the Contao configuration so it uses
X-LiteSpeed-Tagas the cache tag header and integrate cache tag invalidation with theLiteSpeedProxyservice of this bundle. Open yourconfig/config.yamland add:
fos_http_cache: tags: enabled: true response_header: 'X-LiteSpeed-Tag' cache_manager: custom_proxy_client: Terminal42\ContaoLiteSpeedCache\LiteSpeedProxy
- Adjust tag prefix and environment variable if needed (optional):
Cache tags are global for one CacheRoot. In LiteSpeed you can configure the CacheRoot only at server level, meaning
you cannot dynamically adjust it in your .htaccess. But sometimes you may not have access to this configuration because
you e.g. run on a shared hosting environment. This can be problematic because if you run two Contao setups on the same
environment, invalidating certain tags in one setup may also invalidate the cache entries of the other setup in case you
happen to use the same tags which is very likely.
You can add a custom prefix to the tags then (but for data saving reasons, you may not use more than 3 characters):
terminal42_contao_lite_speed_cache: tag_prefix: 'p1-' # project 1
Happy fast caching! 😎
Miscellaneous info
- Make sure to add the
fos:httpcache:clearcommand to your deployment script in case you are using automated deployments. This will clear the LiteSpeed Cache thanks to the integration of this bundle. - Performance: Feel free to report your own results. We were able to speed up cached requests by around 15 - 20%, depending on the concurrency and other factors of course.