Django 项目远程服务器部署教程:从开发到生产

摘要: 本文以 djangotutorial 项目为例,详细讲解如何将 Django 项目从本地开发环境部署到远程 Linux 服务器。覆盖服务器环境准备、Nginx 反向代理配置、Systemd 服务管理、生产环境 settings.py 修改,以及常见问题的排查思路。部署完成后,项目可通过域名或 IP 对外提供服务。
版本与环境(本文按此配置书写):

  • Django:6.0.2
  • Python:3.12
  • 前端:React + Vite
  • 服务器系统:CentOS 8(命令与 Ubuntu/Debian 基本等价)
  • 服务器用户:普通用户

部署模式选择与版本矩阵

在执行下面的步骤前,请先确认你的目标服务器环境,选择合适的部署轨道:

  • 现代轨(推荐于新环境)
    • Python 3.12、Django 5.2+/6.x、Node 18/20、Vite 6/7
    • 适用于有权限升级系统、内存资源充足的服务器
  • 兼容轨(面向受限服务器,当前目标)
    • Python 3.6.8、Django 3.2.x(LTS)、Node 16.20.2、Vite 4.x
    • SQLite 系统版本过低时,使用 pysqlite3-binary 提供新版本 SQLite
    • 前端构建链需降级(Vite/ESLint/Vitest/Playwright 等)

后文保留现代轨示例,同时在关键位置补充"兼容轨"的差异步骤与版本约束。请务必按所选轨道执行相应命令与版本固定,避免不可复现的问题。

一、环境准备

1.1 服务器端安装基础依赖

bash 复制代码
# CentOS 8
curl -fsSL https://rpm.nodesource.com/setup_18.x | sudo bash -
sudo yum install -y nodejs python3 python3-devel gcc git

# 启用 epel 并安装 Nginx
sudo yum install -y epel-release
sudo yum install -y nginx

# 启用并启动 Nginx
sudo systemctl enable nginx
sudo systemctl start nginx

注意: 如果使用 Ubuntu/Debian,将 yum install 替换为 apt install 即可。

兼容轨提示(Node 16.20.2):

  • 如果服务器 Node 仅有 16.x,建议前端采用本地构建后上传产物(见下文"前端构建(兼容轨)")。
  • 若必须在服务器构建,请将前端依赖降级到 Node 16 兼容版本(Vite 4.x 等)。

1.2 创建项目目录并上传代码

bash 复制代码
# 在服务器上创建项目目录(建议使用 /var/www 或 /home 下的普通用户目录)
sudo mkdir -p /var/www/djangotutorial
sudo chown -R $USER:$USER /var/www/djangotutorial

