Setting up a centralized storage for 1C-Bitrix media files

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 Centralized Media File Storage for 1C-Bitrix

In a clustered Bitrix configuration or when multiple environments (prod, staging, dev) are present, media files from /upload/ live locally on each server. An uploaded product image exists on one node but not on others. File replication via NFS works but creates a single point of failure. Centralized storage based on an S3-compatible object store is the standard solution for this class of problems.

Object Storage Options

  • Yandex Object Storage — S3-compatible, data stored in Russia, straightforward integration
  • AWS S3 — if data can be stored outside the country
  • MinIO — self-hosted S3, can be deployed on your own servers
  • Selectel Object Storage — Russian hosting with S3 API

All options work with the same API (S3 compatible); Bitrix integration is identical for all.

Bitrix Cloud Storage Module

Bitrix has a built-in bitrix.cloud module for cloud file storage. Configuration: Settings → Cloud Storage.

Supported providers out of the box: Amazon S3, Azure Blob Storage. For Yandex Object Storage — via a custom endpoint, since it is S3-compatible:

// Configuration via .settings.php for S3-compatible storage
// Using direct integration via AWS SDK

Limitation of the bitrix.cloud module: not all file types are migrated correctly (file editor in admin panel, resize cache). Testing on staging is recommended.

Direct Integration via AWS SDK

composer require aws/aws-sdk-php
// /local/lib/Storage/S3Storage.php
namespace Local\Storage;

use Aws\S3\S3Client;

class S3Storage
{
    private static ?S3Client $client = null;

    public static function getClient(): S3Client
    {
        if (!self::$client) {
            $config = \Bitrix\Main\Config\Configuration::getValue('s3_storage');
            self::$client = new S3Client([
                'version'                 => 'latest',
                'region'                  => $config['region'],
                'endpoint'                => $config['endpoint'],  // for Yandex: storage.yandexcloud.net
                'use_path_style_endpoint' => true,
                'credentials'             => [
                    'key'    => $config['access_key'],
                    'secret' => $config['secret_key'],
                ],
            ]);
        }
        return self::$client;
    }

    public static function upload(string $localPath, string $s3Key): string
    {
        $bucket = \Bitrix\Main\Config\Configuration::getValue('s3_storage')['bucket'];
        self::getClient()->putObject([
            'Bucket'      => $bucket,
            'Key'         => $s3Key,
            'SourceFile'  => $localPath,
            'ACL'         => 'public-read',
            'ContentType' => mime_content_type($localPath),
        ]);
        return 'https://' . $bucket . '.storage.yandexcloud.net/' . $s3Key;
    }
}

Configuration in /bitrix/.settings.php:

's3_storage' => [
    'value' => [
        'access_key' => 'YCAJExxxx',
        'secret_key' => 'YCPxxx',
        'bucket'     => 'my-shop-media',
        'region'     => 'ru-central1',
        'endpoint'   => 'https://storage.yandexcloud.net',
    ],
],

Intercepting File Uploads in Bitrix

Bitrix saves files via CFile::SaveFile(). To route files to S3 instead of the local disk, intercept via a hook:

// Alternative: override behavior via a post-save event handler
\Bitrix\Main\EventManager::getInstance()->addEventHandler(
    'main',
    'OnAfterFileSave',
    function (\Bitrix\Main\Event $event) {
        $file = $event->getParameter('FILE');
        $localPath = $_SERVER['DOCUMENT_ROOT'] . $file['SRC'];

        if (file_exists($localPath)) {
            $s3Key = ltrim($file['SRC'], '/');
            \Local\Storage\S3Storage::upload($localPath, $s3Key);

            // Optional: delete the local copy after uploading to S3
            // unlink($localPath);
        }
    }
);

For serving files — configure nginx to proxy requests to /upload/ through the S3 CDN:

location /upload/ {
    proxy_pass https://my-shop-media.storage.yandexcloud.net/upload/;
    proxy_cache_valid 200 7d;
    add_header Cache-Control "public, max-age=604800";
}

Migrating Existing Files

Moving the current /upload/ to S3 is a separate operation:

# Sync local upload/ to S3 via AWS CLI
aws s3 sync /var/www/bitrix/upload/ s3://my-shop-media/upload/ \
    --endpoint-url https://storage.yandexcloud.net \
    --acl public-read \
    --no-progress

# Verify file count
aws s3 ls s3://my-shop-media/upload/ --recursive --endpoint-url https://storage.yandexcloud.net | wc -l

Migration is done with rollback capability: local files are not deleted until correct operation is confirmed.

Setup Timeline

S3 storage setup, Bitrix integration via SDK, nginx proxy configuration, existing file migration — 2–4 business days depending on the size of the existing upload/ directory.