如何通过Docker配合宿主机Nginx正确提供Django媒体文件访问服务
问题根因
- 宿主机Nginx的
/media/规则同时配置了proxy_pass和alias,属于配置冲突,Nginx无法判断是转发请求给Django还是读取本地文件 alias /app/media_cdn/指向的是Docker容器内部的路径,宿主机上不存在该路径,就算去掉proxy_pass也无法找到对应文件- 如果你未在Django路由中配置媒体文件访问规则,Django的runserver默认不会处理媒体文件请求,就算转发到8400端口也会返回404
解决方案(推荐优先使用方案一,性能更高更稳定)
方案一:宿主机Nginx直接读取媒体文件(生产环境推荐)
- 首先查询Docker命名卷
media-cdn-data在宿主机的实际挂载路径,执行命令:docker volume inspect media-cdn-data
返回结果中的Mountpoint字段就是媒体文件在宿主机的实际存储路径,通常格式类似/var/lib/docker/volumes/[你的项目名]_media-cdn-data/_data - 替换宿主机Nginx的
/media/配置,删除原有冲突项,最终配置如下:
location /media/ { alias 刚才查到的Mountpoint路径/; expires 30d; add_header Cache-Control "public, immutable"; }
- 权限校验:确保Nginx运行用户(通常是www-data)有该路径的读取权限,若出现权限不足可以执行命令赋予目录读权限:
chmod -R o+rx 刚才查到的Mountpoint路径
方案二:请求转发给Django处理(仅适合临时调试使用)
- 先在Django项目根路由
urls.py中添加媒体文件路由规则:
from django.conf import settings from django.conf.urls.static import static urlpatterns = [ # 原有路由保持不变 ] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
- 修改宿主机Nginx的
/media/配置,删除alias项,避免和proxy_pass冲突,注意proxy_pass末尾不要加斜杠,否则会丢失/media/前缀:
location /media/ { proxy_pass http://127.0.0.1:8400; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; }
生效与排查
- 修改Nginx配置后先执行
nginx -t校验配置语法是否正确,再执行nginx -s reload重载配置 - 可以查看Nginx错误日志
/var/log/nginx/error.log确认具体报错原因,快速定位问题 - 进入容器确认媒体文件确实存在:
docker exec -it [你的backend容器ID/名称] ls /app/media_cdn
内容的提问来源于stack exchange,提问作者Erlich Bachman
相关产品推荐
相关产品推荐

