Setting up browser-side caching for 1C-Bitrix

Our company is engaged in the development, support and maintenance of Bitrix and Bitrix24 solutions of any complexity. From simple one-page sites to complex online stores, CRM systems with 1C and telephony integration. The experience of developers is confirmed by certificates from the vendor.
Our competencies:
Development stages
Latest works
  • image_website-b2b-advance_0.png
    B2B ADVANCE company website development
    1175
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Website development for FIXPER company
    811
  • image_bitrix-bitrix-24-1c_development_of_an_online_appointment_booking_widget_for_a_medical_center_594_0.webp
    Development based on Bitrix, Bitrix24, 1C for the company Development of an Online Appointment Booking Widget for a Medical Center
    564
  • image_bitrix-bitrix-24-1c_mirsanbel_458_0.webp
    Development based on 1C Enterprise for MIRSANBEL
    747
  • image_crm_dolbimby_434_0.webp
    Website development on CRM Bitrix24 for DOLBIMBY
    655
  • image_crm_technotorgcomplex_453_0.webp
    Development based on Bitrix24 for the company TECHNOTORGKOMPLEKS
    976

Configuring Browser-Side Caching for 1C-Bitrix

Configuring Browser-Side Caching for 1C-Bitrix

A returning visitor loads the page in 4 seconds even though the logs show a TTFB of 200 ms. The waterfall in DevTools explains it: 80 requests to static assets, each returning a 304 Not Modified. Files are served from the browser cache, but the browser still asks the server "has this changed?" Properly set caching headers eliminate these requests entirely.

Browser Cache Model

The browser uses two mechanisms:

Freshness — the browser knows until what point a file is current and does not contact the server at all. Controlled by Cache-Control: max-age and Expires headers.

Validation — the browser asks the server "has the file changed?" using ETag or Last-Modified. The server responds with 304, and the browser uses the cache. Saves bandwidth, but not RTT.

The goal is to maximize Freshness for versioned static assets and use Validation for HTML.

nginx Configuration for Bitrix

server {
    # HTML — short cache with revalidation
    location ~* \.html?$ {
        add_header Cache-Control "no-cache, must-revalidate";
        etag on;
    }

    # CSS, JS with hashes in names (Vite/Webpack) — long cache
    location ~* /build/assets/.*\.[a-f0-9]{8,}\.(css|js)$ {
        add_header Cache-Control "public, max-age=31536000, immutable";
        access_log off;
    }

    # Static assets without hashes — moderate cache
    location ~* \.(css|js)$ {
        add_header Cache-Control "public, max-age=604800";
        etag on;
    }

    # Images
    location ~* \.(jpg|jpeg|png|gif|webp|avif|ico|svg)$ {
        add_header Cache-Control "public, max-age=2592000";
        access_log off;
    }

    # Fonts
    location ~* \.(woff|woff2|ttf|otf|eot)$ {
        add_header Cache-Control "public, max-age=31536000, immutable";
        add_header Access-Control-Allow-Origin "*";
        access_log off;
    }

    # Bitrix assets (no hashes)
    location ~* ^/bitrix/(js|css|fonts)/ {
        add_header Cache-Control "public, max-age=604800";
        etag on;
    }
}

immutable in Cache-Control — the browser will not check the file even on a manual page refresh (Ctrl+F5 has no effect). Apply only to files with a version hash in the filename.

Asset Versioning in Bitrix

Without versioning, a long cache is dangerous: after a CSS update, users see the old design for a week.

Built-in Bitrix mechanism — the sessid parameter in asset URLs. Not ideal: it changes every session and invalidates the cache more often than needed.

Via .htaccess / nginx map — append a content hash to static asset URLs at deploy time:

# Deploy script: generate versions
for f in /var/www/site/public/css/*.css; do
    hash=$(md5sum "$f" | cut -c1-8)
    # Create symlink with hash
    ln -sf "$(basename $f)" "${f%.css}.${hash}.css"
done

Vite/Webpack — if the frontend is built via Vite (as in this project), hashes in filenames are generated automatically: app-B3vCf7Tf.js. For these files, max-age=31536000, immutable can safely be applied.

Bitrix Cache Invalidation via Query Parameter

For assets without automatic versioning, use a manual parameter in the template:

// In the template's header.php
$version = '2024031301'; // update on each deploy

echo '<link rel="stylesheet" href="/css/custom.css?v=' . $version . '">';

Automate: read the version from a version.txt file updated by CI/CD:

$version = trim(file_get_contents($_SERVER['DOCUMENT_ROOT'] . '/version.txt'));

Apache .htaccess

<IfModule mod_expires.c>
    ExpiresActive On

    ExpiresByType text/html "access plus 0 seconds"
    ExpiresByType text/css "access plus 1 week"
    ExpiresByType application/javascript "access plus 1 week"
    ExpiresByType image/jpeg "access plus 1 month"
    ExpiresByType image/png "access plus 1 month"
    ExpiresByType image/webp "access plus 1 month"
    ExpiresByType font/woff2 "access plus 1 year"
</IfModule>

<IfModule mod_headers.c>
    <FilesMatch "\.(css|js)$">
        Header set Cache-Control "public, max-age=604800"
    </FilesMatch>
</IfModule>

Verification

curl -sI https://site.ru/css/styles.css | grep -i "cache-control\|expires\|etag"

Chrome DevTools → Network → select a resource → Headers: check Cache-Control in Response Headers and from cache / from disk cache in the Size column on a repeat load.