资讯动态

CentOS+宝塔面板部署Django:从环境配置到Nginx反向代理

发布时间:2026/9/24 10:06:51 来源:尧图企业网站定制
简介一份面向Linux运维与Django开发者的实战教程针对在CentOS系统中使用宝塔面板部署Django项目这一典型需求梳理了从环境准备到线上可访问的完整流程。压缩包内含单个PDF文档大小139KB内容以图文步骤为主适合需要快速搭建生产环境的初中级开发者参考。目前已有2371人学习。教程覆盖基础环境搭建安装宝塔、Python项目管理器、Nginx、项目代码上传的两种方式并明确推荐存放目录通过Python项目管理器创建Django项目时对项目名称、路径、Python版本、框架、启动方式uwsgi、启动文件wsgi.py、端口号及模块依赖安装等关键配置逐项说明同时给出Nginx反向代理中static与media目录的映射方法以及配置完成后的重启与重载步骤可帮助读者避开常见部署坑点实现Django项目的稳定上线。1. 在 CentOS 与宝塔上部署 Django 项目先别急着敲命令Django 项目从本地跑通到远程可访问中间隔着的不是代码是环境配对。网上教程动辄让你配 uWSGI、写 XML 格式的 ini、再折腾 Nginx 正则真按步骤走到一半新手早就分不清是 Python 报错还是 Nginx 报错。而 CentOS 宝塔这套组合把部署路径压缩成了几条命令加几次点击前提是你知道宝塔帮你做了什么、没做什么。这篇教程面向手里已有一个能本地运行的 Django 项目、想用宝塔面板快速把它推到生产环境的开发者也适合被各种半截教程坑过的熟手回来对齐细节。先说结论在宝塔面板上部署 Django真正的工作量不在安装而在路径、权限和进程守护这三件事上这三件事理顺了部署本身就结束了。2. 初始化环境CentOS 7.9 与宝塔面板的版本选型和安装2.1 版本选型CentOS 7.9、Python 版本与宝塔的兼容关系部署 Django 遇到的第一个坑往往不是 Django 本身而是操作系统与 Python 版本的选择。CentOS 7 系列里目前最稳妥的选择是 CentOS 7.9原因是它的软件源里默认带的 Python 是 2.7而宝塔面板安装时会额外拉取自己的 Python 环境这几者之间经常打架。如果你买的是国内云厂商的 VPS镜像库里通常直接提供 CentOS 7.9 x64选这个版本比选 CentOS Stream 省心后者滚动更新的特性容易让面板和运行库突然变化。Django 的版本要求你心里要有数Django 2.2 支持 Python 3.5 到 3.7Django 3.2 LTS 支持 Python 3.6 到 3.9Django 4.x 要求 Python 3.8 以上。CentOS 7.9 系统自带的是 Python 2.7所以你要么用宝塔的 Python 项目管理器装一个 3.8 或 3.9要么自己编译安装。我的经验是直接把宝塔的 Python 项目管理器当作版本管理工具用不要碰系统自带的 Python更不要手动替换/usr/bin/python那个软链接换了之后yum、firewall-cmd全部会罢工。宝塔面板自身的安装门槛也值得提前说安装脚本会检查系统内存如果你在安装时看到“宝塔至少需要 3700MB 内存才能安装”之类的提示先别慌这是脚本对内存的校验阈值并不代表 2G 内存的机器跑不动面板。你可以在安装命令后面加--skip-memory-check跳过这个限制但前提是你清楚面板本身会常驻一些服务建议内存低于 1G 的机器不要装 MySQL 和 PHP能省则省。顺便提一句很多人纠结宝塔和 1Panel 选哪个我的看法是如果你熟悉 Linux 基础操作、愿意折腾 Docker1Panel 更适合你如果你就想快速看到网站页面、用图形界面管理文件数据库宝塔的上手成本确实更低这篇文章的步骤就按宝塔写。2.2 安装宝塔面板从远程连接到看到面板首页拿到 CentOS 7.9 服务器后用 SSH 工具登录先更新系统源。国内服务器建议先把 yum 源换成网易源或阿里源这一步能省下后面装依赖时的大量等待时间。网上有专门的 CentOS 修改网易源脚本核心就是把/etc/yum.repos.d/CentOS-Base.repo里的 mirrorlist 替换成 mirrors.163.com 的路径这里不展开你直接搜“CentOS 修改网易源”照着做就行。更新完源后执行宝塔的安装命令yum update -y wget -O install.sh https://download.bt.cn/install/install_6.0.sh bash install.sh安装过程会持续几分钟脚本会检测 Python 环境、安装面板依赖包最后在终端打印面板的访问地址和默认用户名密码。这里有两个要点一是安装完成后立刻用浏览器访问面板地址如果打不开检查云服务器的安全组是否放行了 8888 端口二是面板默认的入口是一串随机字符路径不要改成纯端口访问否则扫描器会疯狂试探你的面板登录页。登录后第一件事是在面板设置里绑定你的域名并把登录地址改成/ 随机字符串这是部署任何项目前的保命操作。2.3 在宝塔上准备 Python 运行环境版本管理器的取舍宝塔面板的软件商店里有一个应用叫“Python 项目管理器”这是部署 Django 的关键工具它的作用类似于给每个 Python 项目单独开一个房间互不干扰。安装这个管理器时面板会顺带安装 Python 3.7.9但你要根据项目需求决定是否要额外装一个版本。比如你的项目依赖了 pydantic 2.x 或 Django 4.2那就必须在管理器里再装一个 Python 3.9 或 3.11因为 3.7 跑不动这些新依赖。在 Python 项目管理器里添加 Python 版本时我一般会选 3.9兼容性处于一个舒服的位置Django 3.2 和 4.2 都能跑大部分第三方库的预编译 wheel 也覆盖到这个版本。装完之后它会在/www/server/pyproject下生成对应版本的 Python 解释器路径后续创建项目时直接选用这个版本即可。这里有一个新手容易忽略的操作创建完项目后不要急着传代码先把依赖装好否则项目文件里没有虚拟环境Python 项目管理器无法识别项目类型。3. 把 Django 项目送上服务器依赖构建、数据库准备与静态文件收集3.1 本地项目出发前的检查清单settings.py 的三个改动部署前先在本地把项目的部署开关打开这一步做得好服务器上能少踩一半坑。打开你的settings.py按顺序检查三个地方。第一处是DEBUG False这是 Django 部署的红线DEBUG开着部署一旦用户请求触发异常服务器会直接把完整堆栈和本地路径暴露在浏览器上等于把源码结构告诉别人。第二处是ALLOWED_HOSTS填上你的服务器 IP 和打算绑定的域名格式是ALLOWED_HOSTS [123.45.67.89, www.example.com]不然 Django 会拒绝处理请求并抛出 400 错误。第三处是静态文件和媒体文件的路径设置import os BASE_DIR os.path.dirname(os.path.dirname(os.path.abspath(__file__))) STATIC_URL /static/ STATIC_ROOT os.path.join(BASE_DIR, staticfiles) MEDIA_URL /media/ MEDIA_ROOT os.path.join(BASE_DIR, media) # 如果你的项目里还引用了 app 内部的 static 目录需要这句 STATICFILES_DIRS [ os.path.join(BASE_DIR, static), ]这段配置的逻辑是STATIC_ROOT是collectstatic命令的收集目标目录部署时 Nginx 会从这个目录里取 CSS、JS 和图片STATICFILES_DIRS是你原本放在各个 app 或者项目根目录static文件夹里的源文件MEDIA_ROOT是用户上传文件的落地目录。很多人在 VSCode 里写img src/static/images/logo.png本地能显示传到服务器后图片全挂原因就是本地 Django 开发服务器会自动从STATICFILES_DIRS里找静态文件而生产环境下 Django 默认不做这件事必须由 Nginx 指向STATIC_ROOT这一步在下文第 4 章会详细说明。检查完这三处后在本地执行python manage.py check --deployDjango 会输出生产环境的额外警告。有一个警告很常见SECRET_KEY不要硬编码在 settings.py 里。我一般习惯把它读环境变量没有就从文件里读服务器上写进.env文件但这属于安全加固的范畴新手阶段先保证能跑起来这个警告可以暂时忽略。3.2 上传代码与创建虚拟环境用宝塔文件管理器还是 Git把项目代码弄到服务器上有两种常见做法一种是本地打成 tar.gz 包通过宝塔的文件管理器上传再解压另一种是在服务器上git clone走版本管理流程。我更推荐用 Git因为部署不是一次性的之后每次改代码都要重新上传走 Git 能省掉压缩、上传、解压三步。如果没有 Git 仓库临时用文件管理器上传一次也够用但项目规模稍微大一点比如带 node_modules 或者媒体文件上传速度会让人崩溃。无论用哪种方式最终代码落在/www/wwwroot/下即可宝塔对站点的根目录默认就是这个路径下的一个子目录。假设你的项目放在/www/wwwroot/mydjango/进入该目录后用 Python 项目管理器创建虚拟环境它会自动在当前目录生成.venv文件夹并把 Python 解释器地址填入环境配置。cd /www/wwwroot/mydjango /www/server/pyproject/versions/3.9.12/bin/python3.9 -m venv .venv source .venv/bin/activate这里说明一下参数的含义-m venv是用 Python 自带的模块创建虚拟环境.venv是虚拟环境目录名这是业内约定俗称的名字宝塔的 Python 项目管理器默认也会识别这个目录。source命令是激活虚拟环境激活后命令行前缀会变成(.venv)之后执行的pip、python都在这个隔离环境内不会污染系统 Python。如果你的项目里直接复制了本地的venv目录上传在服务器上必须要删掉重新建因为虚拟环境里记录的是本机的 Python 绝对路径换个机器就跑不起来了。3.3 安装依赖与数据库准备requirements.txt 的正确打开方式虚拟环境建好后下一步是安装依赖。不要手动一个包一个包地装所有项目都要在本地生成requirements.txt生成命令是pip freeze requirements.txt。但我建议你自己精简一下这个文件因为pip freeze会把所有传递依赖都列出来有些包的版本号在服务器上可能装不上。比如某一次我部署的项目里锁定了numpy1.24.3在 Python 3.7 上没有对应的预编译包源码编译又缺依赖最后翻车翻在了一个无关紧要的传递依赖上。正确做法是只列项目直接依赖传递给pip去自动解析。服务器上的安装命令source .venv/bin/activate pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple-i参数是指定 pip 源为清华源国内服务器不换源的话从官方 PyPI 下载大包容易超时特别是Pillow、psycopg2这种编译型库等待时间非常考验耐心。如果你用的是 Python 3.9 且项目依赖的是 Django 3.2这里基本不会出意外如果项目用了mysqlclient装之前先确认系统里有没有mysql-devel没有的话要执行yum install gcc mysql-devel -y否则编译阶段会直接报EnvironmentError: mysql_config not found。数据库方面如果你选 SQLite部署后经常会遇到数据库文件权限不足导致 Django 报OperationalError: attempt to write a readonly database这是 SQLite 文件的属主和 Nginx 运行用户不一致造成的。我的建议是生产环境直接用 MySQL宝塔面板里装 MySQL 5.7 或 8.0 都行装完后在面板的数据库页面新建一个数据库和专用账号注意字符集选 utf8mb4这个字符集才能正常存 emoji 和中文。然后在 Django 的settings.py里改成这样DATABASES { default: { ENGINE: django.db.backends.mysql, NAME: mydjango_db, USER: mydjango_user, PASSWORD: 你的数据库密码, HOST: 127.0.0.1, PORT: 3306, OPTIONS: { charset: utf8mb4, }, } }OPTIONS里的charset经常被漏掉漏掉后在 Django shell 里执行查询-删除对象时一旦数据里含中文或表情符号就会报Incorrect string value错误这是新手排查数据库乱码时最容易忽略的细节。3.4 执行迁移与收集静态文件验证项目能否在服务器上独立运行依赖装完、数据库配置好之后先执行迁移和静态文件收集再配置 Nginx这样能提前暴露问题。执行顺序有讲究source .venv/bin/activate python manage.py makemigrations python manage.py migrate python manage.py collectstaticmakemigrations是根据模型变化生成迁移文件你的项目如果是从别的地方拷贝过来的本地生成的迁移文件已经随代码上传了这一步通常输出No changes detected这是正常现象。migrate才是真正把迁移应用到数据库执行完成后会看到一长串OK列表。collectstatic是把你项目里所有 app 的static目录下的文件集中复制到STATIC_ROOT指定的文件夹里这个过程会提示你是否覆盖已有文件输入yes即可。这三条命令跑完后用开发服务器裸跑一次验证命令是source .venv/bin/activate python manage.py runserver 0.0.0.0:8000然后在浏览器里访问http://服务器IP:8000如果你已经在ALLOWED_HOSTS里填了 IP应该能看到首页。看到首页说明项目代码、数据库、静态文件收集链路都通了可以关掉这个进程进入下一步。这一步不要跳过因为如果你在宝塔面板上配置了半天发现项目起不来你根本分不清是 Nginx 配置错了还是 Django 本身就有问题。裸跑能通后续就只需和 Nginx、进程守护工具打交道。4. 宝塔核心配置Nginx 反向代理、进程守护与域名绑定4.1 用 Python 项目管理器启动 Django从手动 uWSGI 到界面化守护早些年部署 Django 的标准流程是装 uWSGI再写一个uwsgi.ini文件用uwsgi --ini uwsgi.ini启动然后用 Supervisor 守着进程。这套流程没有错但宝塔的 Python 项目管理器把这三步压成了图形界面上的几个输入框。它本质上还是用 Supervisor 那个思路来守护进程只是不用你手动改配置文件了。在 Python 项目管理器页面点击“添加项目”填下面这几项项目路径/www/wwwroot/mydjangoPython 版本你之前装的 3.9框架选择 Django启动方式我一般用 Gunicorn一个 Python 写的 WSGI 服务器替代不推荐的runserver做生产服务启动文件mydjango/wsgi.py注意是项目配置目录下的那个 wsgi.py不是 app 目录里的监听端口8000后续 Nginx 会反代到这个端口添加后你可以不立刻点启动先手动生成并编辑一个run.py放项目根目录让 Python 项目管理器调用它来启动服务。run.py的内容标准做法是这样的# -*- coding: utf-8 -*- import os from gevent import monkey monkey.patch_all() from gunicorn.app.base import BaseApplication from gunicorn.six import iteritems os.environ.setdefault(DJANGO_SETTINGS_MODULE, mydjango.settings) class DjangoApplication(BaseApplication): def __init__(self, app, optionsNone): self.options options or {} self.application app super(DjangoApplication, self).__init__() def load_config(self): for key, value in iteritems(self.options): if key in self.cfg.settings: self.cfg.set(key.lower(), value) def load(self): return self.application def main(): options { bind: 0.0.0.0:8000, workers: 3, worker_class: gevent, timeout: 60, preload: True, } DjangoApplication(django_app).run()这段代码的逻辑解释一下monkey.patch_all()是协同程序的补丁让网络请求处理不阻塞workers指定工作进程数对普通机器来说 3 个足够设得太多反而拖垮内存timeout设成 60 秒防止某个请求处理时间过长被强杀preload是预加载模式代码改动后重启不会把旧进程的引用带入新进程。这个文件是宝塔 Python 项目管理器启动 Django 项目时最常见的标准入口你可以直接在管理器里添加项目后让它帮你生成也可以手动放在项目根目录后手动指定启动方式。这个文件不一定每个项目都用得上如果是简单项目直接在 Python 项目管理器里配置 Gunicorn 参数也行。4.2 Nginx 反向代理配置site 配置文件的 location 与参数含义进程守护搞定后把 Nginx 这个门卫请出来。它的职责是接收用户从 80 或 443 端口发来的请求然后把请求转发给 127.0.0.1:8000 上运行的 Django 进程同时把/static/和/media/开头的请求直接交给静态文件系统处理不走 Python 进程。这样的设计让 Nginx 承担静态文件和高并发的短连接Django 只专注业务逻辑。在宝塔面板的“网站”页面添加一个站点域名填你要绑定的域名PHP 版本选纯静态这里不需要 PHP。创建完成后到网站的配置文件编辑页核心配置片段如下server { listen 80; server_name www.example.com; # 防止上传大文件时 413 错误 client_max_body_size 20m; # 静态文件交给 Nginx 直接返回 location /static/ { alias /www/wwwroot/mydjango/staticfiles/; expires 7d; } # 媒体文件用户上传的图片等同样由 Nginx 返回 location /media/ { alias /www/wwwroot/mydjango/media/; expires 30d; } # 其余请求全部转发到 Django location / { proxy_pass http://127.0.0.1:8000; 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_connect_timeout 30s; proxy_read_timeout 120s; } }参数里最值得琢磨的是alias和proxy_pass的配对。location /static/的alias指向/www/wwwroot/mydjango/staticfiles/访问example.com/static/css/app.css时Nginx 会去服务器上读/www/wwwroot/mydjango/staticfiles/css/app.css。关键点alias是直接替换root是拼接前缀。如果你写的是root /www/wwwroot/mydjango/staticfiles/那访问/static/css/app.css时 Nginx 会去读/www/wwwroot/mydjango/staticfiles/static/css/app.css多了一层static静态文件全 404。这是初始配置阶段最容易出现的“玄学错误”实际上就是alias和root的行为差异。X-Forwarded-For和X-Real-IP这两个请求头的作用是让 Django 能拿到用户的真实 IP。没有它们的话request.META[REMOTE_ADDR]永远是 127.0.0.1像django-ratelimit、登录日志里记录的全部是本机地址排查线上问题时非常误导人。4.3 域名解析与 HTTPS 证书申请 SSL 的两个前置条件站点配置保存后先把本地电脑的hosts文件临时解析一下域名到服务器 IP确认 Nginx 配置的转发链路通了再改线上 DNS。在hosts里加一行服务器IP www.example.com然后浏览器访问http://www.example.com能看到 Django 页面就说明反向代理没问题。域名线上生效后到宝塔网站的 SSL 页面申请 Lets Encrypt 证书。这里常见报错是allinssl 宝塔测试请求失败我看过很多人因为这个问题放弃 HTTPS其实原因基本就两个一是域名解析没生效证书申请机构验证域名所有权时访问不到你的服务器安装前先在其它电脑上ping域名确认已经解析到你服务器的 IP二是服务器的 80 端口不通Lets Encrypt 的证书签发验证走的是 80 端口的 HTTP 请求如果服务器安全组只放行了 443 没放行 80申请必失败。这两个条件都满足后宝塔会自动申请并部署证书同时在 Nginx 配置里生成 443 端口的 server 块你只需要把配置里的proxy_pass等参数同样填到新生成的 443 配置块里即可。5. 部署避坑Django 项目起不来的五个常见问题5.1 面板提示“内存不足”装不上这个提示到底是不是硬门槛现象执行宝塔安装脚本时终端输出类似于“对不起您的服务器内存小于 3700MB无法安装宝塔面板”的提示然后安装中断。很多新手看到这行字就以为必须升级服务器内存其实不是。原因这是宝塔安装脚本里的一个内存判断逻辑阈值设得比较高用来提醒小内存用户不要盲目装完整版面板。但对纯 Django 部署场景来说面板本身加 Python 项目的内存占用通常在 1GB 到 1.5GB 之间2GB 内存的机器跑起来很轻松。解决找到安装脚本里的内存检测代码段或者直接在安装命令尾部添加跳过检测的参数wget -O install.sh https://download.bt.cn/install/install_6.0.sh echo -e y | bash install.sh --skip-memory-check注意跳过检测不意味着可以肆无忌惮地在面板里安装 MySQL 8.0、PHP、Redis 全家桶。小内存机器上装面板后只装 Nginx 和 Python 项目管理器这两个必备应用就够了数据库建议用面板单独装 MySQL 5.7其它用不到的服务一律不装。别同时开一堆服务内存吃满后面板会直接打不开Django 进程也会被系统 OOM Killer 杀掉日志里到处是Killed字样排查起来极其痛苦。5.2 页面显示 502 Bad Gateway进程没起来还是端口不对现象按教程配置完 Nginx浏览器访问域名返回 Nginx 默认的 502 Bad Gateway 页面。原因502 的意思是 Nginx 无法连上上游应用。上游 Django 进程没启动、端口监听错误、或防火墙挡了 8000 端口都会出现 502。解决首先到 Python 项目管理器页面确认项目状态是否显示“运行中”如果显示“停止”先看启动日志日志里常见的报错是ModuleNotFoundError: No module named django。这说明虚拟环境没有正确激活检查项目的 Python 解释器路径是否指向了/www/wwwroot/mydjango/.venv/bin/python而不是系统 Python。日志没报错但状态还是停止就手动在命令行跑一次启动命令cd /www/wwwroot/mydjango source .venv/bin/activate gunicorn mydjango.wsgi:application -b 0.0.0.0:8000 --workers 3 --timeout 60如果这个命令能正常运行不报错说明 Python 项目管理器的配置有问题重点检查“启动文件”字段是填了mydjango/wsgi.py还是wsgi.py必须带项目配置目录名作为前缀。确认进程起来后用curl http://127.0.0.1:8000测试本机回环地址如果 curl 输出 404 或者 HTML 内容说明端口没问题问题出在 Nginx 的proxy_pass配置的端口号和 gunicorn 监听的端口号不一致。改掉其中一边即可。5.3 collectstatic 后 CSS 依旧 404alias 路径与 STATIC_ROOT 不一致现象部署完成后页面能打开但所有 CSS、JS、图片全部 404浏览器控制台报一堆Failed to load resource: the server responded with a status of 404。原因这是部署中最容易翻车的地方本质是 Nginx 里写的别名路径和 Django 的STATIC_ROOT实际路径没对上。我见过有人改了STATIC_ROOT后忘了重新执行collectstatic目录里根本没有文件也有人把 Nginx 的alias路径写错了一层目录。解决按三步排查。第一步在服务器上用ls /www/wwwroot/mydjango/staticfiles/确认收集后的静态文件确实存在如果目录为空重新执行一遍collectstatic。第二步确认 Nginx 配置里location /static/的alias路径末尾的staticfiles目录名和你settings.py里的STATIC_ROOT一致注意alias的路径必须以/结尾否则 Nginx 拼接 URL 时会丢失最后一个斜杠。第三步改完 Nginx 配置后执行nginx -t测试语法然后nginx -s reload重载配置这一步很多人忘掉改了配置不重载浏览器刷新出来还是旧页面。另外VSCode 里写的img标签如果用的是绝对路径/static/images/logo.png本地开发服务器能识别是因为 DEBUG 模式下的 Django 自带静态文件服务生产环境必须依赖 Nginx 的alias两者路径要一致。5.4 页面上传文件后无法访问media 目录没配 Nginx现象Django admin 或用户上传图片成功但访问上传后的文件地址返回 404。比如上传了头像控制台显示请求http://example.com/media/avatar/2024/a.png返回 404。原因Django 默认把上传文件存到MEDIA_ROOT目录但生产环境下你只在 Nginx 里配置了location /static/没有配置location /media/所以浏览器请求/media/时 Nginx 找不到对应路径自然返回 404。解决在 Nginx 配置文件里加上media的 location 块location /media/ { alias /www/wwwroot/mydjango/media/; expires 30d; }同时检查/www/wwwroot/mydjango/media/目录的属主是不是和运行 Nginx 的用户一致宝塔安装后 Nginx 运行用户通常是www如果项目文件是root用户上传的Nginx 进程没有读取权限也会导致 404。执行一条命令改变目录属主chown -R www:www /www/wwwroot/mydjango/media/ chown -R www:www /www/wwwroot/mydjango/staticfiles/记住一条原则凡是 Nginx 要直接读取的目录属主必须和 Nginx 运行用户一致否则后面会陆陆续续遇到权限问题。5.5 CSRF 验证失败与重定向错误ALLOWED_HOSTS和CSRF_TRUSTED_ORIGINS的连带问题现象配置完 HTTPS 后用户访问站点一切正常但一旦提交登录表单或 POST 表单页面报CSRF verification failed. Request aborted.或者DisallowedHost提示把请求的主机名加入ALLOWED_HOSTS。原因Django 3.2 以上的版本对 CSRF 校验增加了Origin头检查。当你用 HTTPS 访问站点页面里的表单请求源是https://www.example.com如果settings.py里的CSRF_TRUSTED_ORIGINS没有把这个域名加进去Django 会拒绝这个 POST 请求。至于DisallowedHost则是ALLOWED_HOSTS里漏掉了带https://前缀的域名格式或加入了www漏了裸域名。解决回到settings.py修改这两个配置ALLOWED_HOSTS [www.example.com, example.com] CSRF_TRUSTED_ORIGINS [https://www.example.com, https://example.com]改完重新执行python manage.py collectstatic切记不需要这一步不涉及静态文件只需kill -HUP主进程平滑重载 Gunicorn或者在 Python 项目管理器里点重启。这里有个实际开发中的坑本地开发时DEBUG TrueDjango 默认放行了本地 CSRF 校验所有问题都不会暴露一上服务器就原形毕露所以部署前把这两个配置的域名写全比事后去日志里翻报错快得多。6. 收尾技巧一键重启脚本、日志查看与状态确认6.1 用 shell 脚本管理 Django 进程重启、看日志、确认存活部署完成的标志不是页面能打开而是你能在这个跑起来的状态下自如地更新代码。Django 项目更新代码后静态文件和 Python 代码需要不同的处理方式每次手动敲collectstatic、重启 Gunicorn 很繁琐。我在服务器上习惯放一个deploy.sh把这一步固定下来#!/bin/bash # deploy.sh - 部署完成后一键更新 cd /www/wwwroot/mydjango source .venv/bin/activate # 1. 拉取最新代码如果走 Git 部署 # git pull origin master # 2. 安装新的依赖如果有变动 pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple # 3. 数据库迁移 python manage.py migrate # 4. 重新收集静态文件 python manage.py collectstatic --noinput # 5. 重启进程通过 Python 项目管理器的命令行工具或直接 kill 主进程 pkill -f gunicorn sleep 2 gunicorn mydjango.wsgi:application -b 0.0.0.0:8000 --workers 3 --timeout 60 --daemon echo 部署完成进程状态 ps aux | grep gunicorn | grep -v grep这一步脚本是关键尤其--daemon参数让 Gunicorn 在后台运行不加这个参数你 SSH 断开的时候进程就跟着一起被杀了。很多人部署完没问题关掉终端再访问就 502原因就是用了前台启动。在 Python 项目管理器里配置的话你不需要这个脚本手动点重启也行但我始终觉得把部署动作用脚本固化下来比每次去面板里点鼠标更可靠特别是在改完代码反复调试的阶段。脚本里每一步都有明确输出哪一步挂了你能立刻看到不会出现“面板上显示运行中但页面是旧的”这种模糊状态。6.2 从日志定位问题Gunicorn 错误日志与 Nginx error.log 的分工最后记住一条日志排查的黄金法则浏览器看到什么错误先去 Nginx 日志里找答案再顺藤摸瓜看 Django 日志。宝塔面板在网站页面的“日志”菜单里能直接看到 Nginx 的 access.log 和 error.log但 Django 的应用日志不在这里它需要你配置 Gunicorn 时指定日志文件。我一般在启动命令里加上两个参数--error-logfile /www/wwwroot/mydjango/logs/gunicorn-error.log --access-logfile /www/wwwroot/mydjango/logs/gunicorn-access.log这样 Django 的每个请求和异常都有记录。看日志的习惯直接决定你排查问题的速度。502 优先看 Gunicorn 的错误日志看它抛出的异常堆栈404 优先看 Nginx 的 access log 和 Django 的 URL 配置确认请求到达了哪一层500 则直接翻 Django 异常页面——如果你设置了DEBUG False且没配置LOGGING500 时浏览器只会显示一个粗糙的“Server Error”页面所以日志目录务必在部署前建好否则出问题时会抓瞎。我的习惯是日志目录固定与项目路径同级部署前先mkdir -p logs并chown -R www:www logs确保 Gunicorn 和 Nginx 都有写入权限。部署这条路走通一次之后所有项目都是同一套动作环境、依赖、Nginx、日志。我在这个流程上踩过最惨的一次跟今天说的完全一样---alias写错静态文件 404 排查了一下午最后发现就是root和alias的区别从那以后我每次写 Nginx 配置前都会在心里默念一遍“alias 是替换、root 是拼接”你也记住这句话能少走很多弯路。希望帮到你。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价