Litespeed ignores expr in .htaccess (mod_headers)

I need to overwrite via htaccess the cache-control response header with the value of a custom http response header. On Apache I use the following line:

Header always set Cache-Control "expr=%{resp:x-my-custom-header}"
but doesn't work on Litespeed. Seems that litespeed does not support expr infact the cache-control value returned back to the client is:

Cache-Control: expr={resp:x-wp-cf-super-cache-cache-control}
If I try to force the Cache-Control value but only when another response custom header is present, for example:

Header always set Cache-Control "max-age=1" "expr=resp('x-my-second-custom-header') == '1'"
Litespeed ignores the condition and sets up Cache-Control: max-age=1 always, even if x-my-second-custom-header is not exists or its value is not 1.

How can I solve?

Thank you!
Ok I can also use X-Litespeed-Cache-Control instead of Cache-Control but the problem remains and it is in the htaccess rule to use.

I need to use htaccess because I have to force the value regardless of any X-Litespeed-Cache-Control headers set by PHP software.

However, I have to do it dynamically, i.e. depending on the page being visited, the Cache-Control value must be different and this value is provided by a custom header.

The problem is that if I try to use the rule I wrote above, that on Apache it works perfectly, on Litespeed it doesn't work because the expression expr seems to be ignored.


Well-Known Member
In my mind that hasn't something to with unsupported expressions. If an URL is cached you cannot define a new header on an already cached URL. Cache is cache and PHP cannot be executed. If you want to make it dynamically to set a new header depending on whatever you must use vary cache control in .htaccess. Use vary cache control to define a new uncached status. This new status allows to execute PHP and you can define the header you need depending on vary cache control tag. I hope you understand what I try to explain?
Yes but follow me. The scenario is this:

You request a URL, for example /hello-world

This URL is not yet cached on Litespeed.

Now I have to setup a cache-control header in order to define the cache TTL. Must be the cache-control header because I use also the Cloudlfare cache that use its value to define its TTL.

The value for cache-control header is stored on a custom http header created by a PHP script 'cause this value can differs for each URL.

For example the max-age for the /hello-world URL is 10 but for the /my-account URL is 0.

What I have to do is create (or overwrite if already exists) a cache-control header with this value.

If you try to visit the URL again, there is no problem as its cache-control header was already set the first time, when it was not yet in the cache.

On Apache I use the rule on the first post, but it seems not be compatible with litespeed or maybe litespeed does not support the expr=value, available in Apache 2.4.10 and later

So the problem is how tell to litespeed to create a cache-control header (using htaccess) with a value of another http response header.


Well-Known Member
I already understand where your need is, but again, if an URL is cached you cannot overwrite cache ttl with a new rule without to purge the cache or with a different vary cache tag. This is not a typical LiteSpeed behavior. That is a typical behavior of every fullpage cache.

Maybe I missunderstand what your problem is, but if you have different URLs, you can define different TTL for each URL. Use php requested_uri and set the header you need for each requested uri, but you can only define only 1 cache rule for each URL if you don't use vary cache control tags. I am shure it is possible to solve your need, but not in the way you believe in. More details would help me?
The problem to use PHP only is that other scripts (or plugins if use a CMS) can add they own TTL values. I want use htaccess in order to overwrite existing TTL (added by other PHP scripts) with mine.


Well-Known Member
That will not work. Cache "headers" can only defined and set with PHP, not with .htaccess. If you want to overwrite existing headers you must find an entry at the application where you are the last one who has defined the header. It follows cascading prinziples, but only if a URL isn't already cached. With cache -> no PHP.


Well-Known Member
I don't know if it is a directive. To get LiteSpeed cache run you must not set PHP headers imperative. To get it work simple rewrite rules in .htaccess are enough. You should check LiteSpeed Wiki. In section no-plugin usage you should find a lot of information that will help you finding a solution.
I found the following thread:

I have the same problem but related to "expr". It's not true that headers cannot be setted using htaccess. The same issue comes out also by setting the rule under "Header Operations" into the Litespeed web panel.

There is another issue. If I want create a custom response header for PNG only, on Apache I add a rule like this one:

Header set X-custom-test "test" "expr=%{CONTENT_TYPE} =~ m#image/png#"

The same rule on Litespeed doesn't work. Litespeed add the header for all contents: css, html, images, javascript, etc.. and not for PNG only. Try it

I think it's a Litespeed bug as this rule conforms to the documentation of Apache's mod_headers module


Well-Known Member
I didn't say LiteSpeed cannot generally set headers in .htaccess. As I know this is limited to cache control, but if you think there is a bug why don't you open a support ticket to get qualified feedback?