华为云ECS云服务器部署Django网站:uWSGI+Nginx全套配置指南
1. 引言:为什么选择华为云ECS部署Django
Django作为Python生态中最成熟、最全面的Web框架,凭借其 'batteries-included' 的设计理念,深受开发者喜爱。然而,Django自带的开发服务器runserver仅适用于本地调试场景,绝对不能直接用于生产环境。生产环境部署需要一套稳定、高效、安全的分层架构,而uWSGI+Nginx的组合正是业界公认的黄金标准。
华为云弹性云服务器ECS提供了灵活、可扩展的计算资源,结合其稳定的网络环境和丰富的镜像源支持,是部署Django生产应用的理想选择。本文将从零开始,手把手带你在华为云ECS上完成Django项目的全流程部署。
需要先登录华为云控制台,点击:华为云控制台,还没有账号,点击:注册并关联,已有账号点击:登录后关联
2. 部署架构原理解析
在动手操作之前,理解整个部署架构的工作原理至关重要。一套完整的Django生产部署架构由三层组成:
2.1 分层架构概述
- Nginx(前端Web服务器):负责接收客户端的HTTP请求,处理静态资源(CSS、JavaScript、图片等),并将动态请求转发给后端的uWSGI服务。
- uWSGI(应用服务器):作为Django与Nginx之间的桥梁,通过WSGI协议调用Django应用,处理动态内容生成。
- Django(后端应用):实际处理业务逻辑、数据库交互、模板渲染等核心功能。
2.2 请求流转过程
用户请求的完整流转路径如下:浏览器发起HTTP请求 → 经过域名解析到达ECS的公网IP → Nginx监听80/443端口接收请求 → Nginx判断请求类型:若请求静态资源则直接返回,若为动态请求则通过uWSGI协议转发给uWSGI服务 → uWSGI调用Django的WSGI接口处理请求 → Django生成响应内容并逐层返回给用户。
2.3 分层架构的核心优势
这种分层设计带来了三大核心价值:
- 性能优化:uWSGI通过多进程/多线程模型大幅提升并发处理能力,Nginx的异步非阻塞IO架构可轻松处理数万并发连接。
- 安全隔离:Nginx作为前端防护层,可以有效阻断SQL注入、XSS攻击等常见Web威胁,同时隐藏后端服务的具体细节。
- 资源效率:静态资源由Nginx直接返回,完全不占用Django应用进程的资源,让Django专注于动态内容的处理。
3. 华为云ECS环境准备
3.1 购买ECS实例
登录华为云控制台后,进入弹性云服务器ECS产品页面,点击 '购买弹性云服务器'。在配置选择上,建议关注以下几点:
- 区域选择:选择距离目标用户群体最近的地域,以降低网络延迟。
- 计费模式:生产环境建议选择包年/包月以获得更优价格;测试或学习用途可选择按需计费,灵活按量付费。
- 镜像选择:推荐使用Ubuntu 22.04 LTS或CentOS 7/8,华为云也提供了Huawei Cloud EulerOS 2.0作为备选。本文示例基于Ubuntu 22.04 LTS。
- 规格配置:至少2核4GB内存起步,根据预期访问量适当升级。
- 弹性公网IP:购买时务必绑定弹性公网IP,否则无法从公网访问。
3.2 安全组规则配置
安全组是华为云的重要网络安全隔离手段,必须在ECS所属的安全组中开放必要的端口。以下是Django部署必需的安全组规则:
| 方向 | 优先级 | 策略 | 类型 | 协议端口 | 源地址 | 说明 |
|---|---|---|---|---|---|---|
| 入方向 | 1 | 允许 | IPv4 | TCP: 22 | 0.0.0.0/0 | SSH远程连接 |
| 入方向 | 1 | 允许 | IPv4 | TCP: 80 | 0.0.0.0/0 | HTTP网站访问 |
| 入方向 | 1 | 允许 | IPv4 | TCP: 443 | 0.0.0.0/0 | HTTPS网站访问 |
| 入方向 | 1 | 允许 | IPv4 | TCP: 8001-8003 | 0.0.0.0/0 | uWSGI测试端口(可选) |
具体配置步骤可参考华为云文档 '为安全组添加安全组规则'。生产环境中建议将SSH端口22的源地址限制为特定IP段,而非0.0.0.0/0,以提高安全性。
3.3 登录ECS与基础环境配置
购买完成后,通过SSH登录到ECS实例:
ssh root@你的弹性公网IP登录后首先更新系统软件源。华为云提供了高速镜像源,建议切换以提升下载速度:
# Ubuntu系统
sudo apt update && sudo apt upgrade -y
# CentOS系统
sudo yum update -y安装编译工具和Python开发依赖:
# Ubuntu
sudo apt install -y build-essential python3-dev python3-pip libpcre3 libpcre3-dev zlib1g zlib1g-dev
# CentOS
sudo yum install -y gcc gcc-c++ python3-devel python3-pip pcre-devel zlib-devel关键依赖说明:
- python3-dev/python3-devel:提供Python.h头文件,编译uWSGI等C扩展时必须依赖。
- libpcre3/pcre-devel:正则表达式支持库,Nginx的核心依赖。
- zlib1g/zlib-devel:数据压缩支持,直接影响静态资源的传输效率。
4. Python虚拟环境与Django项目准备
4.1 创建Python虚拟环境
强烈建议为每个Django项目创建独立的Python虚拟环境,从根本上避免不同项目之间的依赖冲突。本文以项目路径/home/myblog为例:
# 创建项目目录
sudo mkdir -p /home/myblog
cd /home/myblog
# 创建虚拟环境
python3 -m venv venv
# 激活虚拟环境
source venv/bin/activate
# 升级pip工具链
pip install --upgrade pip setuptools wheel虚拟环境管理的最佳实践:将虚拟环境目录venv/纳入.gitignore,使用requirements.txt或Pipfile固化所有依赖的精确版本,确保开发环境与生产环境完全一致。
4.2 上传Django项目
有多种方式可以将本地Django项目代码上传到ECS:
- Git克隆:如果代码托管在Git仓库,直接在ECS上执行
git clone。 - SCP上传:使用
scp -r 本地项目路径 root@ECS_IP:/home/myblog/。 - FTP/SFTP工具:使用FileZilla等图形化工具上传。
4.3 Django项目生产环境配置
在部署到生产环境之前,必须对Django的settings.py进行关键修改:
# settings.py 关键配置
# 1. 关闭调试模式(生产环境绝对必须设为False)
DEBUG = False
# 2. 配置允许访问的域名/IP
ALLOWED_HOSTS = ['你的域名', '你的ECS公网IP']
# 3. 配置静态文件收集路径
STATIC_URL = '/static/'
STATIC_ROOT = '/home/myblog/static/' # collectstatic命令将收集到这里
# 4. 配置媒体文件路径(如有用户上传文件)
MEDIA_URL = '/media/'
MEDIA_ROOT = '/home/myblog/media/'
# 5. 配置数据库(建议使用环境变量管理敏感信息)
# 例如使用PostgreSQL或MySQL替代SQLite完成配置修改后,执行数据库迁移和静态文件收集:
# 在虚拟环境中执行
python manage.py migrate
python manage.py collectstaticcollectstatic命令会将所有App中的静态文件复制到STATIC_ROOT指定的目录,供Nginx直接提供服务。
5. uWSGI应用服务器配置
5.1 安装uWSGI
在激活的虚拟环境中安装uWSGI:
pip install uwsgi安装成功后,可以用一个简单的测试程序验证uWSGI是否能正常工作:
cd /home/myblog
# 创建测试文件
cat > test.py << 'EOF'
def application(env, start_response):
start_response('200 ok', [('Content-Type', 'text/html')])
return [b'Hello World']
EOF
# 启动测试(Ubuntu)
uwsgi --http :8001 --wsgi-file test.py此时通过浏览器访问 http://你的ECS公网IP:8001,如果看到 'Hello World' 页面,说明uWSGI安装成功。测试完成后按Ctrl+C停止进程。
5.2 uWSGI配置文件详解
命令行方式启动虽然直观,但不便于管理和持久化运行。生产环境必须使用配置文件来启动uWSGI。在项目目录下创建uwsgi.ini文件:
# /home/myblog/uwsgi.ini
[uwsgi]
# ---------- 项目基础配置 ----------
# 项目根目录(必填)
chdir = /home/myblog
# Django的WSGI入口文件(必填)
# 格式:项目名.wsgi:application
module = myblog.wsgi:application
# 虚拟环境路径(推荐指定,确保uWSGI使用正确的Python环境)
home = /home/myblog/venv
# ---------- 进程与线程管理 ----------
# 启用主进程管理模式
master = true
# 工作进程数:通常设置为CPU核心数 * 2
processes = 4
# 每个工作进程的线程数
threads = 2
# 允许在请求处理中创建新线程
enable-threads = true
# ---------- 通信配置 ----------
# 方式一:Unix Socket(推荐,性能更优、更安全)
socket = /home/myblog/myblog.sock
chmod-socket = 664
chown-socket = www-data:www-data
# 方式二:TCP端口(备选方案,如需跨服务器通信时使用)
# socket = 127.0.0.1:9001
# ---------- 进程管理文件 ----------
# PID文件,用于重启和停止操作
pidfile = /home/myblog/uwsgi.pid
# ---------- 日志配置 ----------
# 日志文件路径
daemonize = /home/myblog/uwsgi.log
# ---------- 其他优化参数 ----------
# 自动清理Socket和PID文件
vacuum = true
# 请求超时设置(秒)
harakiri = 30
# 请求体缓冲大小
post-buffering = 4096
# 启用线程锁优化
thunder-lock = true
# 设置最大请求数,防止内存泄漏
max-requests = 50005.3 关键参数深度解析
- chdir:项目根目录,uWSGI启动后将切换到此目录。
- module:指向Django项目的
wsgi.py文件,:application是Django默认的WSGI可调用对象。 - socket vs http:
socket用于与Nginx通过uWSGI协议通信(推荐),http则直接对外提供HTTP服务(仅测试用)。生产环境必须使用socket。 - processes与threads:
processes是工作进程数,threads是每个进程内的线程数。建议processes = CPU核心数 * 2,threads = 2。 - socket权限:
chmod-socket=664确保Nginx进程(通常以www-data用户运行)有权限读写Socket文件。
5.4 启动uWSGI服务
# 使用配置文件启动uWSGI(后台运行)
uwsgi --ini /home/myblog/uwsgi.ini
# 查看uWSGI进程状态
ps aux | grep uwsgi
# 停止uWSGI服务
uwsgi --stop /home/myblog/uwsgi.pid
# 重启uWSGI服务
uwsgi --reload /home/myblog/uwsgi.pid6. Nginx反向代理与静态文件服务
6.1 安装Nginx
安装Nginx:
# Ubuntu
sudo apt install -y nginx
# CentOS
sudo yum install -y nginx安装完成后启动Nginx并设置开机自启:
sudo systemctl start nginx
sudo systemctl enable nginx此时通过浏览器访问 http://你的ECS公网IP,如果看到Nginx欢迎页面,说明Nginx安装成功。
6.2 Nginx配置文件详解
在/etc/nginx/sites-available/目录下创建Django项目的Nginx配置文件:
# /etc/nginx/sites-available/myblog
server {
# 监听端口
listen 80;
# 服务器域名或IP
server_name 你的域名或公网IP;
# 字符集
charset utf-8;
# 日志配置
access_log /var/log/nginx/myblog_access.log;
error_log /var/log/nginx/myblog_error.log;
# ---------- 静态文件处理(动静分离) ----------
# Django收集的静态文件(CSS/JS/图片等)
location /static/ {
alias /home/myblog/static/;
expires 30d; # 设置缓存过期时间
}
# 媒体文件(用户上传文件)
location /media/ {
alias /home/myblog/media/;
expires 30d;
}
# ---------- 动态请求转发给uWSGI ----------
location / {
# 包含uWSGI标准参数
include /etc/nginx/uwsgi_params;
# 转发到uWSGI的Socket(必须与uwsgi.ini中的socket路径一致)
uwsgi_pass unix:/home/myblog/myblog.sock;
}
# ---------- 安全与性能优化 ----------
# 禁止访问隐藏文件
location ~ /\. {
deny all;
}
# 大文件上传支持
client_max_body_size 100M;
}6.3 配置文件核心要点解析
- 动静分离:
location /static/和location /media/直接由Nginx返回文件,完全不经过uWSGI和Django,大幅提升性能。 - alias与root的区别:
alias将URL路径映射到文件系统路径,root则是将URL路径附加到根路径后。对于/static/,使用alias更直观。 - uwsgi_pass:指定uWSGI服务的Socket地址,必须与
uwsgi.ini中的socket配置完全一致。 - client_max_body_size:控制客户端请求体的最大大小,对于有文件上传功能的应用尤其重要。
6.4 启用站点配置
# 创建软链接启用站点
sudo ln -s /etc/nginx/sites-available/myblog /etc/nginx/sites-enabled/
# 测试Nginx配置语法是否正确
sudo nginx -t
# 如果测试通过,重新加载Nginx配置
sudo systemctl reload nginx7. systemd进程守护与开机自启
目前uWSGI是通过命令行启动的,一旦SSH会话断开或服务器重启,uWSGI进程就会终止。为了确保uWSGI作为系统服务持久运行,需要配置systemd服务。
7.1 创建systemd服务文件
# /etc/systemd/system/uwsgi.service
[Unit]
Description=uWSGI service for Django project
After=network.target
[Service]
Type=forking
User=www-data
Group=www-data
WorkingDirectory=/home/myblog
ExecStart=/home/myblog/venv/bin/uwsgi --ini /home/myblog/uwsgi.ini
ExecStop=/home/myblog/venv/bin/uwsgi --stop /home/myblog/uwsgi.pid
ExecReload=/home/myblog/venv/bin/uwsgi --reload /home/myblog/uwsgi.pid
Restart=always
RestartSec=5
KillSignal=SIGQUIT
[Install]
WantedBy=multi-user.target7.2 启动与管理服务
# 重新加载systemd配置
sudo systemctl daemon-reload
# 启动uWSGI服务
sudo systemctl start uwsgi
# 设置开机自启
sudo systemctl enable uwsgi
# 查看服务状态
sudo systemctl status uwsgi
# 查看日志
sudo journalctl -u uwsgi -f配置完成后,uWSGI将作为系统服务自动运行,服务器重启后也会自动启动,真正达到生产级稳定性要求。
8. 域名绑定与HTTPS证书配置
8.1 域名解析配置
如果拥有自己的域名,需要在域名注册商处将域名解析到ECS的弹性公网IP:
- A记录:将域名(如
example.com)指向ECS的公网IP。 - CNAME记录:将
www.example.com指向example.com。
解析生效后,将Nginx配置中的server_name改为域名:
server_name example.com www.example.com;8.2 使用Let's Encrypt免费SSL证书
HTTPS是生产环境的标配,Let's Encrypt提供免费的SSL证书,可以通过Certbot工具自动获取和续期:
# 安装Certbot
sudo apt install -y certbot python3-certbot-nginx
# 自动获取证书并配置Nginx
sudo certbot --nginx -d example.com -d www.example.com
# 测试证书自动续期
sudo certbot renew --dry-runCertbot会自动修改Nginx配置,启用HTTPS并设置HTTP自动跳转HTTPS。证书有效期为90天,Certbot的定时任务会自动续期,无需人工干预。
9. 性能优化与安全加固
9.1 uWSGI性能调优
- 调整进程与线程数:根据服务器CPU核心数调整
processes和threads参数。 - 启用缓存:在Django中配置Redis或Memcached缓存热点数据,减少数据库查询压力。
- 数据库优化:创建合适的数据库索引,使用慢查询日志分析并优化慢SQL。
9.2 Nginx性能调优
在/etc/nginx/nginx.conf中调整以下参数:
# 工作进程数(通常设为CPU核心数)
worker_processes auto;
# 每个工作进程的最大连接数
worker_connections 1024;
# 启用gzip压缩
gzip on;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
# 静态资源缓存
location ~* \.(jpg|jpeg|png|gif|ico|css|js)$ {
expires 30d;
add_header Cache-Control 'public, immutable';
}9.3 安全加固措施
- 关闭DEBUG:生产环境
DEBUG = False是底线,否则会泄露敏感信息。 - 限制ALLOWED_HOSTS:只允许真实的域名和IP访问。
- 使用HTTPS:全程加密传输,防止中间人攻击。
- 配置安全头:在Nginx中添加安全响应头,如
X-Frame-Options、X-Content-Type-Options等。 - 限制SSH访问:将安全组中22端口的源地址限制为特定IP段。
10. 常见问题与排查指南
10.1 502 Bad Gateway错误
这是Django部署中最常见的错误,通常由以下原因引起:
- uWSGI未启动:检查
ps aux | grep uwsgi确认进程是否存在。 - Socket路径不一致:确保Nginx的
uwsgi_pass与uWSGI的socket路径完全一致。 - Socket权限问题:检查Socket文件的权限,确保Nginx用户(
www-data)有读写权限。 - uWSGI启动失败:查看
/home/myblog/uwsgi.log日志文件定位具体错误。
10.2 静态文件404 Not Found
- 未执行collectstatic:确认已运行
python manage.py collectstatic。 - Nginx静态路径配置错误:检查
alias路径是否指向STATIC_ROOT目录。 - 目录权限问题:确保Nginx用户对静态文件目录有读取权限。
10.3 500 Internal Server Error
- 检查uWSGI日志:
tail -f /home/myblog/uwsgi.log查看详细错误。 - 检查Django日志:确认
settings.py中配置了LOGGING,便于追踪错误。 - 检查数据库连接:确认数据库服务正常运行且连接配置正确。
10.4 无法访问网站(连接超时)
- 检查安全组规则:确认80/443端口已在安全组中开放。
- 检查Nginx是否运行:
sudo systemctl status nginx。 - 检查防火墙:
sudo ufw status(Ubuntu)或sudo firewall-cmd --list-all(CentOS)。
11. 总结
本文系统性地介绍了在华为云ECS上使用uWSGI+Nginx部署Django项目的完整流程,从架构原理到环境准备,从配置文件编写到服务管理,再到性能优化和问题排查,涵盖了生产环境部署的所有关键环节。
核心要点回顾:
- 生产环境必须使用uWSGI+Nginx分层架构,绝不能直接使用Django的runserver。
- 华为云ECS的安全组规则是网络访问的第一道防线,务必正确配置。
- uWSGI的配置文件是部署的核心,
socket、chdir、module等参数必须精确无误。 - Nginx的动静分离配置能大幅提升性能,静态文件由Nginx直接服务。
- systemd进程守护确保服务持久稳定运行,是生产环境的必备环节。
- HTTPS加密和定期安全加固是保障网站安全的基本要求。
按照本文的步骤操作,你应该能够将Django项目稳定、高效地部署在华为云ECS上,为用户提供可靠的Web服务。
12. 常见问答
问1:Django的runserver能否直接用于生产环境?
绝对不能。runserver是Django内置的开发调试服务器,单进程、单线程,不具备并发处理能力,也没有安全防护,存在严重的安全隐患和性能瓶颈。生产环境必须使用uWSGI或Gunicorn等专业应用服务器配合Nginx使用。
问2:uWSGI应该使用TCP端口还是Unix Socket与Nginx通信?
强烈推荐使用Unix Socket。Unix Socket通过文件系统直接通信,无需经过TCP/IP协议栈,性能更高(高并发下响应速度快5%-10%),安全性更好(仅限本地访问,依赖文件权限控制),还能避免端口冲突问题。
问3:部署后访问网站出现502 Bad Gateway,如何排查?
按照以下顺序排查:首先确认uWSGI进程是否运行(ps aux | grep uwsgi);其次检查uWSGI日志(/home/myblog/uwsgi.log)查看具体错误;然后确认Nginx配置中的uwsgi_pass路径与uWSGI的socket路径完全一致;最后检查Socket文件的权限,确保Nginx用户有读写权限。
问4:静态文件无法加载(404错误)是什么原因?
最常见的原因有三个:一是未执行python manage.py collectstatic命令收集静态文件;二是Nginx配置中alias路径写错了,没有指向STATIC_ROOT目录;三是Nginx用户对静态文件目录没有读取权限。
问5:如何让uWSGI在服务器重启后自动启动?
将uWSGI配置为systemd系统服务即可。创建/etc/systemd/system/uwsgi.service文件,配置ExecStart、ExecStop等参数,然后执行sudo systemctl enable uwsgi启用开机自启。
问6:如何为Django网站启用HTTPS?
推荐使用Let's Encrypt的免费SSL证书。安装Certbot工具后,执行sudo certbot --nginx -d 你的域名即可自动获取证书并配置Nginx启用HTTPS,证书会自动续期,无需人工干预。