# 将本地项目上传到服务器(可在本地执行)
scp -r D:/Work/Django/djangotutorial/* user@your_server_ip:/var/www/djangotutorial/

1.3 配置 Python 虚拟环境

bash 复制代码
cd /var/www/djangotutorial

# 创建虚拟环境
python3 -m venv .venv

# 激活虚拟环境
source .venv/bin/activate

# 安装依赖(项目根目录已有 requirements.txt)
pip install -r requirements.txt

requirements.txt 已通过 python_version 等环境标记区分不同 Python 版本的依赖范围:

  • 现代轨(Python ≥3.10):安装 Django 5.2+、Vite 6/7 等现代版本
  • 兼容轨(Python 3.6.8):自动选择 Django 3.2.x、DRF 3.14.x、simplejwt 4.1--<4.5、django-cors-headers 3.x、Pillow 8.4--<10、gunicorn 20.1 等

兼容轨额外说明(Py3.6):

  • 升级工具链(只在 Py<3.7 执行):

    bash 复制代码
    python -m pip install --upgrade "pip<22.4" "setuptools<60" "wheel<0.39"

避免新版 pip/工具在 Py3.6 下不兼容。


二、生产环境 settings.py 修改

2.1 创建生产环境配置文件

文件路径:
D:\Work\Django\djangotutorial\djangotutorial\settings_production.py

项目已支持通过环境变量切换生产配置,最关键的几项:

python 复制代码
import os
from pathlib import Path

BASE_DIR = Path(__file__).resolve().parent.parent

# ========== 核心安全配置 ==========
SECRET_KEY = os.environ.get(
    "DJANGO_SECRET_KEY",
    "django-insecure-请在生产环境替换为随机密钥"
)

DEBUG = os.environ.get("DJANGO_DEBUG", "False") == "True"

ALLOWED_HOSTS = os.environ.get(
    "DJANGO_ALLOWED_HOSTS",
    "your_domain.com,www.your_domain.com"
).split(",")

# ========== 生产环境必须关闭 DEBUG ==========
# 关闭后 Django 不再显示详细错误页面
# 错误信息写入日志而非返回给用户

2.2 关键配置项说明

INSTALLED_APPS(确保已安装的核心应用):

python 复制代码
INSTALLED_APPS = [
    "corsheaders",           # CORS 跨域支持
    "rest_framework",        # DRF API 框架
    "rest_framework_simplejwt",  # JWT 鉴权
    "simpleui",              # Admin 主题(可选)
    # 你的业务应用
    "polls.apps.PollsConfig",
    "blog.apps.BlogConfig",
    "portfolio.apps.PortfolioConfig",
    "lab_management.apps.LabManagementConfig",
    # Django 内置应用
    "django.contrib.admin",
    "django.contrib.auth",
    "django.contrib.contenttypes",
    "django.contrib.sessions",
    "django.contrib.messages",
    "django.contrib.staticfiles",
]

STATIC 和 MEDIA 配置:

python 复制代码
# STATIC_URL 和 STATIC_ROOT 必须区分
# 开发环境:DEBUG=True 时 Django 自动从各 app 的 static/ 目录查找静态文件
# 生产环境:DEBUG=False 时所有静态文件由 Nginx 直接提供服务

STATIC_URL = "/static/"
STATIC_ROOT = BASE_DIR / "staticfiles"   # collectstatic 收集到的目标目录

MEDIA_URL = "/media/"
MEDIA_ROOT = BASE_DIR / "media"           # 用户上传文件存储目录

生产环境环境变量建议值:

bash 复制代码
# 在服务器上设置(可写入 /etc/environment 或 Systemd service 文件)
export DJANGO_DEBUG=False
export DJANGO_SECRET_KEY="你的随机密钥"
export DJANGO_ALLOWED_HOSTS="your_domain.com,www.your_domain.com"

ALLOWED_HOSTS 提示: 首次上线建议同时加入服务器 IP(例如 112.126.28.128),并保留环境变量覆盖能力,避免解析未生效时被 400。


2.3 SQLite 版本兼容(兼容轨)

适用场景: 服务器系统 SQLite 版本较老(如 3.7.17),而 Django 3.2 需要 ≥3.8.3。

  • 本项目已在 requirements 增加:

    复制代码
    pysqlite3-binary==0.4.6; python_version<"3.7" and sys_platform!="win32"
  • 并在 manage.pydjangotutorial/wsgi.pydjangotutorial/asgi.py 中注入:

    python 复制代码
    import pysqlite3 as _pysqlite3
    import sys as _sys
    _sys.modules["sqlite3"] = _pysqlite3

这样可在不升级系统 SQLite 的前提下满足 Django 要求。

验证:

bash 复制代码
python -c "import sqlite3; print(sqlite3.sqlite_version)"
# 输出应 ≥ 3.8.3
python manage.py check

三、配置 Systemd 服务(守护 Django 进程)

3.1 创建 Service 文件

文件路径: /etc/systemd/system/djangotutorial.service

ini 复制代码
[Unit]
Description=Gunicorn daemon for Django Tutorial Project
After=network.target

[Service]
User=root
Group=root
WorkingDirectory=/var/www/djangotutorial
EnvironmentFile=/etc/djangotutorial.env
ExecStart=/var/www/djangotutorial/.venv/bin/gunicorn \
    --workers 3 \
    --bind unix:/var/www/djangotutorial/djangotutorial.sock \
    --timeout 120 \
    --access-logfile /var/www/djangotutorial/logs/access.log \
    --error-logfile /var/www/djangotutorial/logs/error.log \
    djangotutorial.wsgi:application

Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target

说明: djangotutorial.wsgi:application 中的 djangotutorial 是项目配置包目录名,即 djangotutorial\djangotutorial\wsgi.py 中的 wsgi.py 文件暴露的 application 对象。

安全建议: 实际部署请使用非 root 用户(如 www-data / 自建 appuser),并确保 Unix Socket 的拥有者与 Nginx 运行用户匹配,避免 502 与权限问题。

3.2 创建日志目录并重载 Systemd

bash 复制代码
sudo mkdir -p /var/www/djangotutorial/logs

# 重载 Systemd 配置
sudo systemctl daemon-reload

# 启用并启动服务
sudo systemctl enable djangotutorial
sudo systemctl start djangotutorial

# 检查服务状态
sudo systemctl status djangotutorial

四、配置 Nginx 反向代理

4.1 创建 Nginx 配置文件

文件路径: /etc/nginx/conf.d/djangotutorial.conf

nginx 复制代码
server {
    listen 80;
    server_name your_domain_or_ip;

    # ========== 静态文件(由 Nginx 直接服务)==========
    location /static/ {
        alias /var/www/djangotutorial/staticfiles/;
        # 生产环境可添加缓存头
        expires 30d;
        add_header Cache-Control "public, immutable";
    }

    # ========== 用户上传文件 ==========
    location /media/ {
        alias /var/www/djangotutorial/media/;
    }

    # ========== 前端构建产物(如果有独立前端)==========
    location /frontend/ {
        alias /var/www/djangotutorial/frontend/dist/;
        try_files $uri $uri/ /index.html;
    }

    # ========== 动态请求转发给 Gunicorn ==========
    location / {
        proxy_set_header Host $http_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_redirect off;

        # Gunicorn 通过 Unix Socket 通信(比 TCP 更高效)
        proxy_pass http://unix:/var/www/djangotutorial/djangotutorial.sock;
    }
}

4.2 验证并重载 Nginx

bash 复制代码
# 检查 Nginx 配置语法
sudo nginx -t

# 重载配置
sudo systemctl reload nginx

2.5 前端构建(兼容轨:Node 16.20.2)

依赖版本固定:

  • vite → ^4.5.3
  • @vitejs/plugin-react → 3.1.0
  • vite-tsconfig-paths → ^4.2.1
  • vitest → ^0.29.x
  • eslint → ^8.57.x
  • @typescript-eslint/parser 与 eslint-plugin → ^5.62.x
  • jsdom → ^22.x
  • @playwright/test / playwright → ^1.40.x(若无需 e2e 可移除)

方案 A:服务器构建(Node 16)

bash 复制代码
cd /var/www/djangotutorial/frontend
rm -rf node_modules package-lock.json
npm install
npm run build

方案 B:本地构建 + 上传产物(低内存推荐)

bash 复制代码
# 在本地 Node 16 环境
cd frontend
rm -rf node_modules package-lock.json
npm install && npm run build

# 上传 dist 到服务器
scp -r dist user@your_server_ip:/var/www/djangotutorial/frontend/

验证:构建完成后,Nginx 可直接从 /var/www/djangotutorial/frontend/dist/ 提供前端静态文件。


五、首次部署与初始化

5.1 执行数据库迁移

bash 复制代码
cd /var/www/djangotutorial
source .venv/bin/activate
python manage.py migrate

5.2 收集静态文件

bash 复制代码
# 将所有 app 的静态文件收集到 STATIC_ROOT 目录
python manage.py collectstatic --noinput

5.3 创建初始管理员账号

bash 复制代码
# 交互式创建超级管理员
python manage.py createsuperuser

# 如果项目提供了初始化命令(参考 D:\Work\Django\djangotutorial)
python manage.py init_default_accounts

5.4 验证部署

bash 复制代码
# 检查 Gunicorn Socket 是否正常创建
ls -la /var/www/djangotutorial/djangotutorial.sock

# 查看 Gunicorn 日志
tail -f /var/www/djangotutorial/logs/error.log

# 用 curl 本地测试
curl -H "Host: your_domain_or_ip" http://127.0.0.1/

六、自动化部署脚本

项目根目录已有 deploy.shdjangotutorial\deploy.sh),在服务器上执行即可完成拉取代码→安装依赖→构建前端→迁移数据库→收集静态文件→重启服务的一条龙部署:

bash 复制代码
cd /var/www/djangotutorial

# 添加执行权限
chmod +x deploy.sh

# 自动化部署(会检测端口、创建虚拟环境、执行迁移)
./deploy.sh

部署结果:

重要: 部署前建议在本地完成测试,确保 DEBUG=False 环境下项目能正常运行。


七、常见问题排查

1) 502 Bad Gateway

现象: 浏览器访问返回 502。

排查步骤:

bash 复制代码
# 1. 检查 Gunicorn 是否正在运行
sudo systemctl status djangotutorial

# 2. 检查 Socket 文件是否存在
ls -la /var/www/djangotutorial/djangotutorial.sock

# 3. 查看 Gunicorn 错误日志
cat /var/www/djangotutorial/logs/error.log

# 4. 手动启动 Gunicorn 看是否有报错
source .venv/bin/activate
gunicorn djangotutorial.wsgi:application --bind unix:/var/www/djangotutorial/djangotutorial.sock --timeout 120 --log-file -

常见原因:

  • Gunicorn 启动失败(Python 依赖缺失、端口被占用)
  • Socket 文件权限不足(检查 djangotutorial.sock 的所有者是否为 Nginx 运行用户)
  • Django 代码有报错(Gunicorn 日志中会体现)

2) 静态文件 404

现象: CSS/JS 文件加载失败,控制台显示 404。

排查步骤:

bash 复制代码
# 1. 确认 STATIC_ROOT 目录存在且有内容
ls -la /var/www/djangotutorial/staticfiles/

# 2. 确认 Nginx 配置的 alias 路径与 STATIC_ROOT 一致
# 3. 重新执行 collectstatic
python manage.py collectstatic --noinput

典型错误配置:

nginx 复制代码
# ❌ 错误:Nginx alias 路径末尾没有斜杠,导致路径拼接错误
location /static/ {
    alias /var/www/djangotutorial/staticfiles;  # 缺少 /
}

# ✅ 正确
location /static/ {
    alias /var/www/djangotutorial/staticfiles/;
}

3) DEBUG=False 后页面样式异常

原因: 生产环境 Django 不再自动提供静态文件服务,所有静态资源需由 Nginx 提供。

解决:

  1. 确保已执行 python manage.py collectstatic
  2. 确保 Nginx 配置中 location /static/ 指向 STATIC_ROOT
  3. 清除浏览器缓存后重试

4) 数据库迁移后数据丢失

原因: 使用 SQLite 且 DEBUG=True 时数据库文件路径可能与生产环境不一致。

解决:

  • 生产环境建议使用 MySQL/PostgreSQL,路径在 settings.py 中明确指定
  • 切换数据库前务必备份:cp db.sqlite3 db.sqlite3.bak
  • 迁移前先检查 DATABASES 配置是否正确

5) ALLOWED_HOSTS 配置错误导致全部拒绝

现象: 访问网站返回 400 Bad Request。

python 复制代码
# settings.py 中 ALLOWED_HOSTS 必须包含请求的 Host 头
ALLOWED_HOSTS = os.environ.get(
    "DJANGO_ALLOWED_HOSTS",
    "your_domain.com,www.your_domain.com,112.126.28.128"
).split(",")

提示: 首次部署时建议同时把服务器 IP 加进去,避免域名解析前的访问被拦截。


6) CORS 问题(前后端分离项目)

现象: API 请求被浏览器拦截,控制台显示 CORS policy

python 复制代码
# settings.py 中配置 CORS 白名单
CORS_ALLOWED_ORIGINS = os.environ.get(
    "DJANGO_CORS_ALLOWED_ORIGINS",
    "https://your_domain.com,http://your_domain.com"
).split(",")
bash 复制代码
# 生产环境切勿使用通配符 *
# ❌ CORS_ALLOWED_ORIGINS = ["*"]  # 仅开发环境可用

7) Node/Vite 版本不匹配(构建时报 Node≥18)

现象: Vite 提示需要 Node 18+。

解决:

  • 将 Vite 降级到 4.x,并同步降级 @vitejs/plugin-react 等(详见"前端构建(兼容轨)")。
  • 或升级服务器 Node 至 18/20(现代轨)。

验证:node -v 输出 16.x 且 npm run build 成功完成。


8) pip 安装失败(Py3.6 环境)

现象: 安装新版 pip/setuptools/wheel 或某些包失败。

解决:

bash 复制代码
python -m pip install --upgrade "pip<22.4" "setuptools<60" "wheel<0.39"
pip install -r requirements.txt

验证:依赖安装全部成功,python manage.py check 无报错。


9) SQLite 版本不足(OperationalError/功能缺失)

现象: 迁移或运行时报与 SQLite 版本相关的错误。

解决: 启用 pysqlite3-binary 并在入口处替换 sqlite3(本项目已内置)。

验证:

bash 复制代码
python -c "import sqlite3; print(sqlite3.sqlite_version)"
# 应 ≥ 3.8.3

八、总结

部署 Django 项目到远程服务器的核心流程:

  1. 服务器环境准备 → 安装 Nginx、Python、Node.js(前端构建)
  2. 上传代码 + 配置虚拟环境python3 -m venv .venv && pip install -r requirements.txt
  3. 修改 settings.py 生产配置DEBUG=False、配置 ALLOWED_HOSTS、正确设置 STATIC_ROOT
  4. 配置 Systemd → 用 Gunicorn 托管 Django 进程,Unix Socket 与 Nginx 通信
  5. 配置 Nginx → 反向代理转发动态请求,直接服务静态文件
  6. 迁移 + 初始化migratecollectstaticcreatesuperuser
  7. 验证 → 检查 502、静态文件、CORS 等常见问题

整个流程的自动化脚本已在 deploy.sh 中实现。后续维护只需在本地更新代码后执行 ./deploy.sh 即可完成一键部署。


参考仓库:

相关推荐
钛态4 小时前
Vite 中的 CSS 工程化:从 CSS Modules 到 UnoCSS 的渐进式迁移
前端·vue·react·web
临沂GEO6 小时前
GEO搜索优化科普|正规地理位置流量运营入门指南
大数据·人工智能·python·流量运营
大模型码小白6 小时前
Spring AI Tool 实现自然语言操作 MySQL 数据库详解
服务器·开发语言·数据库·人工智能·python·mysql·spring
荷蒲8 小时前
【小白量化Qbuddy】利用AI学习中文Python
人工智能·python·学习
数据狐(Datafox)9 小时前
京东商品列表API技术解析与落地应用(含标准 JSON 示例)
java·大数据·前端·人工智能·python·数据分析·json
量化吞吐机9 小时前
2026年下半年手工交易规则走向量化表达,产品该先接住哪一步
人工智能·python
Metaphor69210 小时前
使用 Python 读取和删除 Excel 文件属性
python·excel
迷迭香yy11 小时前
Python构建转融券多空识别系统从接口到因子的全流程 IG50免费开源股票数据API接口
开发语言·python·开源
月光船幽幽11 小时前
真实即粗糙,光滑是伪造
人工智能·python
一次旅行11 小时前
Attention机制从数学到工程:拆解缩放点积+多头注意力|附可运行PyTorch实现与踩坑指南
人工智能·pytorch·python