Why Drupal Media Fills Your Quota
Drupal does not store a single copy of each uploaded image. Every time an image style renders on a page, Drupal writes a derivative file to sites/default/files/styles/, organized by style name and the original file path. A single photo uploaded through the Media library can therefore spawn a dozen or more physical files: thumbnail, medium, large, plus whatever custom styles your theme and content types define. On a busy content site this multiplies fast, and the pressure lands on two limits that shared hosting enforces strictly on AlmaLinux with CloudLinux: total disk usage and the inode count (the number of individual files and folders allowed on your account).
Inode exhaustion is the more common surprise. You may sit well under your disk quota in gigabytes and still hit a hard wall because tens of thousands of tiny derivative files, cached CSS/JS aggregates, and Twig template caches have consumed your file allowance. When that happens Drupal can no longer write new derivatives, uploads fail silently, and the site may throw permission-style errors even though nothing about your permissions changed. Checking sites/default/files/php/twig, sites/default/files/css, and the styles directory in cPanel File Manager usually reveals where the file count concentrates.
The second factor is the original files themselves. Editors routinely upload multi-megabyte photos straight from a phone or DSLR, and Drupal keeps that full-resolution original forever even when the largest style used on the frontend is 1200 pixels wide. Those originals sit in sites/default/files/ and are backed up on every account snapshot, compounding the storage cost. Understanding this pipeline — original file, image styles, derivative cache, aggregation cache — is what lets you cut usage without breaking the site. Every optimization below targets one of these four layers using tools available to an unprivileged hosting user.
Tuning Image Styles and Upload Limits
Start by auditing the styles Drupal actually renders. Navigate to Administration > Configuration > Media > Image styles (path /admin/config/media/image-styles). Core ships with thumbnail, medium, large, and wide, and many contributed themes add several more. Any style listed here that no field, view, or responsive image mapping references is dead weight — it still generates files whenever it is invoked by a stray reference. Remove unused custom styles, and for the ones you keep, open each and confirm the Scale and crop or Scale effect uses sensible maximum dimensions. A style capped at 1920 pixels is almost always enough for full-width hero images; anything larger just burns storage.
Next, control what enters the pipeline. On each image field (Structure > Content types > [type] > Manage fields), edit the field settings and set a Maximum image resolution, for example 2560x2560. Drupal downsizes the original on upload when this is set, so a 6000-pixel phone photo is trimmed before it ever reaches disk. Also set a Maximum upload size per field to reject oversized files early. These field-level limits are enforced by Drupal itself and need no server changes.
PHP's own upload ceilings still apply, and on shared hosting you adjust them without root. In cPanel use Select PHP Version > Options (the MultiPHP INI editor / PHP Selector) to raise upload_max_filesize, post_max_size, and memory_limit. If your plan exposes these values only per-directory, create or edit a .user.ini file in your document root:
upload_max_filesize = 32M
post_max_size = 36M
memory_limit = 256M
max_execution_time = 120Keep post_max_size slightly above upload_max_filesize, and give memory_limit real headroom — GD needs several times an image's pixel dimensions in RAM to generate derivatives, and a low limit produces truncated or missing thumbnails rather than a clean error. Changes to .user.ini take effect after the PHP FastCGI process recycles, typically within a few minutes on LiteSpeed.
Enabling WebP and AVIF Derivatives
Modern formats cut image weight dramatically, and Drupal supports them through the toolkit already available in your PHP build. On CloudLinux you can confirm which image extensions are active in Select PHP Version > Extensions — enable gd (which includes WebP support in current PHP builds) or, if your plan offers it, imagick, which handles AVIF where the underlying library allows.
Drupal 10 core can produce WebP directly. Add a Convert effect to an image style at /admin/config/media/image-styles, chained after your scale effect, and set the target extension to webp. For broader control and automatic fallback delivery, the contributed ImageAPI Optimize WebP module (installed via the Extend page after uploading through Extend > Install new module) generates a .webp alongside each derivative and rewrites markup to serve it to supporting browsers. Because it produces a second file per derivative, watch your inode count — pair it with aggressive style pruning so the net effect is smaller total bytes, not more files.
Where a module rewrites URLs to append .webp, add a rewrite guard in your document root .htaccess so LiteSpeed serves the modern file when it exists and the browser advertises support:
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{HTTP_ACCEPT} image/webp
RewriteCond %{REQUEST_FILENAME}.webp -f
RewriteRule ^(.+)\.(jpe?g|png)$ $1.$2.webp [T=image/webp,E=accept:1,L]
</IfModule>
<IfModule mod_headers.c>
Header append Vary Accept env=accept
</IfModule>The Vary: Accept header stops proxies and LiteSpeed's cache from handing a WebP file to a browser that requested a JPEG. Only deploy this rewrite if your generated .webp files actually sit next to the originals; if your module serves them from a separate styles path instead, let the module handle the negotiation and leave .htaccess alone to avoid double-rewriting.
Offloading Delivery and Cleaning Derivatives
Serving every image and derivative from your account consumes bandwidth and keeps LiteSpeed workers busy on static files. A CDN moves that load off your origin. If your plan includes an integrated CDN (Cloudflare via cPanel, for example), enabling it caches your sites/default/files assets at the edge with no code change. For finer control, the contributed CDN module rewrites file URLs in rendered markup to point at a pull-zone hostname; configure it at /admin/config/development/cdn and set the mapping to your origin URL so the edge fetches and caches derivatives on first request. This is genuinely useful only because Drupal exposes the file URL rewriting hook the module relies on — do not attempt to relocate sites/default/files itself, since Drupal must write derivatives locally.
Regularly flush stale derivatives to reclaim inodes. From the admin UI, Configuration > Development > Performance (/admin/config/development/performance) offers Clear all caches, which removes CSS/JS aggregates and Twig caches. To purge image derivatives specifically, delete the contents of sites/default/files/styles/ in cPanel File Manager — Drupal regenerates only the derivatives that are actually requested afterward, so pruned styles never come back. Enable Aggregate CSS files and Aggregate JavaScript files on the same Performance page and set a browser cache lifetime so repeat visitors and the CDN cache assets longer. Between disciplined image styles, WebP conversion, capped uploads, and edge delivery, most Drupal sites cut both their disk footprint and inode count substantially while loading faster for visitors.