# Docker Compose для Битрикс — production-ready конфиг

URL: https://dmeshcheryakov.ru/blog/docker-compose-bitrix/
Раздел: DevOps
Теги: 1С-Битрикс, Docker, DevOps, nginx
Опубликовано: 2026-07-20
Обновлено: 2026-09-07
Автор: Дмитрий Мещеряков (https://dmeshcheryakov.ru)

> Полный docker-compose.yml для Битрикс: nginx, PHP-FPM, MySQL, Redis, cron. Оптимизация для production, persistent volumes, healthchecks.

Это разбор полной конфигурации: nginx, PHP-FPM, MySQL, Redis, отдельный контейнер для агентов и push-сервер. В отличие от минимального набора «поднять и посмотреть», здесь учтены вещи, которые всплывают при попытке пользоваться таким окружением каждый день, — cron, сессии в Redis, разделение dev- и общих настроек.

Сразу оговорю границу: это окружение **для разработки**. Битрикс в продакшене живёт в конфигурации, которую поддерживает вендор, и различия между ней и вашим контейнером — источник классического «на локалке работает».

## Что входит в окружение и зачем

Docker Compose — это описание нескольких связанных контейнеров одним файлом. Здесь их шесть: nginx как веб-сервер, PHP-FPM для приложения, MySQL для базы, Redis для кэша и сессий, отдельный контейнер под cron с агентами и push-сервер.

```
project/
├── docker-compose.yml
├── docker-compose.override.yml  # dev-настройки
├── .env
├── docker/
│   ├── nginx/
│   │   ├── nginx.conf
│   │   └── sites/
│   │       └── bitrix.conf
│   ├── php/
│   │   ├── Dockerfile
│   │   ├── php.ini
│   │   └── www.conf
│   └── mysql/
│       └── my.cnf
└── www/                         # Код Битрикс
    └── bitrix/
```

## docker-compose.yml

```yaml
# docker-compose.yml
version: '3.8'
services:
  nginx:
    image: nginx:1.25-alpine
    container_name: bitrix-nginx
    restart: unless-stopped
    ports:
      - "${NGINX_PORT:-80}:80"
      - "${NGINX_SSL_PORT:-443}:443"
    volumes:
      - ./www:/var/www/html:ro
      - ./docker/nginx/nginx.conf:/etc/nginx/nginx.conf:ro
      - ./docker/nginx/sites:/etc/nginx/sites-enabled:ro
      - ./logs/nginx:/var/log/nginx
    depends_on:
      php:
        condition: service_healthy
    networks:
      - bitrix-network
    healthcheck:
      test: ["CMD", "wget", "-q", "--spider", "http://localhost/health"]
      interval: 30s
      timeout: 10s
      retries: 3
  php:
    build:
      context: ./docker/php
      args:
        PHP_VERSION: ${PHP_VERSION:-8.2}
    container_name: bitrix-php
    restart: unless-stopped
    volumes:
      - ./www:/var/www/html
      - ./docker/php/php.ini:/usr/local/etc/php/php.ini:ro
      - ./docker/php/www.conf:/usr/local/etc/php-fpm.d/www.conf:ro
      - ./logs/php:/var/log/php
    environment:
      - PHP_MEMORY_LIMIT=${PHP_MEMORY_LIMIT:-512M}
      - PHP_MAX_EXECUTION_TIME=${PHP_MAX_EXECUTION_TIME:-300}
      - PHP_UPLOAD_MAX_FILESIZE=${PHP_UPLOAD_MAX_FILESIZE:-100M}
    depends_on:
      mysql:
        condition: service_healthy
      redis:
        condition: service_started
    networks:
      - bitrix-network
    healthcheck:
      test: ["CMD-SHELL", "php-fpm-healthcheck || exit 1"]
      interval: 30s
      timeout: 10s
      retries: 3
  mysql:
    image: mysql:8.0
    container_name: bitrix-mysql
    restart: unless-stopped
    command: --default-authentication-plugin=mysql_native_password
    environment:
      MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
      MYSQL_DATABASE: ${MYSQL_DATABASE:-bitrix}
      MYSQL_USER: ${MYSQL_USER:-bitrix}
      MYSQL_PASSWORD: ${MYSQL_PASSWORD}
    volumes:
      - mysql-data:/var/lib/mysql
      - ./docker/mysql/my.cnf:/etc/mysql/conf.d/custom.cnf:ro
      - ./backups/mysql:/backups
    networks:
      - bitrix-network
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "root", "-p${MYSQL_ROOT_PASSWORD}"]
      interval: 30s
      timeout: 10s
      retries: 5
  redis:
    image: redis:7-alpine
    container_name: bitrix-redis
    restart: unless-stopped
    command: redis-server --appendonly yes --maxmemory 256mb --maxmemory-policy allkeys-lru
    volumes:
      - redis-data:/data
    networks:
      - bitrix-network
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 30s
      timeout: 10s
      retries: 3
  cron:
    build:
      context: ./docker/php
      args:
        PHP_VERSION: ${PHP_VERSION:-8.2}
    container_name: bitrix-cron
    restart: unless-stopped
    entrypoint: /usr/local/bin/cron-entrypoint.sh
    volumes:
      - ./www:/var/www/html
      - ./docker/php/php.ini:/usr/local/etc/php/php.ini:ro
      - ./logs/cron:/var/log/cron
    depends_on:
      - php
      - mysql
    networks:
      - bitrix-network
  push:
    image: ikarpovich/bitrix-push-server:latest
    container_name: bitrix-push
    restart: unless-stopped
    environment:
      - REDIS_HOST=redis
      - REDIS_PORT=6379
    ports:
      - "${PUSH_PORT:-8010}:80"
    depends_on:
      - redis
    networks:
      - bitrix-network
networks:
  bitrix-network:
    driver: bridge
volumes:
  mysql-data:
  redis-data:
```

## Dockerfile для PHP

```dockerfile
# docker/php/Dockerfile
ARG PHP_VERSION=8.2
FROM php:${PHP_VERSION}-fpm-alpine
# Зависимости для сборки
RUN apk add --no-cache --virtual .build-deps \
    $PHPIZE_DEPS \
    freetype-dev \
    libjpeg-turbo-dev \
    libpng-dev \
    libwebp-dev \
    libzip-dev \
    icu-dev \
    libxml2-dev \
    oniguruma-dev \
    curl-dev
# Runtime зависимости
RUN apk add --no-cache \
    freetype \
    libjpeg-turbo \
    libpng \
    libwebp \
    libzip \
    icu-libs \
    libxml2 \
    oniguruma \
    curl \
    bash \
    dcron \
    fcgi
# PHP расширения
RUN docker-php-ext-configure gd \
    --with-freetype \
    --with-jpeg \
    --with-webp
RUN docker-php-ext-install -j$(nproc) \
    gd \
    mysqli \
    pdo_mysql \
    opcache \
    zip \
    intl \
    exif \
    mbstring \
    xml \
    curl \
    bcmath \
    sockets
# Redis
RUN pecl install redis && docker-php-ext-enable redis
# Xdebug (только для dev)
ARG INSTALL_XDEBUG=false
RUN if [ "$INSTALL_XDEBUG" = "true" ]; then \
    pecl install xdebug && docker-php-ext-enable xdebug; \
fi
# Очистка
RUN apk del .build-deps && rm -rf /var/cache/apk/*
# Healthcheck скрипт
RUN set -xe && echo "#!/bin/sh" > /usr/local/bin/php-fpm-healthcheck && \
    echo "SCRIPT_NAME=/health SCRIPT_FILENAME=/health REQUEST_METHOD=GET cgi-fcgi -bind -connect 127.0.0.1:9000 || exit 1" >> /usr/local/bin/php-fpm-healthcheck && \
    chmod +x /usr/local/bin/php-fpm-healthcheck
# Cron entrypoint
COPY cron-entrypoint.sh /usr/local/bin/
RUN chmod +x /usr/local/bin/cron-entrypoint.sh
WORKDIR /var/www/html
USER www-data
EXPOSE 9000
CMD ["php-fpm"]
```

## Конфиг nginx для Битрикс

```nginx
# docker/nginx/sites/bitrix.conf
upstream php-fpm {
    server php:9000;
}
server {
    listen 80;
    server_name _;
    root /var/www/html;
    index index.php index.html;
    # Лимиты
    client_max_body_size 100M;
    client_body_buffer_size 10M;
    # Gzip
    gzip on;
    gzip_types text/plain text/css application/json application/javascript text/xml application/xml;
    gzip_min_length 1000;
    gzip_comp_level 6;
    # Healthcheck
    location = /health {
        access_log off;
        return 200 "OK";
        add_header Content-Type text/plain;
    }
    # Статика
    location ~* \.(jpg|jpeg|gif|png|svg|webp|ico|css|js|woff|woff2|ttf|eot)$ {
        expires 30d;
        add_header Cache-Control "public, no-transform";
        access_log off;
    }
    # Запрет доступа к служебным файлам
    location ~ /(\.ht|\.git|\.env|bitrix/\.settings|bitrix/php_interface/dbconn) {
        deny all;
        return 404;
    }
    # Битрикс urlrewrite
    location / {
        try_files $uri $uri/ @bitrix;
    }
    location @bitrix {
        fastcgi_pass php-fpm;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root/bitrix/urlrewrite.php;
        fastcgi_param QUERY_STRING $args;
    }
    # PHP
    location ~ \.php$ {
        try_files $uri =404;
        fastcgi_pass php-fpm;
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param DOCUMENT_ROOT $document_root;
        # Таймауты для длинных операций
        fastcgi_read_timeout 300;
        fastcgi_send_timeout 300;
        fastcgi_connect_timeout 60;
        # Буферы
        fastcgi_buffer_size 128k;
        fastcgi_buffers 256 16k;
        fastcgi_busy_buffers_size 256k;
    }
    # Push & Pull
    location /bitrix/sub/ {
        proxy_pass http://push:80;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}
```

## Конфиг PHP

```ini
; docker/php/php.ini
[PHP]
memory_limit = ${PHP_MEMORY_LIMIT:-512M}
max_execution_time = ${PHP_MAX_EXECUTION_TIME:-300}
max_input_time = 300
post_max_size = 100M
upload_max_filesize = 100M
max_file_uploads = 50
short_open_tag = On
display_errors = Off
log_errors = On
error_log = /var/log/php/error.log
date.timezone = Europe/Moscow
[Session]
session.save_handler = redis
session.save_path = "tcp://redis:6379"
session.gc_maxlifetime = 86400
[opcache]
opcache.enable = 1
opcache.memory_consumption = 256
opcache.interned_strings_buffer = 16
opcache.max_accelerated_files = 20000
opcache.validate_timestamps = 0
opcache.revalidate_freq = 0
opcache.fast_shutdown = 1
opcache.enable_cli = 1
[mbstring]
mbstring.internal_encoding = UTF-8
mbstring.func_overload = 0
```

## Конфиг MySQL

```ini
# docker/mysql/my.cnf
[mysqld]
# Кодировка
character-set-server = utf8mb4
collation-server = utf8mb4_unicode_ci
# InnoDB
innodb_buffer_pool_size = 1G
innodb_log_file_size = 256M
innodb_flush_log_at_trx_commit = 2
innodb_flush_method = O_DIRECT
# Оптимизации
max_connections = 200
table_open_cache = 4000
thread_cache_size = 50
query_cache_type = 0
query_cache_size = 0
# Таймауты
wait_timeout = 28800
interactive_timeout = 28800
# Логи
slow_query_log = 1
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 2
[client]
default-character-set = utf8mb4
```

## Как запускать агенты Битрикса в контейнере

```bash
#!/bin/bash
# docker/php/cron-entrypoint.sh
# Создаём crontab
cat > /var/spool/cron/crontabs/www-data << 'EOF'
# Агенты Битрикс каждую минуту
* * * * * /usr/local/bin/php /var/www/html/bitrix/modules/main/tools/cron_events.php >> /var/log/cron/agents.log 2>&1
# Очистка кэша раз в день
0 4 * * * /usr/local/bin/php /var/www/html/bitrix/modules/main/tools/backup.php full >> /var/log/cron/backup.log 2>&1
EOF
chmod 0600 /var/spool/cron/crontabs/www-data
chown www-data:www-data /var/spool/cron/crontabs/www-data
# Запускаем cron в foreground
exec crond -f -d 8
```

## .env файл

```bash
# .env
# PHP
PHP_VERSION=8.2
PHP_MEMORY_LIMIT=512M
PHP_MAX_EXECUTION_TIME=300
PHP_UPLOAD_MAX_FILESIZE=100M
# MySQL
MYSQL_ROOT_PASSWORD=super_secret_root_password
MYSQL_DATABASE=bitrix
MYSQL_USER=bitrix
MYSQL_PASSWORD=super_secret_password
# Ports
NGINX_PORT=80
NGINX_SSL_PORT=443
PUSH_PORT=8010
```

## Настройка Битрикс

```php
<?php
// /bitrix/.settings_extra.php
return [
    // Redis кэш
    'cache' => [
        'value' => [
            'type' => [
                'class_name' => '\\Bitrix\\Main\\Data\\CacheEngineRedis',
                'extension' => 'redis',
            ],
            'redis' => [
                'host' => 'redis',
                'port' => 6379,
            ],
            'sid' => $_SERVER['DOCUMENT_ROOT'] . '#01',
        ],
    ],
    // Агенты через cron
    'agents' => [
        'value' => [
            'crontab' => true,
        ],
    ],
];
```

**Production checklist:**
- Смените все пароли в `.env`
- Настройте SSL сертификаты
- Включите `opcache.validate_timestamps = 0`
- Настройте backup MySQL
- Добавьте мониторинг (Prometheus/Grafana)

## Команды

```bash
# Запуск
docker-compose up -d
# Логи
docker-compose logs -f php
# Войти в контейнер
docker-compose exec php sh
# Перезагрузить nginx
docker-compose exec nginx nginx -s reload
# Бэкап MySQL
docker-compose exec mysql mysqldump -u bitrix -p bitrix > backup.sql
```

## Итоги

| Контейнер | Образ | Назначение |
|-----------|-------|------------|
| nginx | nginx:1.25-alpine | Веб-сервер |
| php | php:8.2-fpm-alpine | PHP-FPM |
| mysql | mysql:8.0 | База данных |
| redis | redis:7-alpine | Кэш, сессии |
| cron | php:8.2-fpm-alpine | Агенты |
| push | bitrix-push-server | Push & Pull |

Несколько решений в этой конфигурации, которые стоит перенести в любое другое окружение для Битрикса.

**Отдельный контейнер для cron.** Разделение веб-процессов и фоновых задач — не эстетика: агент, съевший всю память, не должен ронять сайт, а тяжёлый обмен не должен конкурировать за процессы PHP-FPM с посетителями. Плюс на локальной машине это единственный способ убедиться, что агенты действительно работают через cron, а не на хитах, — то есть воспроизвести продакшен.

**Сессии в Redis.** При нескольких контейнерах PHP файловые сессии перестают работать: пользователь попадает то на один контейнер, то на другой, и его каждый раз разлогинивает. Проблема выглядит как «Битрикс глючит с авторизацией» и стоит нескольких часов до догадки.

**Alpine-образы там, где можно.** Разница в размере ощутима, но проверяйте набор расширений: часть из них требует сборки, а несовместимость с musl вылезает в самый неподходящий момент. Если возникают странные сбои — попробуйте обычный образ на Debian, прежде чем искать причину в коде.

**Разделение `docker-compose.yml` и `docker-compose.override.yml`.** Общая конфигурация одна на команду, локальные отличия (порты, xdebug, монтирование) — в override, который не коммитится. Иначе каждый разработчик правит общий файл под себя, и конфликт в нём становится ежедневным ритуалом.

**Не переносите этот compose-файл на боевой сервер.** Пароли в `.env`, порты наружу, отсутствие ограничений по ресурсам, отладочные настройки PHP — всё это допустимо на локальной машине и недопустимо в проде. Продакшен-конфигурация — отдельная работа с другими требованиями, а не тот же файл с изменённым паролем.