Nginx 无法在数字海洋上提供 django 静态或媒体文件
Posted
技术标签:
【中文标题】Nginx 无法在数字海洋上提供 django 静态或媒体文件【英文标题】:Nginx failing to serve django static or media files on digital ocean 【发布时间】:2021-07-25 06:12:39 【问题描述】:当我将 dockerised django 应用程序部署到数字海洋时,我在提供静态文件和媒体文件时遇到了问题。我在这里阅读了许多类似的问题,但到目前为止,没有一个答案对我有用。
大致遵循本指南https://testdriven.io/blog/dockerizing-django-with-postgres-gunicorn-and-nginx/#nginx,我现在可以使用以下命令在本地启动我的 docker 容器并让 nginx 完美地服务静态/媒体文件:
sudo docker-compose -f docker-compose-prod.yml down -v
sudo docker-compose -f docker-compose-prod.yml up -d --build
sudo docker-compose -f docker-compose-prod.yml exec web python manage.py collectstatic --no-input --clear
我现在正尝试在数字海滴上进行同样的工作。在远程服务器上,我运行与上面完全相同的命令来启动服务。然后,除了访问任何静态或媒体文件的能力之外,一切都按预期工作。例如,每当我访问 my digital ocean ip/static/admin/css/nav_sidebar.css 时,都会遇到 404 错误。每当我看到 chrome 尝试获取我的自定义 css 时,请求只会显示为“已取消”(然后,如果我访问已取消请求的 URL 路径,我会看到相同的 404)。
我的代码可以在这里看到:https://github.com/PaulGilmartin/personal_website 可能与本次讨论相关的部分:
nginx.conf
upstream personal_website
server web:8000;
server
listen 80;
location /
proxy_pass http://personal_website;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
proxy_redirect off;
location /static/
alias /var/www/personal_website/static/;
location /media/
alias /var/www/personal_website/media/;
settings.py
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'static')
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
我特别困惑的是完全相同的命令可以在本地完美运行。这让我认为远程服务器上的 404 是基于权限的症状,但我不明白在我的 Dockerfile.prod 中的情况如何,我小心地将所有内容都分配给非 root 用户。
任何帮助都将不胜感激,因为我对可能出现的问题的想法不够了解!
编辑:这是我的 docker-compose 文件:
version: '3.7'
services:
web:
build:
context: .
dockerfile: Dockerfile.prod
command: gunicorn personal_website.wsgi:application --bind 0.0.0.0:8000 --timeout 120
volumes:
- static_volume:/var/www/personal_website/static
- media_volume:/var/www/personal_website/media
env_file:
- ./.env.prod
expose:
- 8000
ports:
- "80:8000"
depends_on:
- db
db:
image: postgres:11
volumes:
- postgres_data:/var/lib/postgresql/data/
env_file:
- ./.env.prod.db
nginx:
build: ./nginx
volumes:
- static_volume:/var/www/personal_website/static
- media_volume:/var/www/personal_website/media
ports:
- 1337:80
depends_on:
- web
volumes:
postgres_data:
static_volume:
media_volume:
【问题讨论】:
显示你的 docker-compose 文件 @IvanStarostin 编辑添加它:) 检查collectstatic
输出。可能是用户 WWW 无权向提及的卷写入任何内容。也许你的意思是在你的 dockerfile 中 chown 到 $APP_HOME
,而不是 $HOME
。
我认为既然 APP_HOME 包含在 HOME 中并且 chown
是递归的,那部分应该没问题吗?我可以看到 www
是所有文件输出的所有者,包括 collectstatic 的输出:www@86c0586098e9:/var/www/personal_website$ ls -l ... drwxr-xr-x 3 www www 4096 May 2 19:46 media drwxr-xr-x 1 www www 4096 May 2 15:58 nginx drwxr-xr-x 4 www www 4096 May 2 19:46 static drwxr-xr-x 1 www www 4096 May 2 11:32 templates www@86c0586098e9:/var/www/personal_website/static$ ls -l drwxr-xr-x 6 www www 4096 May 2 19:46 admin drwxr-xr-x 2 www www 4096 May 2 19:48 css
我注意到我的 nginx.conf 文件只有 root 权限,这会有所不同吗?我猜这是因为 nginx/Dockerfile 配置 paul@web:~/personal_website$ sudo docker exec 0431ab4ac863 ls -l /etc/nginx/conf.d/ total 4 -rw-r--r-- 1 root root 425 5月2日 15:58 nginx.conf
【参考方案1】:
我感觉问题出在这里:
STATIC_ROOT = os.path.join(BASE_DIR, 'static')
这个路径实际上应该和 nginx 期望的一样:
/var/www/personal_website/static/
因此,您可以尝试以下方法:
尝试在 Django 设置中硬编码静态根目录:
STATIC_ROOT = '/var/www/personal_website/static/'
在运行 Django 的容器中执行 bash:docker exec -it <container_name> /bin/bash
- 在那里运行 collectstatic 并检查静态文件是否复制到您期望的文件夹中。如果没有 - 那么您可能想找到文件被复制的确切位置。
如果它也看到带有静态文件的正确卷,还要检查 nginx 容器内部
我遇到了完全相同的问题,静态和媒体的硬编码路径解决了这个问题
更新: 我已经克隆了该项目,对我来说,它没有获取静态文件。因此,我在 docker-compose-prod.yml 中进行了以下更改,它开始工作:
从服务中删除 ports - web:
ports:
- "80:8000"
它不是必需的,因为 Web (Django) 不应该从外部访问。仅在 Docker 内部的公开端口 8000 上
设置nginx的开放端口为80:
ports:
- 80:80
我不知道 DigitalOcean 使用哪个端口来托管网站,但默认为 80。
【讨论】:
不幸的是,这没有帮助。我已经可以看到静态文件已正确移动到容器中的“/var/www/personal_website/static/”,并且 STATIC_ROOT 已正确解析,因此并没有抱太大希望。我认为如果这是问题所在,它也不会在本地工作。 @PaulGilmartin 查看我的答案的更新。建议是否有帮助 做到了!我最初向 Web 服务添加了端口,因为没有它我根本无法让网站运行(我想是因为我在 nginx 服务中有 1337:80,而不是 Digital Ocean 使用的 80:80)。非常感谢! 不客气!我猜你最终是从外部 i.o. 接触到 Django。 nginx 因为端口:“web”上的 80:8000。以上是关于Nginx 无法在数字海洋上提供 django 静态或媒体文件的主要内容,如果未能解决你的问题,请参考以下文章
数字海洋 NGINX 和 gunicorn 上的 CORS 标头访问控制缺少 django
Nuxt.js 前端和 laravel api 在同一个 nginx 服务器上 数字海洋