Setting up Varnish 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
    1177
  • 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 Varnish for 1C-Bitrix

A PHP Bitrix process generates a catalog page in 200–800 milliseconds. With 100 concurrent users, the server hits CPU and memory limits. Varnish caches the HTTP response and serves subsequent requests in 1–5 ms without PHP involvement. However, there are several conflicts between Varnish and Bitrix that break authentication, cart, and personalized content.

Architecture: Varnish in Front of Nginx

Standard scheme: client → Varnish (:80/:443) → Nginx (:8080) → PHP-FPM. Nginx is switched to port 8080. Varnish receives requests, caches cacheable ones, and sends non-cacheable ones directly to the backend.

client → varnish:80 → nginx:8080 → php-fpm:9000
                 ↓ (cache hit)
              varnish cache (RAM)

Installation on CentOS/RHEL (typical for Bitrix VM):

yum install varnish
systemctl enable varnish

Key Integration Issues with Bitrix

Bitrix uses session cookies PHPSESSID and authentication cookies BITRIX_SM_*. Varnish by default doesn't cache requests with cookies — this is correct but overly conservative. An anonymous user with an empty cart still gets a session cookie and misses the cache.

Another conflict is HTTPS. Varnish doesn't terminate SSL. You need Nginx or HAProxy in front of Varnish for SSL termination. The scheme becomes more complex: client → Nginx(:443, SSL) → Varnish(:80) → Nginx(:8080) → PHP-FPM.

VCL Configuration for Bitrix

vcl 4.1;

backend default {
    .host = "127.0.0.1";
    .port = "8080";
    .connect_timeout = 5s;
    .first_byte_timeout = 120s;
}

sub vcl_recv {
    # Force HTTP/1.1 (Varnish doesn't support HTTP/2 with backend)
    set req.http.X-Forwarded-For = client.ip;

    # Don't cache admin panel and login
    if (req.url ~ "^/bitrix/" || req.url ~ "^/area51/") {
        return (pass);
    }

    # Don't cache POST and authenticated users
    if (req.method == "POST" || req.method == "PUT") {
        return (pass);
    }

    # Authenticated user — BITRIX_SM_UIDH cookie
    if (req.http.Cookie ~ "BITRIX_SM_UIDH") {
        return (pass);
    }

    # Cart not empty
    if (req.http.Cookie ~ "BX_BASKET_ADD") {
        return (pass);
    }

    # Remove cookies that don't affect content (analytics, ads)
    set req.http.Cookie = regsuball(req.http.Cookie,
        "(^|;\s*)(_ga|_gid|_gat|_fbp|_ym_uid|_ym_d|_ym_isad)[^;]*", "");

    # If no cookies remain — can cache
    if (req.http.Cookie == "") {
        unset req.http.Cookie;
    }

    return (hash);
}

sub vcl_backend_response {
    # Don't cache responses with Set-Cookie (auth)
    if (beresp.http.Set-Cookie ~ "BITRIX_SM_") {
        set beresp.uncacheable = true;
        return (deliver);
    }

    # Cache static files for long
    if (bereq.url ~ "\.(css|js|png|jpg|webp|gif|woff2|ico)$") {
        set beresp.ttl = 30d;
        set beresp.grace = 1d;
        unset beresp.http.Set-Cookie;
        return (deliver);
    }

    # HTML pages — 5 minutes with 1 hour grace
    if (beresp.http.Content-Type ~ "text/html") {
        set beresp.ttl = 5m;
        set beresp.grace = 1h;
    }

    return (deliver);
}

sub vcl_deliver {
    # Debug header — remove in production
    if (obj.hits > 0) {
        set resp.http.X-Cache = "HIT";
    } else {
        set resp.http.X-Cache = "MISS";
    }
}

Cache Invalidation from Bitrix

When a product is updated or news is published, Varnish continues serving the old page until TTL expires. You need a mechanism for forced invalidation.

In bitrix/php_interface/init.php add an infoblock event handler:

AddEventHandler('iblock', 'OnAfterIBlockElementUpdate', 'PurgeVarnishCache');
AddEventHandler('iblock', 'OnAfterIBlockElementAdd', 'PurgeVarnishCache');

function PurgeVarnishCache($arFields) {
    $url = 'http://127.0.0.1/';
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PURGE');
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    // For selective invalidation by tag:
    curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-Cache-Tags: catalog']);
    curl_exec($ch);
    curl_close($ch);
}

In VCL, add handling for PURGE requests from localhost:

sub vcl_recv {
    if (req.method == "PURGE") {
        if (client.ip != "127.0.0.1") {
            return (synth(403, "Not allowed"));
        }
        return (purge);
    }
}

Varnish and Bitrix Composite

If Bitrix Composite is used (composite pages with AJAX loading of dynamic blocks), Varnish shouldn't cache the HTML basis of the page, otherwise Composite breaks. Either disable HTML caching through Varnish and keep it only for static files, or configure Composite for specific components without caching the entire page through Varnish.