Docker部署Apache/PHP时子目录访问返回404错误求助
咱们先拆解下核心矛盾:XAMPP/MAMP能正常访问/project_1/public_html,但Docker里只能看到/project_1/的目录索引,却访问不了子目录。这大概率是Docker容器内的权限配置、Apache文档根设置,或者路径映射细节出了问题,咱们一步步来排查:
1. 先看Apache错误日志(最直接的定位方式)
别瞎猜,先看容器里的Apache错误日志,它会明确告诉你404的原因是文件不存在、权限不足还是配置错误。
- 如果你用的是官方
httpd镜像,日志路径是/usr/local/apache2/logs/error.log,执行命令进入容器查看:docker exec -it [你的容器名称/ID] tail -f /usr/local/apache2/logs/error.log - 如果你用的是
php:apache这类镜像,日志通常在/var/log/apache2/error.log:docker exec -it [你的容器名称/ID] tail -f /var/log/apache2/error.log
比如如果日志显示Permission denied: access to /project_1/public_html/index.html,那就是权限问题;如果显示File does not exist: /usr/local/apache2/htdocs/project_1/public_html,那就是挂载路径或者DocumentRoot配置错了。
2. 验证挂载路径与DocumentRoot配置
检查docker-compose.yml的挂载规则
确保你把本地的Work目录挂载到了Apache的文档根目录,比如:
services: apache: image: httpd:2.4 volumes: # 本地Work目录 → 容器内Apache的文档根 - ./Work:/usr/local/apache2/htdocs - ./httpd.conf:/usr/local/apache2/conf/httpd.conf ports: - "80:80"
这里要注意:不同Apache镜像的默认文档根可能不一样,官方httpd是/usr/local/apache2/htdocs,而php:apache是/var/www/html,别搞混了!
检查httpd.conf的DocumentRoot与Directory配置
确保DocumentRoot指向你挂载的路径,并且对应的Directory块允许访问子目录:
# 比如挂载到/usr/local/apache2/htdocs的话 DocumentRoot "/usr/local/apache2/htdocs" <Directory "/usr/local/apache2/htdocs"> # 允许目录索引、跟随符号链接 Options Indexes FollowSymLinks # 允许.htaccess生效 AllowOverride All # 允许所有访问 Require all granted </Directory>
如果Directory块里没有FollowSymLinks,或者Require all denied,那访问子目录就会被拦截。
3. 容器内文件权限问题(最常见的坑)
XAMPP/MAMP是用你主机的用户运行Apache的,所以文件权限和主机一致;但Docker里的Apache默认用www-data用户运行,它的UID/GID和你主机用户不一样,导致容器内的Work/project_1/public_html目录没有读取权限,自然返回404。
解决方法:
方法一:在Dockerfile中修改权限
如果是自定义镜像,在Dockerfile里添加:
# 假设挂载路径是/usr/local/apache2/htdocs RUN chown -R www-data:www-data /usr/local/apache2/htdocs
方法二:挂载时指定主机用户UID/GID
在docker-compose.yml里添加user字段,用你主机当前用户的UID和GID(可以用id -u和id -g命令查看):
services: apache: image: httpd:2.4 user: "1000:1000" # 替换成你的UID:GID volumes: - ./Work:/usr/local/apache2/htdocs - ./httpd.conf:/usr/local/apache2/conf/httpd.conf
4. 项目内.htaccess的重写规则问题
如果你的项目里有.htaccess文件,它的重写规则可能是基于XAMPP/MAMP的环境(比如把public_html作为文档根),现在整个Work是文档根,路径结构变了,规则就失效了。
比如原来的.htaccess可能有:
RewriteEngine On RewriteRule ^(.*)$ index.php/$1 [L]
现在需要添加RewriteBase指定当前路径:
RewriteEngine On RewriteBase /project_1/public_html/ RewriteRule ^(.*)$ index.php/$1 [L]
5. 最后验证容器内的文件是否存在
进入容器,直接查看路径是否正确:
docker exec -it [你的容器名称/ID] ls -l /usr/local/apache2/htdocs/project_1/public_html
如果显示文件列表,说明路径没问题;如果提示No such file or directory,那就是挂载路径写错了,或者本地Work目录下的项目结构不对。
内容的提问来源于stack exchange,提问作者Danielli

