Настройка связки Nginx и PHP в контейнерах Docker
В данном материале рассмотрены способы организации работы веб-сервера на базе Nginx и PHP в среде Docker. Основное внимание уделено эффективной связке двух контейнеров, а также альтернативные подходы. Каждый вариант сопровождается пояснениями и разбором возможных трудностей.
Основное решение: связка двух контейнеров через Docker Compose
Как настроить Nginx и PHP-FPM в отдельных контейнерах, объединённых одной сетью?
Данный подход считается наиболее гибким и масштабируемым. Nginx выступает в роли фронтенда, передавая запросы на PHP-FPM контейнер. Для управления несколькими контейнерами используется Docker Compose.
version: '3.8'
services:
nginx:
image: nginx:alpine
ports:
- "80:80"
volumes:
- ./html:/usr/share/nginx/html
- ./nginx/default.conf:/etc/nginx/conf.d/default.conf
depends_on:
- php
php:
image: php:8.2-fpm
volumes:
- ./html:/var/www/html
Docker nginx php (docker для nginx и php)
Файл nginx/default.conf содержит настройки сервера:
server {
listen 80;
server_name localhost;
root /var/www/html;
index index.php index.html;
location ~ \.php$ {
fastcgi_pass php:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}
При запуске docker-compose up -d оба контейнера стартуют в одной сети и могут обмениваться данными через имя сервиса (php).
Типичная проблема 502 Bad Gateway возникает, если PHP-FPM не отвечает или неправильно указан адрес. Решение: проверить, что контейнер php запущен и слушает порт 9000. Команда docker logs php покажет ошибки. Другая причина – неправильный SCRIPT_FILENAME. Нужно убедиться, что корневая директория совпадает с монтированным томом.
Проблема прав доступа: файлы внутри контейнера могут принадлежать root. Для корректной работы PHP рекомендуется установить пользователя и группу в файле конфигурации PHP-FPM (www.conf).
Вариант 1: Единый контейнер с супервизором
Как объединить Nginx и PHP-FPM в одном контейнере? Для управления двумя процессами используется supervisord. Подход удобен для простых сценариев, но менее гибкий и не соответствует принципам микросервисов.
FROM ubuntu:22.04
RUN apt-get update && apt-get install -y nginx php-fpm supervisor
COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf
CMD ["/usr/bin/supervisord", "-c", "/etc/supervisor/supervisord.conf"]
Файл supervisord.conf:
[program:nginx]
command = /usr/sbin/nginx -g "daemon off;"
[program:php-fpm]
command = /usr/sbin/php-fpm -F
Проблема: управление логами и перезапуск процессов усложняется. При сбое одного процесса контейнер может продолжать работу в нерабочем состоянии. Рекомендуется использование healthcheck для мониторинга.
Вариант 2: Использование Alpine образов для уменьшения размера
Как минимизировать размер итогового образа? Применение официальных Alpine образов nginx:alpine и php:8.2-fpm-alpine сокращает объём загрузки. Пример docker-compose с Alpine:
services:
nginx:
image: nginx:alpine
php:
image: php:8.2-fpm-alpine
# Дополнительная установка расширений через Dockerfile
Alpine использует musl вместо glibc, что может приводить к несовместимости некоторых PHP-расширений, требующих glibc. Решение: установить необходимые пакеты через apk, либо использовать образ на основе Debian.
Вариант 3: Использование Unix-сокета вместо TCP
Как повысить производительность на одной машине? PHP-FPM может слушать Unix-сокет, а не TCP-порт. В docker-compose контейнеры обмениваются через общий том с сокетом.
# php/Dockerfile
RUN mkdir /run/php
# php-fpm.conf
listen = /run/php/php8.2-fpm.sock
# nginx default.conf
fastcgi_pass unix:/var/run/php/php8.2-fpm.sock;
Том должен быть общим:
volumes:
- ./php-socket:/run/php
Права доступа к сокету: Nginx должен иметь право на чтение сокета. Обычно группа www-data или 777. Необходимо настроить пользователя в php-fpm.
Вариант 4: Многосайтовая конфигурация с отдельными хостами
Как обслуживать несколько сайтов на одном экземпляре Nginx? Используется конфигурация виртуальных хостов. В Docker Compose можно смонтировать несколько конфигов.
volumes:
- ./nginx/sites-enabled:/etc/nginx/conf.d
Каждый файл конфигурации определяет свой server_name.
Ошибка 404 при обращении к другим сайтам: убедиться, что файлы сайтов доступны в монтируемых томах.
Расширенные примеры
Дополнительные сценарии использования Docker с Nginx и PHP.
Dockerfile для PHP с расширениями и кастомной конфигурацией
FROM php:8.2-fpm-alpine
RUN apk add --no-cache \
freetype-dev \
libjpeg-turbo-dev \
libpng-dev \
libzip-dev \
zip \
unzip \
&& docker-php-ext-configure gd --with-freetype --with-jpeg \
&& docker-php-ext-install -j$(nproc) gd pdo_mysql zip \
&& docker-php-ext-enable opcache
COPY ./php.ini /usr/local/etc/php/conf.d/custom.ini
Пример php.ini:
upload_max_filesize = 20M
post_max_size = 20M
memory_limit = 256M
opcache.enable=1
opcache.memory_consumption=128
Результат: образ с готовым набором расширений и оптимизированной производительностью.
Многоконтейнерное приложение с Nginx, PHP и MySQL через Docker Compose
version: '3.8'
services:
nginx:
image: nginx:alpine
ports:
- "80:80"
volumes:
- ./app:/var/www/html
- ./nginx.conf:/etc/nginx/conf.d/default.conf
depends_on:
- php
php:
build: ./php
volumes:
- ./app:/var/www/html
environment:
- DB_HOST=mysql
- DB_USER=app
- DB_PASS=secret
mysql:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: rootpass
MYSQL_DATABASE: app
MYSQL_USER: app
MYSQL_PASSWORD: secret
volumes:
- mysql_data:/var/lib/mysql
volumes:
mysql_data:
Запуск: docker-compose up -d. Приложение может использовать переменные окружения для подключения к MySQL.
Настройка healthcheck для PHP-FPM контейнера
healthcheck:
test: ["CMD", "php-fpm-healthcheck"]
interval: 30s
timeout: 10s
retries: 3
Для этого требуется утилита php-fpm-healthcheck, которую можно установить через Dockerfile:
RUN git clone https://github.com/renatomefi/php-fpm-healthcheck.git /usr/local/bin/php-fpm-healthcheck
Healthcheck позволяет автоматически перезапускать контейнер при обнаружении неработоспособности.
Использование Docker secrets для хранения паролей
services:
php:
secrets:
- db_password
secrets:
db_password:
file: ./secrets/db_password.txt
В PHP пароль можно получить через чтение файла /run/secrets/db_password.
Настройка Nginx как reverse proxy для нескольких PHP-сервисов
Пример конфигурации для балансировки нагрузки:
upstream php_backend {
server php1:9000;
server php2:9000;
}
server {
location ~ \.php$ {
fastcgi_pass php_backend;
}
}
Такой подход используется для горизонтального масштабирования PHP-обработчиков.
Объединение логов Nginx и PHP в общий volume
volumes:
- ./logs/nginx:/var/log/nginx
- ./logs/php:/var/log/php
В конфиге PHP (www.conf) нужно указать путь к логу:
access.log = /var/log/php/access.log
error.log = /var/log/php/error.log
После запуска в ./logs появятся файлы access.log и error.log.