判断静态文件是否真的由Nginx托管
Django在生产环境下默认不提供静态文件服务,必须由前端服务器接管。如果你在浏览器中看到CSS或JS文件返回404,或者页面样式完全丢失,通常意味着静态文件没有被正确收集到指定目录,或者Nginx的root或alias配置路径与Django的STATIC_ROOT不一致。检查方法是先确认Django的STATIC_ROOT设置,运行collectstatic后查看该目录下是否存在文件,再对比Nginx配置中的location块是否指向同一路径。这是最基础的判断逻辑,很多新手在这步就卡住了:明明配置了Nginx,但路径对不上。我会先看一眼settings.py里的STATIC_ROOT和STATIC_URL,然后直接上服务器ls一下目录结构。
从Django端准备静态文件
在Django项目的settings.py中设置STATIC_ROOT为服务器上的绝对路径,例如/var/www/example.com/static,然后运行python manage.py collectstatic将所有静态文件复制到该目录。接着在Nginx配置中新增一个location块,比如location /static/ { alias /var/www/example.com/static/; },注意alias路径末尾的斜杠不能省略,否则会导致路径拼接错误。之后reload Nginx使配置生效。这里有个细节:STATIC_ROOT路径不要放在项目内部,最好单独找个目录,方便权限管理。collectstatic命令会把所有应用的static目录和STATICFILES_DIRS里的文件都复制过去,如果你用了第三方库的静态文件(比如admin后台),它也能一并处理。
Nginx配置中的路径陷阱
一个容易忽略的陷阱是Nginx的alias与root指令的区别。如果使用root,Nginx会将请求URI拼接到root路径后面,例如root /var/www/example.com/static,则访问/static/css/style.css时会查找/var/www/example.com/static/static/css/style.css,导致404。而alias会直接替换匹配的路径部分,因此对静态文件目录应优先使用alias而非root。另外,检查Django的STATIC_URL是否与Nginx location路径一致,例如STATIC_URL='/static/'。很多人的配置看起来没错,但实际因为多了一层目录出问题。我建议先在Nginx配置里写alias,并确保末尾斜杠和STATIC_ROOT末尾斜杠保持一致。如果你非要用root,可以写location /static/ { root /var/www/example.com; },这样URI里的/static会拼到root后面变成/var/www/example.com/static,效果和alias一样,但容易混淆,不推荐。
验证配置是否生效
配置完成后,先通过curl或浏览器直接访问一个静态文件URL,例如http://yourdomain.com/static/css/style.css,观察HTTP状态码。若返回200且内容正确则成功。若返回403,检查目录权限:确保Nginx运行用户(如www-data)对STATIC_ROOT有读取权限(一般设置为755)。若返回404,检查路径拼接是否正确,并在Nginx错误日志中搜索对应条目,通常位于/var/log/nginx/error.log。我经常用curl -I看响应头,顺便确认Content-Type是否正确。如果静态文件是CSS但返回了text/plain,可能是MIME类型没配置好,但Nginx默认会根据扩展名判断,一般不会错。另外,记得清浏览器缓存,否则容易误判。
什么时候可以跳过Nginx静态文件配置
如果Django应用同时使用WhiteNoise或django-storages等第三方库托管静态文件,那么Nginx静态文件配置可能不是必需的,或者需要调整优先级。例如,使用WhiteNoise时,Nginx可将/static请求代理到Django,但性能不如直接由Nginx提供文件。建议仅在访问量较低或需要自定义缓存头时使用WhiteNoise,否则应坚持Nginx反向代理。另外,务必在生产环境中关闭Django的DEBUG模式,否则静态文件可能会由Django自身处理,导致性能下降并暴露敏感信息。我自己偏好的做法是:小项目用WhiteNoise省事,大项目或者对性能有要求时,一定用Nginx直接服务。如果你用了CDN或对象存储,那Nginx这层甚至可以改成反向代理到上游,但那就属于另一套方案了。
还需要留意什么
配置文件改完记得执行nginx -t检查语法,没问题再reload。如果Nginx和Django跑在不同的容器里,路径映射要对应好,避免 alias 指到容器内部路径但宿主机上找不到的情况。我见过有人把STATIC_ROOT设成容器内的/app/static,但Nginx在宿主机上用alias指向同一个路径,结果文件不存在。这种情况下要么把静态文件挂载到宿主机,要么让Nginx也跑在容器里统一路径。另外,如果你用了多个location块处理静态文件,注意顺序,Nginx会优先匹配精确的location,但一般不会冲突。整体来说,配好之后,一个简单的200响应和正确的文件内容就是最好的证明。