I'm seeking help with a persistent issue regarding Drupal 11 CSS aggregation on my server setup. I hope someone might have encountered this or have some ideas.
My Environment:
CMS: Drupal 11
Control Panel: CyberPanel 2.3
Web Server: OpenLiteSpeed (OLS)
OS: AlmaLinux 8
Cloudflare: Used for DNS management ONLY (Proxy feature is disabled - Grey Cloud).
The Problem:
When I enable Drupal's "Aggregate CSS files" setting (css.preprocess = 1 at /admin/config/development/performance), the website's styling breaks (e.g., menus malfunction, layout issues occur).
Upon investigation, I discovered that while most aggregated CSS files are correctly generated in the web/sites/default/files/css/ directory as plain text *.css files, one specific aggregated CSS file is consistently saved with a .css extension but contains binary Gzip data. Viewing this particular file's content shows unreadable characters (e.g., \n6áÈÙ”...).
The HTML source code correctly links to the .css file (e.g., <link href="/sites/default/files/css/css_some_hash.css">), not a .css.gz file. It appears the browser receives this binary Gzip content but expects plain text/css, leading to parsing failure and broken rendering.
Disabling Drupal's CSS aggregation (css.preprocess = 0) resolves the display issue entirely, but this negatively impacts page load performance, which I would prefer to avoid.
Troubleshooting Steps Already Performed:
I have tried extensively to resolve this, including:
File Permissions: Verified and set correct write permissions for the web server/PHP user on the web/sites/default/files/ directory and its css/js subdirectories.
vHost Configuration: Explicitly set enableGzip 0 and enableBr 0 in the vHost configuration file for my domain (eg.one).
LSWS WebAdmin Console (Port :7080):
Confirmed Enable GZIP Compression: No and Enable Brotli Compression: No under Virtual Hosts -> eg.one -> General tab.
Checked inside Virtual Hosts -> eg.one -> Context tab, specifically for the / context (Type: Static), and ensured any Gzip/Brotli/Compression settings there were also disabled.
Checked server-level Gzip/Brotli settings in Server Configuration -> Tuning -> Gzip/Brotli Compression (tested disabling server-level compression, no change, reverted).
.htaccess: Temporarily commented out the standard Drupal .htaccess block related to serving pre-compressed .gz files (<IfModule mod_headers.c>...). This had no effect, so the change was reverted.
LSWS Cache Module: Temporarily commented out the module cache { ... } block in the vHost configuration. This also had no effect, so the change was reverted.
Cloudflare: Confirmed Cloudflare Proxy is disabled (DNS Only / Grey Cloud).
My Question:
Despite explicitly disabling Gzip/Brotli compression at multiple levels (vHost, Context, potentially Server), OpenLiteSpeed/CyberPanel still seems to incorrectly compress just one specific aggregated CSS file on disk, saving it with binary data under a .css extension.
Does anyone know why this might be happening, especially affecting only one file?
Are there other less obvious OpenLiteSpeed or CyberPanel settings I should investigate that could cause this behavior?
* Could this be a known bug related to specific versions or configurations?
Any advice or direction would be highly appreciated!
1) Double Check Drupal’s Own Aggregation/Compression Behavior
Although Drupal typically only aggregates CSS (concatenates multiple files into fewer files), some Drupal versions or site setups can also apply GZIP/deflate if certain modules or advanced aggregator settings are in place. Drupal core does not usually store aggregator output on disk in gzipped form (it leaves compression to the web server), but a few scenarios can lead to double-compressed or partially gzipped CSS in sites/default/files/css/:
Theme or Contrib Modules: Verify you are not using any performance or front-end optimization modules (for example, “AdvAgg,” “Boost,” “Blazy,” “Performance Tweaks,” “CDN/Cloudflare modules,” etc.) that might compress assets behind the scenes. If you do, either disable them temporarily or inspect their config to ensure they are not compressing the final aggregated file themselves.
Drupal .htaccess:
In older Drupal versions, there was a .htaccess snippet that served pre-gzipped .gz versions if they existed. You already tried commenting out the relevant block under <IfModule mod_headers.c> AddType ... ExpiresByType .... Confirm you fully commented any references to AddEncoding gzip .gz or RewriteCond %{HTTP:Accept-Encoding} ... lines and retested.
Although you reverted changes, try fully removing all .htaccess compression references for debugging, just in case.
Flush the Aggregator: Make sure you:
drush cr (or use Admin UI: Reports -> Status -> Clear cache) to ensure old aggregator data is purged.
Then re-enable CSS aggregation to see if the newly written aggregated files are correct.
Look at Database aggregator tables: In Drupal’s config or aggregator-related tables, verify there is no leftover config that specifically says “compress aggregated CSS.” Typically you would not see this in a standard Drupal 9/10/11, but if you see references to compression in advanced aggregator modules, that’s a red flag.
2) Rule Out Leftover or Accidental GZ Caching in LiteSpeed
Even after disabling enableGzip 0 and enableBr 0, leftover or default rules might be triggered in certain contexts. Some areas to watch for:
Check the /context in OLS:
You mentioned you looked under Virtual Hosts → eg.one → Context → / (Type: Static). Verify the static file context doesn’t have a custom AddDefaultCharset or ForceType plus compression. If you see any AddOutputFilterByType or mod_deflate style lines, remove them.
Check .htaccess vs. LiteSpeed Directives:
Sometimes LiteSpeed can parse Apache-like directives in the .htaccess. Even if you removed the standard Drupal compression snippet, confirm that the OpenLiteSpeed “Apache config” is not including another snippet from somewhere else (like /opt/litespeed/conf/httpd.conf or a custom include) which might re-enable compression for .css files.
Disable LSCache (Module) Thoroughly:
Even if you “commented out the cache { … } block,” be sure the LSCache module is actually not active. In the OpenLiteSpeed WebAdmin → Cache tab, ensure there are no hidden “Enable Cache” directives for CSS, or forced re-compression. If you have the WordPress plugin LSCache installed at the server level for any other domain, ensure it’s not hooking in to your Drupal site with some multi-site rule.
Manually Inspect the “Gzipped” File:
Download the problematic .css file from sites/default/files/css/.
Open it in a hex editor (or simply run file css_some_hash.css on your local machine or in SSH) to confirm it sees gzip compressed data or “DEFLATE compressed data.”
If so, rename that file to .gz and test unzipping it. If it is truly just leftover from a prior caching step, it should uncompress fine.
If it’s partially corrupted, it could be a sign that something else is messing with how aggregator files are written.
3) Confirm Response Headers vs. File Storage
Occasionally, the file on disk is plain text, but the server is sending it down with an HTTP Content-Encoding: gzip header. The browser might choke on that if it also sees Content-Type: text/css. In other words, the file physically on disk might look gibberish because you open it in an editor that sees the bytes after a transparent decompression from the web server. So:
Look for Content-Encoding: gzip or Content-Type: text/css; charset=UTF-8.
If you see Content-Encoding: gzip, your server is definitely sending it compressed, which might be normal unless it’s also physically stored compressed.
If you see no Content-Encoding, but the file itself is still binary, it implies the file is stored incorrectly on disk as gzipped data, which is suspicious.
Check the ETag or “Vary” Headers:
If Vary: Accept-Encoding is present, your server might be toggling compression based on the request.
If you forcibly request curl -H "Accept-Encoding: none" ..., do you get plain text or still binary?
These tests clarify whether the problem is “the file on disk is saved incorrectly” or “the file is normal but the server is always sending it gzipped.”
4) Additional Rare Culprits
Symbolic Links or Reference Issues: If that particular CSS file is aggregated from a theme or library that physically resides in a symlinked directory, sometimes a misconfiguration can cause OLS to compress or store it differently. Worth verifying that the path is fully local, no symlinks are triggering alternative “Static context” rules in your OLS config.
Weird Permission or Ownership: If that one file is incorrectly owned by root while the rest are owned by nobody or www-data (depending on your system’s user), sometimes the aggregator or OLS tries to read it, fails, and leaves partial data (which appears compressed). This is less likely, but worth checking that all aggregator files share the same user/group ownership.
Potential Drupal 11 Beta/Dev Quirks: Drupal 11 is not an official stable release as of early 2023–2024 (unless you’re using dev builds). Could it be a bug in the aggregator pipeline for certain libraries? If you can reproduce the same issue in Drupal 10 with the same environment, it might be environment-related rather than a Drupal version bug. Otherwise, keep an eye on Drupal’s issue queue for aggregator problems in dev versions.
Just a Single Large File: Sometimes if one aggregated file is significantly larger than the others, and some advanced directive in OLS or a module says “Compress files over X bytes,” it might forcibly compress that file. Look carefully in OLS server-level or virtual host-level performance or content settings for a “Minimum Size for compression” directive (it might be set to 0, but confirm).
5) Step-by-Step “Isolation” Strategy
If you’re still stuck, try:
Completely Disable Any LiteSpeed Cache or Optimization:
In OLS admin, remove the module cache { ... } block, set enableCache 0, set enableGzip 0, enableBr 0, etc.
Restart OpenLiteSpeed (or do a graceful restart).
Remove All .htaccess References (comment out the compression blocks, ETags, etc.).
Clear Drupal’s Cache thoroughly.
Re-aggregate.
If the file still ends up binary, it is almost certainly Drupal or a Drupal module compressing at the aggregator level.
Spin Up Another Environment (even if temporary). For instance, a local Docker with Apache or Nginx. Then see if Drupal 11 aggregator reproduces the same “one Gzip file” phenomenon. If it doesn’t happen, you know the bug is environment-specific to LiteSpeed or your CyberPanel config.