如何在非根URL下用Nginx部署Django应用并修复静态文件问题?
解决Django在非根URL下静态文件加载失败问题
一、调整Django核心配置
这是解决静态文件路径问题的关键,让Django自动生成带非根前缀的URL:
设置
FORCE_SCRIPT_NAME:在settings.py中添加,指定你的部署前缀,比如部署在/myapp路径下:FORCE_SCRIPT_NAME = '/myapp'这个参数会让Django在生成所有URL(包括静态文件、视图路由)时自动带上该前缀。
修改
STATIC_URL:将静态文件URL前缀与FORCE_SCRIPT_NAME对齐,避免硬编码:STATIC_URL = f"{FORCE_SCRIPT_NAME}/static/" # 或者直接写死:STATIC_URL = '/myapp/static/'确保
STATIC_ROOT与容器挂载一致:配置静态文件收集目录,比如:STATIC_ROOT = '/var/www/static/'部署前必须执行
python manage.py collectstatic --noinput,将所有APP的静态文件收集到STATIC_ROOT目录。在docker中可以把这个命令加到启动脚本或command里。避免硬写URL:模板中引用静态文件必须用
{% static %}标签,比如:<link rel="stylesheet" href="{% static 'css/main.css' %}">视图中生成URL要用
reverse()函数,不要直接拼接字符串,确保自动带上前缀。
二、Docker-Compose与Nginx配置配合
通过Nginx反向代理正确传递请求前缀,并映射静态文件目录:
Docker-Compose示例配置
确保Django和Nginx共享静态文件卷,且处于同一网络:
services: django: build: . command: sh -c "python manage.py collectstatic --noinput && gunicorn myproject.wsgi:application --bind 0.0.0.0:8000" volumes: - static_volume:/var/www/static/ networks: - app-network nginx: image: nginx:alpine volumes: - ./nginx/conf.d:/etc/nginx/conf.d - static_volume:/var/www/static/ ports: - "80:80" depends_on: - django networks: - app-network volumes: static_volume: networks: app-network: driver: bridge
Nginx配置文件(nginx/conf.d/myapp.conf)
关键是正确处理前缀转发和静态文件映射:
server { listen 80; # 直接映射静态文件,不走Django location /myapp/static/ { alias /var/www/static/; expires 30d; } # 转发动态请求到Django服务 location /myapp/ { proxy_pass http://django:8000/; # 末尾的斜杠必须加,会去掉/myapp/前缀转发给Django 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; } }
注意:proxy_pass末尾的斜杠是核心,它会把/myapp/xxx转换成/xxx转发给Django,而Django通过FORCE_SCRIPT_NAME识别前缀,生成带/myapp的响应URL。
三、常见问题排查
- 静态文件未收集:检查docker启动日志,确认
collectstatic命令执行成功,且STATIC_ROOT目录下有静态文件。 - HTTPS环境配置:如果用HTTPS,需在
settings.py添加:
确保Django识别正确的请求协议,生成HTTPS前缀的URL。USE_X_FORWARDED_HOST = True SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https') - Gunicorn无需加前缀:不要给Gunicorn传递
--prefix参数,前缀处理由Nginx和Django的FORCE_SCRIPT_NAME共同完成。
内容的提问来源于stack exchange,提问作者IceCube092
相关产品推荐
相关产品推荐

