diff --git a/.env.example b/.env.example index 100a265..9c5f32e 100644 --- a/.env.example +++ b/.env.example @@ -8,10 +8,14 @@ HTTP_PORT=80 HTTPS_PORT=443 TIMEZONE=Europe/Moscow +# Pinned nginx image — do not bump without testing +NGINX_IMAGE=nginx:1.27.4-bookworm + # PHP-FPM image tag and optional extra extensions (space-separated) -# Example: mbstring imagick redis xdebug +# mbstring is always installed in the base image (required by Bitrix) +# Example: imagick redis xdebug PHP_VERSION=8.3 -PHP_EXTRA_EXTENSIONS=mbstring +PHP_EXTRA_EXTENSIONS= # Linux/macOS: set to your user to avoid permission issues in www/ UID=1000 diff --git a/.gitattributes b/.gitattributes index 83e01c1..9803772 100644 --- a/.gitattributes +++ b/.gitattributes @@ -5,6 +5,7 @@ *.ps1 text eol=crlf *.sh text eol=lf +docker/php/docker-entrypoint.sh text eol=lf Makefile text eol=lf *.conf text eol=lf *.ini text eol=lf diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9ca9f60..711a3f0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -13,10 +13,12 @@ jobs: uses: actions/checkout@v4 - name: Check shell syntax - run: bash -n scripts/*.sh docker/mysql/initdb/*.sh + run: bash -n scripts/*.sh docker/mysql/initdb/*.sh docker/php/docker-entrypoint.sh - name: Validate Compose config - run: docker compose config + run: | + cp .env.example .env + docker compose config - name: Build Docker images run: docker compose build diff --git a/README.md b/README.md index 5675b74..1364d4f 100644 --- a/README.md +++ b/README.md @@ -13,13 +13,13 @@ Clone the repository, set a local domain, put a Bitrix backup into `www/`, run ` | --- | --- | --- | | PHP-FPM | `php:8.3-fpm-bookworm` (build arg `PHP_VERSION`) | Custom image with Bitrix-oriented `php.ini` | | MySQL | `mysql:8.0.36` (pinned via `MYSQL_IMAGE`) | Named volume `mysql-data`, init script for Bitrix user | -| nginx | `nginx:stable` | HTTPS, envsubst template, Bitrix URL rewrite | +| nginx | `nginx:1.27.4-bookworm` (override via `NGINX_IMAGE`) | HTTPS, envsubst template, Bitrix URL rewrite | | SSL | [mkcert](https://github.com/FiloSottile/mkcert) | Certs in `docker/nginx/certs/` (gitignored) | | Orchestration | Docker Compose v2 | `compose.yaml`, healthchecks, `depends_on` conditions | -**PHP extensions installed by default:** `bcmath`, `exif`, `gd`, `intl`, `mysqli`, `pdo_mysql`, `soap`, `zip`. +**PHP extensions installed by default:** `bcmath`, `exif`, `gd`, `intl`, `mbstring`, `mysqli`, `pdo_mysql`, `soap`, `zip`. -**Additional extensions** via `PHP_EXTRA_EXTENSIONS` in `.env` (space-separated). `.env.example` includes `mbstring` (required by Bitrix). You can add more, e.g. `mbstring imagick redis xdebug`. +**Optional extensions** via `PHP_EXTRA_EXTENSIONS` in `.env` (space-separated), e.g. `imagick redis xdebug`. ## Project Structure @@ -83,9 +83,10 @@ cp .env.example .env | `DOMAIN` | `bitrix.local` | Local HTTPS domain (must match hosts file and cert name) | | `HTTP_PORT` | `80` | Host port mapped to nginx HTTP | | `HTTPS_PORT` | `443` | Host port mapped to nginx HTTPS | +| `NGINX_IMAGE` | `nginx:1.27.4-bookworm` | Pinned nginx image tag | | `TIMEZONE` | `Europe/Moscow` | PHP and MySQL timezone | | `PHP_VERSION` | `8.3` | PHP-FPM image tag (Docker build arg) | -| `PHP_EXTRA_EXTENSIONS` | `mbstring` | Space-separated extra PHP extensions, e.g. `mbstring imagick redis xdebug` | +| `PHP_EXTRA_EXTENSIONS` | _(empty)_ | Space-separated optional PHP extensions, e.g. `imagick redis xdebug` | | `UID` | `1000` | Linux/macOS user ID inside PHP container | | `GID` | `1000` | Linux/macOS group ID inside PHP container | | `XDEBUG_MODE` | `off` | Xdebug mode when `xdebug` is installed (`off`, `debug`, `develop`, …) | @@ -100,7 +101,7 @@ Example `.env` for a custom domain with extra PHP extensions: ```dotenv DOMAIN=my-site.local MYSQL_PASSWORD=change-me -PHP_EXTRA_EXTENSIONS=mbstring imagick redis xdebug +PHP_EXTRA_EXTENSIONS=imagick redis xdebug XDEBUG_MODE=debug ``` @@ -252,7 +253,7 @@ make clean # stop containers and remove Docker volumes ## PHP and nginx Defaults -PHP limits in `docker/php/php.ini` (oriented toward large Bitrix backups): +PHP limits in `docker/php/php.ini` (oriented toward large Bitrix backups). Timezone is set at container start from `TIMEZONE` in `.env` via `docker/php/docker-entrypoint.sh`. - `memory_limit = 512M` - `upload_max_filesize = 1024M` @@ -286,7 +287,7 @@ On first start with an empty volume, `docker/mysql/initdb/01-bitrix-user.sh`: The base PHP image stays small. Enable extra extensions only when needed: ```dotenv -PHP_EXTRA_EXTENSIONS=mbstring imagick redis xdebug +PHP_EXTRA_EXTENSIONS=imagick redis xdebug XDEBUG_MODE=debug ``` diff --git a/compose.yaml b/compose.yaml index 96166de..b5a28dd 100644 --- a/compose.yaml +++ b/compose.yaml @@ -1,11 +1,11 @@ services: nginx: - image: nginx:stable + image: ${NGINX_IMAGE:-nginx:1.27.4-bookworm} container_name: ${PROJECT_NAME:-bitrix-local}-nginx restart: unless-stopped depends_on: php: - condition: service_started + condition: service_healthy environment: DOMAIN: ${DOMAIN:-bitrix.local} NGINX_ENVSUBST_TEMPLATE_SUFFIX: .template @@ -43,6 +43,12 @@ services: working_dir: /var/www/html expose: - "9000" + healthcheck: + test: ["CMD-SHELL", "php-fpm -t || exit 1"] + interval: 10s + timeout: 5s + retries: 5 + start_period: 10s mysql: image: ${MYSQL_IMAGE:-mysql:8.0.36} diff --git a/docker/php/.dockerignore b/docker/php/.dockerignore new file mode 100644 index 0000000..8158478 --- /dev/null +++ b/docker/php/.dockerignore @@ -0,0 +1,4 @@ +README* +*.md +.git +.gitignore diff --git a/docker/php/Dockerfile b/docker/php/Dockerfile index 7fa1438..64a6df9 100644 --- a/docker/php/Dockerfile +++ b/docker/php/Dockerfile @@ -20,7 +20,7 @@ RUN set -eux; \ rm -rf /var/lib/apt/lists/* RUN set -eux; \ - curl -fsSL https://github.com/mlocati/docker-php-extension-installer/releases/latest/download/install-php-extensions \ + curl -fsSL https://github.com/mlocati/docker-php-extension-installer/releases/download/2.11.12/install-php-extensions \ -o /usr/local/bin/install-php-extensions; \ chmod +x /usr/local/bin/install-php-extensions; \ IPE_GD_WITHOUTAVIF=1 install-php-extensions \ @@ -28,6 +28,7 @@ RUN set -eux; \ exif \ gd \ intl \ + mbstring \ mysqli \ pdo_mysql \ soap \ @@ -44,5 +45,10 @@ RUN set -eux; \ COPY php.ini /usr/local/etc/php/conf.d/99-bitrix.ini COPY opcache.ini /usr/local/etc/php/conf.d/99-opcache.ini +COPY docker-entrypoint.sh /usr/local/bin/bitrix-entrypoint.sh +RUN chmod +x /usr/local/bin/bitrix-entrypoint.sh WORKDIR /var/www/html + +ENTRYPOINT ["bitrix-entrypoint.sh"] +CMD ["php-fpm"] diff --git a/docker/php/docker-entrypoint.sh b/docker/php/docker-entrypoint.sh new file mode 100644 index 0000000..2a5a66e --- /dev/null +++ b/docker/php/docker-entrypoint.sh @@ -0,0 +1,8 @@ +#!/bin/bash +set -e + +if [ -n "${TZ:-}" ]; then + printf 'date.timezone = %s\n' "$TZ" > /usr/local/etc/php/conf.d/98-timezone.ini +fi + +exec docker-php-entrypoint "$@" diff --git a/docker/php/php.ini b/docker/php/php.ini index 3b2de33..50fcce5 100644 --- a/docker/php/php.ini +++ b/docker/php/php.ini @@ -1,5 +1,3 @@ -date.timezone = ${TZ} - short_open_tag = On expose_php = Off diff --git a/scripts/doctor.sh b/scripts/doctor.sh index 693e7ad..7b2c4b0 100644 --- a/scripts/doctor.sh +++ b/scripts/doctor.sh @@ -4,7 +4,7 @@ set -euo pipefail if [ -f .env ]; then set -a # shellcheck disable=SC1091 - . ./.env + source <(grep -vE '^(UID|GID)=' .env) set +a fi @@ -74,4 +74,11 @@ case "$(uname -s 2>/dev/null || echo unknown)" in ;; esac +PHP_EXTRA_EXTENSIONS="${PHP_EXTRA_EXTENSIONS:-}" +XDEBUG_MODE="${XDEBUG_MODE:-off}" +if [[ " ${PHP_EXTRA_EXTENSIONS} " == *" xdebug "* ]] && [ "$XDEBUG_MODE" = "off" ]; then + echo "Warning: xdebug is in PHP_EXTRA_EXTENSIONS but XDEBUG_MODE=off." + echo " Set XDEBUG_MODE=debug in .env and rebuild: docker compose build php" +fi + exit "$STATUS"