Почему PHP-FPM возвращает 404 в Docker-конфигурации Laravel
Решение проблемы 404 ошибок при настройке PHP-FPM с Laravel в Docker. Пошаговое исправление конфигурации nginx и docker-compose для корректной работы API.
Почему PHP-FPM возвращает 404 для всех запросов в моей Docker‑конфигурации?
У меня есть три контейнера:
- nginx
- backend: php‑fpm + Laravel
- frontend: Vue.js + nginx
Я настроил так, чтобы все запросы на /api/* перенаправлялись на backend в Laravel, а остальные запросы — на frontend. Frontend работает нормально, страницы открываются, но backend возвращает 404 для всех запросов.
Где я допустил ошибку в конфигурации?
# docker-compose.yml
services:
backend:
build:
context: ./backend
dockerfile: Dockerfile
args:
HTTP_PROXY: http://172.17.0.1:8118
HTTPS_PROXY: http://172.17.0.1:8118
NO_PROXY: localhost,127.0.0.1,::1,host.docker.internal,172.17.0.1,db,redis,backend,mailhog,frontend,web,adminer
http_proxy: http://172.17.0.1:8118
https_proxy: http://172.17.0.1:8118
no_proxy: localhost,127.0.0.1,::1,host.docker.internal,172.17.0.1,db,redis,backend,mailhog,frontend,web,adminer
extra_hosts:
- "host.docker.internal:host-gateway"
container_name: jdasia-backend
env_file:
- ./docker/.env.docker
volumes:
- ./backend:/var/www/html
depends_on:
- db
- redis
environment:
XDEBUG_MODE: ${XDEBUG_MODE:-develop,debug}
XDEBUG_CLIENT_HOST: ${XDEBUG_CLIENT_HOST:-host.docker.internal}
XDEBUG_CLIENT_PORT: ${XDEBUG_CLIENT_PORT:-9003}
http_proxy: http://172.17.0.1:8118
https_proxy: http://172.17.0.1:8118
no_proxy: localhost,127.0.0.1,::1,host.docker.internal,172.17.0.1,db,redis,backend,mailhog,frontend,web,adminer
HTTP_PROXY: http://172.17.0.1:8118
HTTPS_PROXY: http://172.17.0.1:8118
NO_PROXY: localhost,127.0.0.1,::1,host.docker.internal,172.17.0.1,db,redis,backend,mailhog,frontend,web,adminer
extra_hosts:
- "host.docker.internal:host-gateway"
nginx:
image: nginx:stable-alpine
container_name: jdasia-nginx
ports:
- "80:80"
- "443:443"
volumes:
- ./infra/nginx/default.conf:/etc/nginx/conf.d/default.conf:ro
- ./infra/nginx/certs:/etc/nginx/certs:ro
depends_on:
- backend
- frontend
frontend:
build:
context: ./frontend
dockerfile: Dockerfile
args:
HTTP_PROXY: http://172.17.0.1:8118
HTTPS_PROXY: http://172.17.0.1:8118
NO_PROXY: localhost,127.0.0.1,::1,host.docker.internal,172.17.0.1,db,redis,backend,mailhog,frontend,web,adminer
http_proxy: http://172.17.0.1:8118
https_proxy: http://172.17.0.1:8118
no_proxy: localhost,127.0.0.1,::1,host.docker.internal,172.17.0.1,db,redis,backend,mailhog,frontend,web,adminer
extra_hosts:
- "host.docker.internal:host-gateway"
container_name: jdasia-frontend
volumes:
- ./frontend:/app
- /app/node_modules
- ./infra/nginx/certs:/etc/nginx/certs:ro
environment:
- NODE_ENV=development
- HTTP_PROXY=http://172.17.0.1:8118
- HTTPS_PROXY=http://172.17.0.1:8118
- NO_PROXY=localhost,127.0.0.1,::1,host.docker.internal,172.17.0.1,db,redis,backend,mailhog,frontend,web,adminer
- http_proxy=http://172.17.0.1:8118
- https_proxy=http://172.17.0.1:8118
- no_proxy=localhost,127.0.0.1,::1,host.docker.internal,172.17.0.1,db,redis,backend,mailhog,frontend,web,adminer
depends_on:
- backend
volumes:
db_data:
# ./backend/Dockerfile
FROM php:8.2-fpm-trixie
# Proxy support
ARG HTTP_PROXY
ARG HTTPS_PROXY
ARG NO_PROXY
# Only set proxy if explicitly provided
ENV http_proxy=${HTTP_PROXY:-} \
https_proxy=${HTTPS_PROXY:-} \
no_proxy=${NO_PROXY:-} \
ALL_PROXY=${HTTP_PROXY:-}
# Install system deps (Debian/apt)
RUN apt-get update \
&& DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
git curl unzip zip \
tcpdump mc htop \
libpq-dev libicu-dev libzip-dev libonig-dev \
pkg-config autoconf make g++ \
&& docker-php-ext-configure intl \
&& docker-php-ext-install pdo pdo_pgsql mbstring intl zip opcache \
&& if [ -n "$HTTP_PROXY" ]; then pecl config-set http_proxy "$HTTP_PROXY"; fi \
&& pecl channel-update pecl.php.net || true \
&& (pecl install -o -f redis xdebug \
|| (echo "PECL direct install failed, trying tarballs" \
&& curl -fsSL --connect-timeout 20 --retry 5 ${HTTPS_PROXY:+--proxy "$HTTPS_PROXY"} https://pecl.php.net/get/redis-6.0.2.tgz -o /tmp/redis.tgz \
&& curl -fsSL --connect-timeout 20 --retry 5 ${HTTPS_PROXY:+--proxy "$HTTPS_PROXY"} https://pecl.php.net/get/xdebug-3.3.2.tgz -o /tmp/xdebug.tgz \
&& pecl install /tmp/redis.tgz /tmp/xdebug.tgz)) \
&& docker-php-ext-enable redis xdebug \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
# Composer
COPY --from=composer:2 /usr/bin/composer /usr/bin/composer
WORKDIR /var/www/html
# Copy composer files first
COPY composer.json composer.lock ./
# Install PHP dependencies without running scripts (artisan not copied yet)
RUN composer install --no-dev --optimize-autoloader --no-scripts
# Copy application files (excluding vendor and node_modules)
COPY . .
RUN rm -rf node_modules
# Opcache recommended settings
ENV PHP_OPCACHE_VALIDATE_TIMESTAMPS=1 \
PHP_OPCACHE_MAX_ACCELERATED_FILES=20000 \
PHP_OPCACHE_MEMORY_CONSUMPTION=128 \
PHP_OPCACHE_MAX_WASTED_PERCENTAGE=10
# Xdebug configuration (copied into conf.d)
COPY 99-xdebug.ini /usr/local/etc/php/conf.d/99-xdebug.ini
CMD ["php-fpm"]
# ./infra/nginx/default.conf
server {
listen 80;
server_name localhost;
root /var/www/html/public;
index index.php index.html;
# PHP-FPM handler
location ~ \.php$ {
include /etc/nginx/fastcgi_params;
fastcgi_pass backend:9000;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_index index.php;
}
# Frontend (Vue.js SPA) - все остальные запросы
location / {
proxy_pass http://frontend:80;
}
# Backend API
location /api/ {
try_files $uri $uri/ /index.php?$query_string;
}
client_max_body_size 20m;
}
# HTTPS server
server {
listen 443 ssl;
http2 on;
server_name localhost;
ssl_certificate /etc/nginx/certs/dev.crt;
ssl_certificate_key /etc/nginx/certs/dev.key;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
index index.php index.html;
# Frontend (Vue.js SPA) - все остальные запросы
location / {
proxy_pass http://frontend:80;
}
# Backend API - send directly to PHP without filesystem checks
location /api/ {
proxy_pass http://backend:9000;
}
client_max_body_size 20m;
}
Основная проблема в вашей конфигурации заключается в несоответствии путей между точкой монтирования в docker-compose.yml и корневой директорией в nginx‑конфигурации.
Ваша текущая конфигурация указывает nginx искать файлы в /var/www/html/public, но в контейнере бэкенда файлы монтируются в /var/www/html. Laravel требует, чтобы веб‑сервер обращался именно к директории public, а не к корню проекта.
# docker-compose.yml
volumes:
- ./backend:/var/www/html # Файлы в /var/www/html
# nginx.conf
root /var/www/html/public; # Но nginx ищет в /var/www/html/public
Содержание
- Основные причины 404 ошибок
- Исправление конфигурации
- Настройка nginx для Laravel
- Проверка прав доступа
- Отладка и диагностика
Основные причины 404 ошибок
1. Несоответствие путей монтирования
Как видно из вашего docker-compose.yml, бэкенд монтируется в /var/www/html, но nginx пытается обслуживать запросы из /var/www/html/public. Laravel требует, чтобы веб‑сервер обращался именно к директории public.
According to Stack Overflow discussions, это самая распространенная причина 404 ошибок в Docker‑конфигурациях Laravel.
2. Неправильная конфигурация try_files
Ваш HTTPS‑сервер не имеет корневой директории, что вызывает проблемы с обработкой статических файлов.
3. Отсутствие правильной обработки PHP‑файлов
Конфигурация location для PHP‑файлов может быть неполной для корректной работы с Laravel.
Исправление конфигурации
1. docker-compose.yml
Убедитесь, что корневая директория Laravel монтируется правильно:
backend:
volumes:
- ./backend:/var/www/html # Правильно
2. nginx default.conf
Добавьте корневую директорию для HTTPS‑сервера и исправьте конфигурацию:
# HTTP сервер
server {
listen 80;
server_name localhost;
root /var/www/html/public; # Указываем правильную директорию
index index.php index.html;
# Frontend (Vue.js SPA)
location / {
proxy_pass http://frontend:80;
}
# Backend API - Laravel маршрутизация
location /api/ {
try_files $uri $uri/ /index.php?$query_string;
}
# Обработка PHP файлов
location ~ \.php$ {
include /etc/nginx/fastcgi_params;
fastcgi_pass backend:9000;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_index index.php;
fastcgi_param PATH_INFO $fastcgi_path_info;
}
client_max_body_size 20m;
}
# HTTPS сервер
server {
listen 443 ssl;
http2 on;
server_name localhost;
root /var/www/html/public; # ДОБАВЛЕНО корневая директория
index index.php index.html;
# Frontend (Vue.js SPA)
location / {
proxy_pass http://frontend:80;
}
# Backend API - Laravel маршрутизация
location /api/ {
try_files $uri $uri/ /index.php?$query_string;
}
# Обработка PHP файлов
location ~ \.php$ {
include /etc/nginx/fastcgi_params;
fastcgi_pass backend:9000;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_index index.php;
fastcgi_param PATH_INFO $fastcgi_path_info;
}
client_max_body_size 20m;
}
Настройка nginx для Laravel
Правильная конфигурация location для PHP
Согласно исследованиям Laravel.io, для корректной работы Laravel с nginx необходима следующая конфигурация:
location ~ \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass backend:9000;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
}
Конфигурация try_files для API
Для корректной обработки API‑запросов в Laravel используйте:
location /api/ {
try_files $uri $uri/ /index.php?$query_string;
}
Проверка прав доступа
Убедитесь, что веб‑сервер имеет правильные права доступа к директориям Laravel:
# В контейнере backend
docker exec jdasia-backend chown -R www-data:www-data /var/www/html
docker exec jdasia-backend chmod -R 755 /var/www/html/storage
docker exec jdasia-backend chmod -R 755 /var/www/html/bootstrap/cache
Отладка и диагностика
1. Проверка логов
Проверьте логи nginx и PHP‑FPM:
# Логи nginx
docker logs jdasia-nginx
# Логи PHP‑FPM
docker logs jdasia-backend
# Логи ошибок PHP‑FPM
docker exec jdasia-backend tail /var/log/php8.2-fpm.log
2. Проверка существования файлов
Убедитесь, что файлы существуют в правильных директориях:
# Проверьте содержимое контейнера backend
docker exec jdasia-backend ls -la /var/www/html/
# Проверьте наличие public директории
docker exec jdasia-backend ls -la /var/www/html/public/
3. Проверка прав доступа к файлам
docker exec jdasia-backend ls -la /var/www/html/public/index.php
According to Server Fault, часто проблема заключается в том, что nginx не может найти файлы, которые существуют в PHP‑контейнере, но не смонтированы в nginx‑контейнер.
Источники
- Laravel docker-compose 404 not found Nginx - Stack Overflow
- Laravel, Docker and Nginx: 404 for all files in /public folder - Stack Overflow
- Nginx Laravel routing shows 404 - Laravel.io
- 404 Not Found - Nginx - docker compose - Unix & Linux Stack Exchange
Заключение
Основная проблема в вашей конфигурации — несоответствие путей между монтированием в docker-compose.yml и корневой директорией в nginx. Для решения:
- Убедитесь, что nginx
rootуказывает на/var/www/html/public. - Добавьте корневую директорию для HTTPS‑сервера.
- Проверьте права доступа к файлам.
- Используйте правильную конфигурацию
try_filesдля Laravel. - Настройте правильную обработку PHP‑файлов с
fastcgi_param SCRIPT_FILENAME.
После этих изменений все запросы к /api/* должны корректно обрабатываться вашим Laravel бэкендом.