Docker Container Configuration for 1C-Bitrix
Docker Container Configuration for 1C-Bitrix
Running Bitrix in Docker is straightforward. Configuring containers to operate stably in production — restarting correctly, retaining data, and avoiding permission issues — requires knowledge of the platform's specifics. Common problems: Bitrix writes files as root, but nginx reads them as www-data; OPcache does not detect changes in code files; agents do not run because cron is not configured inside the container.
nginx Container Configuration
# docker/nginx/conf.d/bitrix.conf
server {
listen 80;
server_name _;
root /var/www/html;
index index.php;
charset utf-8;
client_max_body_size 256m;
# Bitrix security
location ~* /\.ht { deny all; }
location ~* /bitrix/modules { deny all; }
location ~* /bitrix/php_interface { deny all; }
location ~* /bitrix/tools { deny all; }
# Static files with caching
location ~* \.(jpg|jpeg|png|gif|webp|svg|ico|css|js|woff2)$ {
expires 30d;
add_header Cache-Control "public, no-transform";
try_files $uri =404;
}
# Bitrix clean URLs
location / {
try_files $uri $uri/ /bitrix/urlrewrite.php$is_args$args;
}
# PHP via FPM
location ~ \.php$ {
fastcgi_pass php-fpm:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
# Timeouts for long-running operations (import, reports)
fastcgi_read_timeout 300;
fastcgi_send_timeout 300;
}
# Bitrix urlrewrite
location = /bitrix/urlrewrite.php {
fastcgi_pass php-fpm:9000;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}
File Permissions: Resolving the UID Problem
A classic problem: PHP-FPM inside the container runs as www-data (UID 33), while files in the volume were created by root or a different host user. Bitrix cannot write cache or save uploaded files.
Set the UID explicitly in the Dockerfile:
FROM php:8.1-fpm-alpine
# Create a user with the host UID (passed via build arg)
ARG HOST_UID=1000
RUN addgroup -g $HOST_UID bitrix \
&& adduser -u $HOST_UID -G bitrix -D bitrix
# Run PHP-FPM as bitrix
RUN sed -i 's/user = www-data/user = bitrix/g' /usr/local/etc/php-fpm.d/www.conf \
&& sed -i 's/group = www-data/group = bitrix/g' /usr/local/etc/php-fpm.d/www.conf
Pass the UID in docker-compose:
php-fpm:
build:
context: ./docker/php
args:
HOST_UID: ${HOST_UID:-1000}
.env:
HOST_UID=1000 # or the result of `id -u` on the host
Healthcheck for PHP-FPM
php-fpm:
healthcheck:
test: ["CMD-SHELL", "SCRIPT_FILENAME=/var/www/html/index.php SCRIPT_NAME=/index.php REQUEST_METHOD=GET cgi-fcgi -bind -connect 127.0.0.1:9000 | grep -q '200 OK'"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
Simpler alternative:
healthcheck:
test: ["CMD-SHELL", "php-fpm -t && kill -0 1"]
interval: 30s
Restart Policies
services:
nginx:
restart: unless-stopped # restart always except after explicit stop
php-fpm:
restart: unless-stopped
mysql:
restart: always # MySQL always, including after host reboot
unless-stopped vs always: with always, the container will restart even if explicitly stopped with docker stop. unless-stopped — does not restart after an explicit stop, but restarts after the Docker daemon restarts.
Log Rotation
By default, Docker accumulates logs indefinitely. On an active Bitrix site this can reach 1–5 GB per week:
# docker-compose.yml
services:
nginx:
logging:
driver: "json-file"
options:
max-size: "50m"
max-file: "5"
php-fpm:
logging:
driver: "json-file"
options:
max-size: "100m"
max-file: "3"
Or globally in /etc/docker/daemon.json:
{
"log-driver": "json-file",
"log-opts": {
"max-size": "100m",
"max-file": "3"
}
}
Zero-Downtime Container Updates
# Update only php-fpm without stopping nginx
docker-compose pull php-fpm
docker-compose up -d --no-deps --build php-fpm
# Verify the new container is healthy
docker-compose ps php-fpm
# If something went wrong — rollback
docker-compose up -d --no-deps php-fpm --scale php-fpm=1
When using multiple PHP-FPM replicas (via docker-compose scale), update one at a time while the others handle traffic.
Backups
#!/bin/bash
# backup.sh — run via cron on the host
DATE=$(date +%Y%m%d_%H%M%S)
BACKUP_DIR="/backups/bitrix"
# Database dump through the running container
docker-compose exec -T mysql mysqldump \
-u bitrix -p"${DB_PASSWORD}" \
--single-transaction bitrix | gzip > "$BACKUP_DIR/db_$DATE.sql.gz"
# Archive upload/ and config files
docker run --rm \
-v bitrix_files:/data:ro \
-v "$BACKUP_DIR":/backup \
alpine tar czf "/backup/files_$DATE.tar.gz" /data/upload /data/bitrix/.settings.php
# Remove backups older than 7 days
find "$BACKUP_DIR" -mtime +7 -delete







