背景
最近在使用 docker
复现一个钓鱼网站的时候,在进行 docker
镜像的搭建时,选择了将 PHP
、Nginx
和 mysql
三个服务放在三个不同的镜像中,使用 docker-compose
进行相互通信来完成网站的复现搭建,但是在复现的过程中网站可以访问,但是 js、css、图片
等静态资源加载时, Nginx
会返回 404
找不到资源的错误。
问题及分析
docker启动的Nginx配置访问静态资源,访问失败404 ?
GET http://localhost:8080/Public/bootstrap/css/bootstrap.min.css net::ERR_ABORTED 404 (Not Found)
GET http://localhost:8080/Public/dist/css/AdminLTE.min.css net::ERR_ABORTED 404 (Not Found)
一般这种情况我们需要先考虑以下两点:
- 配置文件中的
访问路径
有问题 - 对应
文件不存在
但是按照 Nginx
配置文件访问静态资源,路径是正确的,PHP
容器中对应的文件也存在应该是没问题的,但浏览器在加载时始终显示404,而且网页是可以访问到的。
经过问题排查,发现原来Nginx是docker启动的,访问的静态资源必须是在docker容器里面的才可以,否则肯定找不到。PHP
web服务容器中的网站目录并没有挂载到 Nginx
容器里面。而且 Nginx
的 conf
配置文件进行路径映射的时候,映射的是容器里的文件路径。
server {
listen 80;
server_name loalhost;
root /var/www/html;
index index.php index.html index.htm;
# 静态文件直接从本地Nginx容器获取
location / {
index index.php index.html admin.php;
try_files $uri $uri/ /index.php?$query_string;
autoindex off;
}
# 以php结尾的请求则转发给php容器进行处理
location ~ \.php(.*)$ {
fastcgi_pass php:9000;
fastcgi_index index.php;
fastcgi_split_path_info ^((?U).+\.php)(/?.+)$;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_param PATH_TRANSLATED $document_root$fastcgi_path_info;
include fastcgi_params;
}
location ~ /\.ht {
deny all;
}
}
解决办法
1.将资源挂载到 Ngnix
容器直接从容器获取:这里我创建了一个共享卷 website_code
将其分别挂在到 PHP
和 Nginx
容器,具体 docker-compose
文件如下所示,这里为了防止 Nginx
对网站代码进行修改,我们设置了 挂载共享卷只读
,而 PHP
容器为可读可写(网站容器本身)。【推荐】
# edit by aurora
services:
nginx:
image: nginx:1.16.1
container_name: nginx
ports:
- "8080:80"
volumes:
- ./nginx.conf:/etc/nginx/conf.d/default.conf
- website_code:/var/www/website:ro # 挂载共享卷为只读
depends_on:
- php
networks:
- app-network
php:
build:
context: .
dockerfile: Dockerfile
container_name: php
environment:
MYSQL_DATABASE: mywebsite
MYSQL_USER: root
MYSQL_PASSWORD: root
MYSQL_HOST: mysql
MYSQL_PORT: 3306
volumes:
- website_code:/var/www/website # 挂载共享卷为读写
networks:
- app-network
mysql:
image: mysql:5.7
container_name: mysql
volumes:
- mysql_data:/var/lib/mysql
- ./init.sql:/docker-entrypoint-initdb.d/init.sql
environment:
MYSQL_ROOT_PASSWORD: root
networks:
- app-network
volumes:
mysql_data:
website_code:
networks:
app-network:
driver: bridge
2.修改 Nginx
配置文件,将静态资源请求也转发到 PHP
容器进行处理。(可能会存在权限问题,需要自己去修改php配置文件,尝试修改php.ini文件中的security.limit_extensions设置,会存在一定安全问题)
在配置文件中添加如下代码,这部分只是一个示例,按照需求去更改
location ~* \.(css|js|png|jpg|jpeg|gif|ico|html)$ {
fastcgi_pass php:9000;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
注意事项
- 如果是docker启动的单独的
Nginx
,一定要注意映射目录,Nginx只能访问到自己容器内的目录,所以,在启动容器时就需要进行对应目录挂载。 - 在两个容器之间进行目录共享时,需要注意以下两点
- 共享卷:创建共享卷,并将其挂载到
PHP和Nginx
容器中。对于Nginx
容器,使用只读模式(ro
),避免修改代码。 - 避免本地挂载:没有本地代码目录挂载到 PHP 容器,避免了覆盖容器内的代码。
- 共享卷:创建共享卷,并将其挂载到
- 在进行网站
Docker
镜像的搭建时出于安全以及成功访问考虑,需要给网站目录进行权限设定。