Django静态文件收集一键脚本与华为云ECS线上部署完整流程
引言:为什么需要一套完整的Django部署流程
Django作为Python生态中最受欢迎的Web框架之一,以其“ batteries-included ”的设计哲学赢得了大量开发者的青睐。然而,当项目从本地开发环境迁移到生产环境时,许多开发者尤其是初学者往往会遇到各种各样的挑战:静态文件加载404、Nginx与uWSGI通信失败、数据库连接超时、媒体文件无法上传……这些问题看似琐碎,却足以让一个即将上线的项目卡住数天之久。
在众多部署难点中,静态文件的处理是最容易被忽视却又最容易出问题的一环。Django在开发环境下通过runserver命令可以自动提供静态文件服务,但这种方式性能低下且不安全,绝不能用于生产环境。正确的做法是使用collectstatic命令将所有静态文件收集到一个统一目录中,再由Nginx等高性能Web服务器直接提供访问。然而,每次代码更新后手动执行collectstatic、重启uWSGI、重启Nginx,不仅繁琐而且容易遗漏步骤。这正是本文要解决的核心问题——通过一键脚本将静态文件收集与整个部署流程自动化。
本文将从零开始,在华为云ECS云服务器上完整部署一个Django项目,并重点打造一个高效的静态文件收集一键脚本。无论你是刚接触Django部署的新手,还是希望优化现有部署流程的资深开发者,这篇文章都能为你提供切实可行的参考。
需要先登录华为云控制台,点击:华为云控制台,还没有账号,点击:注册并关联,已有账号点击:登录后关联
一、部署前的准备工作
1.1 华为云ECS实例的选购与初始化
在华为云控制台中购买弹性云服务器ECS时,需要根据项目规模选择合适的配置。对于中小型Django项目,推荐选择2核4GB内存的规格,操作系统建议选择Ubuntu 22.04 LTS或Huawei Cloud EulerOS 2.0。购买完成后,系统会分配一个弹性公网IP,这是后续访问服务器和部署项目的入口地址。
购买ECS后第一件重要的事情是重置root密码,然后通过SSH工具(如Xshell、Putty或终端命令行)连接到服务器。连接命令如下:
ssh root@你的弹性公网IP1.2 安全组规则配置
安全组是华为云ECS的虚拟防火墙,控制着进出服务器的网络流量。Django部署至少需要放行以下端口:
- 22端口:SSH远程登录
- 80端口:HTTP网站访问
- 443端口:HTTPS加密访问(如启用SSL)
- 8000-8003端口:uWSGI测试与调试端口
- 3306端口:MySQL数据库远程访问(如需要)
在华为云控制台的“安全组”页面中,添加入方向规则,协议选择TCP,端口填写上述端口号,源地址设置为0.0.0.0/0表示允许所有IP访问。生产环境中建议根据实际情况限制源IP范围以提高安全性。
二、服务器环境搭建
2.1 更新系统与配置镜像源
连接上ECS后,首先更新系统软件包列表,并将镜像源切换为华为云开源镜像站以加速后续软件安装:
sudo apt update && sudo apt upgrade -y2.2 安装Python环境
Ubuntu 22.04默认自带Python 3.10,但为了更好的兼容性,建议安装Python 3.11或3.12。首先安装编译依赖:
sudo apt install -y python3-pip python3-dev python3-venv build-essential libssl-dev libffi-dev验证Python和pip的安装:
python3 --version
pip3 --version2.3 安装与配置MySQL数据库
大多数Django项目使用MySQL或PostgreSQL作为生产数据库。安装MySQL:
sudo apt install -y mysql-server安装完成后进行安全初始化配置:
sudo mysql_secure_installation这个命令会引导你设置root密码、移除匿名用户、禁止root远程登录、删除测试数据库等。配置完成后,进入MySQL创建Django项目使用的数据库和用户:
sudo mysql -u root -p
CREATE DATABASE myblog CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'django_user'@'localhost' IDENTIFIED BY '你的密码';
GRANT ALL PRIVILEGES ON myblog.* TO 'django_user'@'localhost';
FLUSH PRIVILEGES;
EXIT;2.4 安装Nginx
Nginx将作为反向代理服务器和静态文件服务器。安装命令:
sudo apt install -y nginx安装完成后启动Nginx并设置为开机自启:
sudo systemctl start nginx
sudo systemctl enable nginx在浏览器中访问服务器公网IP,看到Nginx欢迎页面即表示安装成功。
2.5 安装uWSGI
uWSGI是一个高性能的WSGI服务器,负责将Web请求转发给Django应用处理。使用pip3安装:
sudo pip3 install uwsgi为了验证uWSGI是否正常工作,可以创建一个简单的测试文件:
sudo mkdir /home/myblog
cd /home/myblog
sudo vim test.py在test.py中写入以下内容:
def application(env, start_response):
start_response('200 ok', [('Content-Type','text/html')])
return [b"Hello World"]然后启动uWSGI测试:
sudo uwsgi --http :8001 --wsgi-file test.py在浏览器中访问“http://服务器IP:8001”,看到“Hello World”即表示uWSGI工作正常。
三、Django项目部署
3.1 项目代码上传
将本地开发完成的Django项目代码上传到服务器。常用的方式有:
- Git克隆:如果代码托管在GitHub、Gitee或华为云CodeArts,直接在服务器上
git clone - SCP/SFTP上传:使用
scp命令或FTP工具将项目文件夹上传到服务器 - 华为云CodeArts部署模板:通过CodeArts Deploy服务一键部署
以Git方式为例:
cd /home/myblog
git clone https://github.com/你的用户名/你的项目.git3.2 创建虚拟环境并安装依赖
为项目创建独立的Python虚拟环境,避免与其他项目产生依赖冲突:
cd /home/myblog/你的项目
python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txt如果项目没有requirements.txt,可以使用pip freeze > requirements.txt在本地生成后再上传。
3.3 配置Django生产环境settings.py
生产环境的settings.py需要进行多项关键配置:
# 关闭调试模式
DEBUG = False
# 允许访问的域名列表
ALLOWED_HOSTS = ['你的域名或公网IP']
# 数据库配置——切换到生产数据库
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'myblog',
'USER': 'django_user',
'PASSWORD': '你的密码',
'HOST': 'localhost',
'PORT': '3306',
'OPTIONS': {'charset': 'utf8mb4'},
}
}
# 静态文件配置——核心!
STATIC_URL = '/static/'
STATIC_ROOT = '/home/myblog/你的项目/static_collected'
# 媒体文件配置(用户上传文件)
MEDIA_URL = '/media/'
MEDIA_ROOT = '/home/myblog/你的项目/media'STATIC_ROOT是collectstatic命令收集静态文件的目标目录,必须是一个绝对路径。而MEDIA_ROOT是用户上传文件的存储目录,两者需要分开管理。
3.4 数据库迁移
在虚拟环境中执行数据库迁移,创建项目所需的数据表:
python manage.py migrate四、静态文件收集的深度解析
4.1 什么是collectstatic
collectstatic是Django内置的管理命令,其作用是将项目所有应用中的静态文件(CSS、JavaScript、图片等)统一复制到STATIC_ROOT指定的目录中。为什么需要这一步?因为在生产环境中,Django本身不应当负责提供静态文件服务——这既低效也不安全。正确的做法是让Nginx这类高性能Web服务器直接从STATIC_ROOT目录读取并返回静态文件。
collectstatic命令会遍历以下位置查找静态文件:
- 每个已安装应用下的
static/子目录 STATICFILES_DIRS中指定的额外目录- 第三方应用自带的静态文件
当多个位置存在同名文件时,Django会按照STATICFILES_FINDERS中定义顺序选择第一个找到的文件。
4.2 静态文件去重与版本管理
在生产环境中,浏览器缓存可能导致用户看到旧版本的CSS或JS文件。Django的ManifestStaticFilesStorage存储后端可以自动为静态文件名添加内容哈希值,从而实现缓存破坏。在settings.py中配置:
STORAGES = {
'staticfiles': {
'BACKEND': 'django.contrib.staticfiles.storage.ManifestStaticFilesStorage',
},
}启用后,{% static 'css/style.css' %}在模板中会被渲染为类似/static/css/style.55a8c5e3.css的路径,文件内容变化时哈希值随之变化,强制浏览器重新加载。
4.3 执行collectstatic
在项目根目录下执行:
python manage.py collectstatic --noinput--noinput参数表示自动确认覆盖,避免交互式提示中断自动化流程。执行后,所有静态文件将被复制到STATIC_ROOT目录中。
五、一键部署脚本的编写与使用
5.1 为什么需要一键脚本
每次代码更新后,开发者需要依次执行以下操作:拉取最新代码、激活虚拟环境、安装新依赖、执行数据库迁移、收集静态文件、重启uWSGI、重启Nginx。手动执行这些步骤不仅耗时,而且容易遗漏或出错。一个精心编写的一键脚本可以将整个流程自动化,实现“一条命令完成部署”。
5.2 完整的部署脚本
在项目根目录下创建deploy.sh文件,内容如下:
#!/bin/bash
# Django项目一键部署脚本
# 适用于华为云ECS Ubuntu环境
# ==================== 配置区域 ====================
PROJECT_DIR="/home/myblog/你的项目"
VENV_DIR="$PROJECT_DIR/venv"
STATIC_ROOT="/home/myblog/你的项目/static_collected"
GIT_BRANCH="main"
LOG_FILE="/var/log/django_deploy.log"
# =================================================
# 日志函数
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a $LOG_FILE
}
log "========== 开始部署 =========="
# 1. 进入项目目录
cd $PROJECT_DIR || { log "错误:项目目录不存在"; exit 1; }
# 2. 拉取最新代码
log "拉取最新代码..."
git pull origin $GIT_BRANCH || { log "错误:Git拉取失败"; exit 1; }
# 3. 激活虚拟环境并安装依赖
log "安装Python依赖..."
source $VENV_DIR/bin/activate
pip install -r requirements.txt --quiet || { log "错误:依赖安装失败"; exit 1; }
# 4. 执行数据库迁移
log "执行数据库迁移..."
python manage.py migrate --noinput || { log "错误:数据库迁移失败"; exit 1; }
# 5. 收集静态文件(核心步骤)
log "收集静态文件..."
python manage.py collectstatic --noinput || { log "错误:静态文件收集失败"; exit 1; }
# 6. 重启uWSGI服务
log "重启uWSGI..."
sudo systemctl restart uwsgi || { log "错误:uWSGI重启失败"; exit 1; }
# 7. 重启Nginx服务
log "重启Nginx..."
sudo systemctl reload nginx || { log "错误:Nginx重载失败"; exit 1; }
log "========== 部署完成 =========="赋予脚本执行权限:
chmod +x deploy.sh以后每次更新代码后,只需执行:
./deploy.sh5.3 脚本的扩展与优化
上述脚本可以根据实际需求进行扩展:
- 添加测试环节:在收集静态文件前运行单元测试,测试不通过则中止部署
- 支持回滚:记录每次部署的Git commit ID,出错时可快速回滚到上一个版本
- 发送通知:部署完成后通过钉钉、企业微信或邮件发送通知
- 多服务器部署:使用Fabric等工具将脚本扩展到多台服务器
六、Nginx与uWSGI的配置
6.1 uWSGI配置文件
为Django项目创建uWSGI配置文件/etc/uwsgi/sites/你的项目.ini:
[uwsgi]
# 项目目录
chdir = /home/myblog/你的项目
# Django的WSGI模块
module = 你的项目.wsgi:application
# 虚拟环境路径
home = /home/myblog/你的项目/venv
# 进程与线程
processes = 4
threads = 2
# Socket文件(与Nginx通信)
socket = /home/myblog/你的项目/uwsgi.sock
# Socket权限
chmod-socket = 666
# 主进程管理
master = true
# 日志文件
logto = /var/log/uwsgi/你的项目.log
# 优雅退出
exit-on-reload = true创建日志目录并设置权限:
sudo mkdir -p /var/log/uwsgi
sudo chown -R www-data:www-data /var/log/uwsgi创建systemd服务文件/etc/systemd/system/uwsgi.service:
[Unit]
Description=uWSGI service for Django project
After=network.target
[Service]
User=www-data
Group=www-data
WorkingDirectory=/home/myblog/你的项目
ExecStart=/usr/local/bin/uwsgi --ini /etc/uwsgi/sites/你的项目.ini
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target启动并启用uWSGI服务:
sudo systemctl start uwsgi
sudo systemctl enable uwsgi6.2 Nginx配置
Nginx的配置是整个部署流程中至关重要的一环。它不仅要作为反向代理将动态请求转发给uWSGI,还要直接提供静态文件和媒体文件的访问服务。
创建Nginx站点配置文件/etc/nginx/sites-available/你的项目:
server {
listen 80;
server_name 你的域名或公网IP;
# 客户端上传文件大小限制
client_max_body_size 50M;
# 静态文件路由——由Nginx直接提供
location /static/ {
alias /home/myblog/你的项目/static_collected/;
expires 30d;
access_log off;
}
# 媒体文件路由——用户上传文件
location /media/ {
alias /home/myblog/你的项目/media/;
expires 7d;
}
# 动态请求转发给uWSGI
location / {
include uwsgi_params;
uwsgi_pass unix:/home/myblog/你的项目/uwsgi.sock;
uwsgi_read_timeout 60;
}
# 优雅处理404
location /404.html {
root /usr/share/nginx/html;
}
error_page 404 /404.html;
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}location /static/块中的alias指令指向STATIC_ROOT目录,Nginx会直接读取该目录下的文件并返回给客户端。而location /块将其他所有请求通过uwsgi_pass转发给uWSGI处理。
启用站点配置并重载Nginx:
sudo ln -s /etc/nginx/sites-available/你的项目 /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx七、使用华为云OBS托管静态文件的高级方案
7.1 为什么考虑OBS
对于大型Django项目或需要全球加速的场景,将静态文件托管在华为云OBS(对象存储服务)中并配合CDN加速是更优的方案。OBS的优势包括:
- 海量存储:理论上无限容量,无需担心磁盘空间
- 高可用性:数据多副本存储,可靠性高达99.995%
- CDN加速:与华为云CDN无缝集成,全球用户访问延迟低
- 内网免流量:ECS同地域访问OBS不产生外网流量费用
7.2 配置Django使用OBS存储静态文件
首先安装华为云OBS的Python SDK:
pip install esdk-obs-python
pip install django-storages在settings.py中配置OBS作为静态文件存储后端:
# OBS配置
OBS_ACCESS_KEY_ID = '你的Access Key'
OBS_SECRET_ACCESS_KEY = '你的Secret Key'
OBS_STORAGE_BUCKET_NAME = '你的桶名称'
OBS_ENDPOINT = 'obs.cn-south-1.myhuaweicloud.com'
# 静态文件存储
STORAGES = {
'staticfiles': {
'BACKEND': 'storages.backends.s3boto3.S3Boto3Storage',
'OPTIONS': {
'access_key': OBS_ACCESS_KEY_ID,
'secret_key': OBS_SECRET_ACCESS_KEY,
'bucket_name': OBS_STORAGE_BUCKET_NAME,
'endpoint_url': f'https://{OBS_ENDPOINT}',
'custom_domain': '你的CDN域名',
},
},
}
STATIC_URL = 'https://你的CDN域名/static/'
STATICFILES_STORAGE = 'storages.backends.s3boto3.S3Boto3Storage'配置完成后,执行collectstatic会将静态文件直接上传到OBS桶中。用户访问时,请求直接由CDN节点响应,大幅减轻ECS的带宽压力。
八、部署后的验证与优化
8.1 验证部署是否成功
部署完成后,从以下几个方面进行验证:
- 网站访问:在浏览器中输入域名或公网IP,确认Django应用正常响应
- 静态文件加载:打开浏览器开发者工具的Network面板,确认CSS、JS、图片等静态文件返回200状态码
- 媒体文件上传:测试用户头像或文件上传功能,确认文件能正确保存到
MEDIA_ROOT目录 - 数据库连接:确认涉及数据库查询的页面能正常展示数据
8.2 常见问题排查
静态文件404:检查STATIC_ROOT目录是否存在且包含文件,检查Nginx配置中alias路径是否正确,检查Nginx进程是否有读取该目录的权限。
uWSGI无法启动:查看/var/log/uwsgi/你的项目.log日志文件,通常是由于Python路径错误、虚拟环境未激活或socket文件权限问题导致。
502 Bad Gateway:表明Nginx无法连接到uWSGI。检查uWSGI服务是否运行,检查socket文件是否存在且权限正确,检查Nginx配置中的uwsgi_pass路径是否与uWSGI配置一致。
8.3 安全与性能优化建议
- 启用HTTPS:使用Let's Encrypt免费证书为网站启用HTTPS加密
- 配置Gzip压缩:在Nginx中启用Gzip压缩,减少传输数据量
- 设置缓存策略:为静态文件设置合理的
expires头,利用浏览器缓存减少重复请求 - 限制ALLOWED_HOSTS:在settings.py中严格配置允许访问的域名,防止HTTP Host头攻击
- 使用环境变量管理敏感信息:将数据库密码、SECRET_KEY等敏感配置存储在环境变量中,不要硬编码在settings.py里
九、总结
本文完整地介绍了在华为云ECS云服务器上部署Django项目的全过程,从ECS选购、环境搭建、项目配置,到静态文件收集、一键部署脚本、Nginx与uWSGI配置,再到使用OBS托管静态文件的高级方案。其中静态文件收集一键脚本是整个部署流程自动化的核心,它将原本需要手动执行的多个步骤整合为一条命令,大大提高了部署效率和可靠性。
部署是一个持续优化的过程。随着项目规模的扩大和访问量的增长,你可能还需要引入负载均衡、数据库读写分离、Redis缓存等更多技术组件。但无论如何演进,静态文件的正确收集与高效服务始终是Django生产部署中最基础也最重要的一环。希望本文的内容能够帮助你在华为云上顺利部署Django项目,并为后续的优化打下坚实的基础。
常见问题问答
问1:为什么我的Django项目部署后静态文件加载不出来,显示404错误?
答:这是Django部署中最常见的问题。请按以下顺序排查:第一,确认是否执行了python manage.py collectstatic命令,且STATIC_ROOT目录中确实有文件;第二,检查Nginx配置文件中location /static/块的alias路径是否与STATIC_ROOT完全一致;第三,确认Nginx进程(通常是www-data用户)有读取STATIC_ROOT目录的权限;第四,检查STATIC_URL是否与Nginx中配置的URL前缀匹配。
问2:collectstatic命令每次都要手动执行吗?有没有自动化的办法?
答:完全可以自动化。本文第五节提供了一个完整的Shell一键部署脚本,将git pull、pip install、migrate、collectstatic、重启服务等步骤整合在一起。每次代码更新后只需执行./deploy.sh即可完成全部部署流程。此外,也可以配置Git钩子或使用CI/CD工具(如Jenkins、GitLab CI)在代码推送时自动触发部署。
问3:静态文件和媒体文件有什么区别?部署时应该怎么处理?
答:静态文件是开发者编写的CSS、JavaScript、图片等资源,属于代码库的一部分,变更频率低;媒体文件是用户上传的内容(如头像、附件),变更频率高,由用户动态产生。部署时,静态文件通过collectstatic收集到STATIC_ROOT,由Nginx直接提供;媒体文件存储在MEDIA_ROOT,同样由Nginx提供访问,但需要注意MEDIA_ROOT目录的写入权限,确保Django应用能正常保存用户上传的文件。
问4:使用华为云OBS托管静态文件有什么好处?配置复杂吗?
答:OBS托管静态文件的主要好处包括:无限存储空间、高可靠性、与CDN无缝集成实现全球加速、ECS同地域内网访问免流量费。配置并不复杂,安装django-storages和OBS SDK后,在settings.py中配置STORAGES即可。配置完成后,collectstatic会自动将文件上传到OBS桶中,无需额外操作。
问5:华为云ECS的安全组规则应该怎么配置才能让Django项目正常访问?
答:至少需要放行以下入方向端口:22(SSH)、80(HTTP)、443(HTTPS,如启用)。如果使用uWSGI的HTTP模式进行测试,还需要放行8001等端口。如果数据库需要远程访问,还需放行3306端口。生产环境中不建议将数据库端口暴露到公网,应仅允许内网或特定IP访问。
问6:一键部署脚本执行后uWSGI无法重启,该怎么处理?
答:首先检查uWSGI的systemd服务状态:sudo systemctl status uwsgi,查看错误信息。常见原因有:虚拟环境路径变化导致uWSGI找不到Python解释器、socket文件权限不足、项目代码有语法错误导致uWSGI加载失败。查看uWSGI日志/var/log/uwsgi/你的项目.log通常能获得具体的错误线索。修复问题后,手动重启uWSGI服务即可。



