在 DigitalOcean Droplets 上部署 Python Django 指南 2026
本指南逐步引导你在 DigitalOcean Droplet 上部署 Python Django 网络应用,从使用 virtualenv 准备机器、安装 Gunicorn、连接 PostgreSQL、配置 Nginx 反向代理,到使用 Let's Encrypt 启用免费 SSL — 完整提供每个阶段可立即运行的实际命令。适合想要完全控制生产环境而无需依赖 PaaS 平台的开发人员。
目录
设置 Droplet 和 Python virtualenv
在部署 Django 之前,选择适合你项目的 Droplet 大小。对于流量较低的小到中型应用程序,每月 $6 的基础 Droplet(1 GiB RAM、1 vCPU、25 GB SSD、1,000 GiB 传输)足以在同一机器上运行使用 Gunicorn 和 Nginx 的网络应用。如果你预期有并发用户或计划在同一机器上运行 PostgreSQL,请考虑升级到每月 $12 的计划(2 GiB RAM、1 vCPU、50 GB SSD、2,000 GiB 传输)以避免内存问题。对于泰国用户,选择 sgp1 区域(新加坡)获得最低延迟,其次是 blr1(班加罗尔)。Droplet 创建后并使用 SSH 密钥身份验证,使用 ssh root@your_droplet_ip SSH 进入机器。始终先使用 apt update && apt upgrade -y 更新系统。接下来,使用 adduser deployer 创建单独的非根用户以提高安全性,然后使用 usermod -aG sudo deployer 授予 sudo 权限。使用 su - deployer 切换到新用户。安装 Python 和创建虚拟环境的必要工具:sudo apt install python3-venv python3-pip build-essential -y。Python 3 预装在 Ubuntu 24.04 LTS 中,但你需要单独安装 venv 包。准备好后,为每个应用创建项目文件夹和虚拟环境以防止同一 Droplet 上多个项目之间的库版本冲突:mkdir -p ~/myproject && cd ~/myproject 然后 python3 -m venv venv,然后使用 source venv/bin/activate 激活它。终端提示符会在开头显示 (venv) 以确认虚拟环境已激活。从此刻起,通过 pip 安装的所有 Python 包都将单独存储在 venv 文件夹中,不会混入系统。这是将 Django 部署到生产环境的标准做法。
- 基础 Droplet 每月 $6(1 GiB RAM)足以用于小型应用;如果在同一机器上运行数据库,建议每月 $12(2 GiB RAM)
- sgp1 区域(新加坡)为泰国用户提供最低延迟,其次是 blr1(班加罗尔)
- 在生产使用前,始终使用 adduser + usermod -aG sudo 创建非根用户
安装 Django 和 Gunicorn
激活虚拟环境后,使用一条命令安装生产 Django 部署的三个必要包:pip install django gunicorn psycopg2-binary。Django 是核心框架,Gunicorn 是 WSGI HTTP 服务器,用于运行你的 Python 应用程序而非 Django 的内置开发服务器,psycopg2-binary 是 Python 的 PostgreSQL 驱动程序。接下来,使用 django-admin startproject myproject . 在当前文件夹中创建新的 Django 项目(注意末尾的点以避免创建嵌套目录)。继续之前,测试应用是否使用开发服务器运行:python manage.py runserver 0.0.0.0:8000,然后使用 sudo ufw allow 8000 打开端口 8000 通过浏览器使用你的 Droplet IP 测试。此步骤仅用于调试 — 永远不要在生产中保持端口 8000 开放,因为开发服务器不是为处理真实流量或处理多个并发请求设计的。测试后,使用 sudo ufw delete allow 8000 关闭端口。接下来,测试使用 Gunicorn 而不是开发服务器:gunicorn --bind 0.0.0.0:8000 --workers 3 myproject.wsgi。推荐的工作进程数通常是 (2 × CPU 核心数) + 1;对于 1 vCPU Droplet,3 个工作进程是足够的。在实时运行前,编辑 myproject/settings.py 以设置 ALLOWED_HOSTS = ['your_domain.com', 'your_droplet_ip'] — 否则当通过你的域或 IP 访问时,Django 会立即返回 400 Bad Request,因为默认仅允许 localhost。一旦 Gunicorn 成功运行且没有错误,你就可以在下一步中将其配置为使用 systemd 的永久后台服务。
- pip install django gunicorn psycopg2-binary 一条命令安装所有三个
- django-admin startproject myproject .(注意点以防止嵌套文件夹)
- 先使用 gunicorn --bind 测试;设置 workers = (2×CPU)+1
连接到 PostgreSQL
对于 Django 生产环境,建议使用 PostgreSQL 而非 SQLite,因为它能更好地处理来自多个进程的并发写入。使用 sudo apt install postgresql postgresql-contrib libpq-dev -y 安装它。使用 sudo -u postgres psql 作为 postgres 用户进入 psql shell,然后为此应用创建单独的数据库和用户 — 永远不要直接从你的应用使用 postgres 用户。按顺序运行这些 SQL 命令:CREATE DATABASE myproject_db; CREATE USER myproject_user WITH PASSWORD 'your_strong_password'; ALTER ROLE myproject_user SET client_encoding TO 'utf8'; GRANT ALL PRIVILEGES ON DATABASE myproject_db TO myproject_user;,然后使用 \q 退出。接下来,修改 settings.py 将 DATABASES 部分从默认的 sqlite3 更改为 PostgreSQL:DATABASES = {'default': {'ENGINE': 'django.db.backends.postgresql', 'NAME': 'myproject_db', 'USER': 'myproject_user', 'PASSWORD': 'your_strong_password', 'HOST': 'localhost', 'PORT': '5432'}}。在实际应用中,你应该从环境变量中获取密码,而不是直接写在会提交到 git 的文件中。配置后,使用 python manage.py migrate 运行第一次迁移以在新数据库中创建 Django 的系统表,并使用 python manage.py createsuperuser 为你的团队创建管理员账户。如果你不想自己管理 PostgreSQL,DigitalOcean 提供托管 PostgreSQL 数据库,起价为每月 $15.15,提供 1 vCPU/1 GiB RAM 和 10-30 GB 存储的计划,包括自动备份和与你的网络 Droplet 的分离。这种方法降低了运营开销并消除了需要调整网络服务器大小而不影响数据库的风险(定价截至 2026 年 7 月 — 在提供商网站上验证当前价格)。
- 安装 PostgreSQL:apt install postgresql postgresql-contrib libpq-dev
- 为此应用创建单独的 DB+用户;永远不要直接从应用使用 postgres 用户
- 在 settings.py 中将 ENGINE 更改为 django.db.backends.postgresql,然后运行 migrate
- 另一种选择:托管 PostgreSQL 起价为每月 $15.15,如果你不想自己管理它
配置 Nginx 反向代理
Gunicorn 成功运行后,下一步是通过 systemd 将其作为永久后台服务运行,而不是在终端中保持命令运行。在 /etc/systemd/system/gunicorn.socket 创建 socket 文件,在 /etc/systemd/system/gunicorn.service 创建服务文件。服务文件应大致包含:[Service] User=deployer Group=www-data WorkingDirectory=/home/deployer/myproject ExecStart=/home/deployer/myproject/venv/bin/gunicorn --workers 3 --bind unix:/run/gunicorn.sock myproject.wsgi:application。使用 sudo systemctl start gunicorn.socket && sudo systemctl enable gunicorn.socket 启用它。使用 Unix socket 而不是 TCP 端口更安全,因为它不会向互联网暴露端口。使用 sudo apt install nginx -y 安装 Nginx,然后在 /etc/nginx/sites-available/myproject 创建新的配置文件。主要内容是一个服务器块,将请求代理到 Gunicorn 的 socket:server { listen 80; server_name your_domain.com; location = /favicon.ico { access_log off; log_not_found off; } location /static/ { root /home/deployer/myproject; } location / { include proxy_params; proxy_pass http://unix:/run/gunicorn.sock; } }。通过创建符号链接启用此配置:sudo ln -s /etc/nginx/sites-available/myproject /etc/nginx/sites-enabled/。重启前始终使用 sudo nginx -t 检查语法。如果没有错误出现,使用 sudo systemctl restart nginx 重启。最后,使用 sudo ufw allow 'Nginx Full' 为网络流量打开防火墙,它一次打开端口 80 和 443。如果你仍然从早期测试中打开了端口 8000,关闭它。一个常见的错误是忘记检查项目文件夹的权限 — Nginx 以 www-data 用户身份运行,必须有执行权限才能访问 deployer 的主目录。如果你看到 502 Bad Gateway,验证 gunicorn.socket 是否运行中,使用 sudo systemctl status gunicorn.socket,并使用 journalctl -u gunicorn 检查日志。
- 将 gunicorn 配置为绑定到 Unix socket 的 systemd 服务,而不是直接 TCP 端口
- Nginx 服务器块 proxy_pass 到 unix:/run/gunicorn.sock
- 重启前始终用 nginx -t 测试配置
静态文件和 SSL
基于真实使用经验,Django 出于性能原因在生产环境中不提供静态文件(CSS/JS/图像)— Nginx 必须代替进行。首先,在 settings.py 中使用 STATIC_URL = 'static/' 和 STATIC_ROOT = BASE_DIR / 'staticfiles' 定义静态文件文件夹,然后使用 python manage.py collectstatic 将来自每个应用的所有静态文件收集到一个文件夹中。每当你修改静态文件或部署新代码时,都必须重新运行此命令,否则页面会加载但没有 CSS 样式。验证 Nginx 配置的 /static/ 位置块指向正确的 staticfiles 文件夹路径。接下来,通过 Certbot 使用 Let's Encrypt 启用免费 SSL。使用 sudo apt install certbot python3-certbot-nginx -y 安装它,然后使用一条命令颁发并配置 SSL 证书:sudo certbot --nginx -d your_domain.com -d www.your_domain.com。Certbot 自动编辑你的 Nginx 配置以将 HTTP 重定向到 HTTPS,并通过在后台运行的 systemd 计时器设置自动续期,无需手动设置。使用 sudo systemctl status certbot.timer 验证计时器是否处于活跃状态。系统将在过期前每 90 天自动续期你的证书。SSL 上线后,更新 settings.py 以实现真正的生产使用:始终设置 DEBUG = False,添加 SECURE_SSL_REDIRECT = True 强制 HTTPS,并为强制严格源检查的较新 Django 版本添加 CSRF_TRUSTED_ORIGINS = ['https://your_domain.com']。在生产环境中保持 DEBUG=True 是最常见的安全错误之一 — 它会向触发错误的任何人暴露堆栈跟踪、服务器路径和所有设置。
- STATIC_ROOT + collectstatic 每次编辑静态文件或部署新代码时都必须重新运行
- certbot --nginx -d domain 颁发免费 SSL 并自动配置 HTTP→HTTPS 重定向
- certbot.timer 每 90 天自动续期证书 — 无需手动 cron 设置
- 生产必须始终设置 DEBUG=False 和 SECURE_SSL_REDIRECT=True
何时使用此方法(真实世界用例)
这里描述的自管理 Droplet 部署方法适合想要完全环境控制、需要安装专门系统库(如用于 GeoDjango 的 GDAL 或用于视频处理的 ffmpeg)或预算有限且需要可预见成本的团队。它与 App Platform(托管 PaaS)不同,App Platform 自动化基础设施但每单位规格成本更高,定制选项更少。对于低流量的新项目或 MVP,每月 $6 的基础 Droplet(1 GiB RAM)可以轻松同时运行 Django、Gunicorn、Nginx 和 PostgreSQL。随着你的应用获得真实用户和流量增长,注意警告信号:当 RAM 一贯超过 80% 或在高峰使用期间响应时间变慢时,是时候升级到每月 $12(2 GiB)或每月 $24(4 GiB、2 vCPU)。如果流量超过单机容量,下一步是使用 Load Balancer(起价每月 $12)在多个网络 Droplet 前面进行水平扩展。对于数据库,如果你按照本指南开始使用自管理 PostgreSQL,当你的团队缺乏时间处理补丁和备份,或当数据库成为你系统的瓶颈并且你想从网络服务器独立扩展它时,迁移到托管 PostgreSQL(起价每月 $15.15),这避免了不必要地调整应用机器大小。此方法的典型用例包括内部开发团队、部署多个独立客户项目的代理机构,或还不需要 Kubernetes 复杂性的小型 SaaS 初创公司。感兴趣的读者可以注册并在 获取 $200 免费信用 → 获得启动信用(本文中的所有定价截至 2026 年 7 月 — 在决定前在提供商网站上验证当前价格)。
- 适合需要完全环境控制和专门系统库的团队
- RAM 一贯超过 80% = 是时候调整到下一个计划(每月 $12 或 $24)
- 流量超过单机容量 = 添加 Load Balancer 起价每月 $12
- 团队缺乏数据库维护时间或数据库成为瓶颈 = 从每月 $15.15 切换到托管 PostgreSQL
常见错误和解决方案
这一点很重要——排名第一的错误是将 ALLOWED_HOSTS 留空或不完整,导致通过你的真实域或 IP 访问时出现 400 Bad Request,即使它在开发服务器上工作正常。通过确保你的域和 Droplet IP 都添加到 settings.py 中的列表来修复此问题。第二个常见错误是在上线前忘记设置 DEBUG = False — 如果你在生产中保持 DEBUG = True,这是一个主要的安全风险,因为错误页面会向公众显示完整的堆栈跟踪,泄露服务器路径、设置和敏感信息。使用环境变量在开发和生产之间保持 DEBUG 值分离,而不是每次编辑文件。另一个常见问题是 502 Bad Gateway,通常是由 Gunicorn 未运行或 Nginx 由于文件权限无法访问 Unix socket 导致。使用 sudo systemctl status gunicorn.socket 检查并用 journalctl -u gunicorn -n 50 检查最近日志。最常见的原因是服务文件的 ExecStart 中的路径不正确,或者写 gunicorn 二进制路径时 virtualenv 未被正确激活 — 始终验证路径完全匹配。另一个常见问题是 psycopg2-binary 安装失败,因为系统包 libpq-dev 和构建工具缺失。通过在运行 pip install 前安装 build-essential libpq-dev 来修复。静态文件问题也很常见:页面加载但没有 CSS 样式,通常是因为在新部署后忘记了 collectstatic 或 Nginx /static/ 位置路径与你的实际 STATIC_ROOT 不匹配。别忘了关闭开始时为测试留下的端口 8000。最后,一个常见的错误是拉取包含模型更改的代码后未能运行 python manage.py migrate — 你会收到关于缺失列的错误,即使代码看起来正确。将迁移作为部署脚本的一部分,使其自动运行,而不是作为你必须记住的手动步骤。
- ALLOWED_HOSTS 空/不完整 = 真实域/IP 上的 400 Bad Request
- DEBUG=True 留在生产中 = 安全风险,暴露堆栈跟踪和设置
- 502 Bad Gateway 多数来自 gunicorn.service 中的错误路径或不正确的 socket 权限
- 新部署后忘记 collectstatic / migrate = 缺失 CSS 或列错误
最佳实践
通过使用 python-dotenv 或 django-environ 等库的 .env 文件将所有秘密(SECRET_KEY、数据库密码、API 密钥)存储在环境变量中,永远不要硬编码在 settings.py 中。从第一天开始将 .env 添加到 .gitignore 以防止其泄露到你的 git 存储库中。使用 pip freeze > requirements.txt 固定所有库版本以确保你的生产环境与你在本地测试的内容匹配 — 这防止了当发布更新的依赖版本时的意外破坏。通过在服务文件中使用 Restart=always 并运行 sudo systemctl enable gunicorn 将 systemd gunicorn.service 配置为在崩溃时自动重启并在重启时启动。使用 ufw 严格应用防火墙规则以仅打开必要的端口,并考虑安装 fail2ban 来阻止来自外部的暴力破解 SSH 尝试。对于每次代码部署,遵循一致的过程:拉取代码、通过 pip install -r requirements.txt 安装任何新依赖、如果模型改变则运行 migrate、如果静态文件改变则运行 collectstatic,最后重启 gunicorn — 这最小化了停机时间并防止意外跳过一步。在进行重大更改(如升级 Django 版本或更改数据库模式)之前,请提前创建 Droplet 快照,每月仅需 $0.06/GiB — 比从头重建系统便宜得多,如果更新期间出现问题。启用 DigitalOcean 监控(免费提供每个账户一个免费 Uptime 检查)以在 RAM 或磁盘使用意外增加时获得即时警报。最后,将你的 settings.py 分离为不同的开发和生产文件,或使用环境变量跨环境控制行为不同,防止调试设置或测试值意外用于生产。
- 将秘密存储在 .env + python-dotenv/django-environ 中;永远不要提交到 git
- pip freeze > requirements.txt 固定版本以完全匹配开发/生产
- systemd Restart=always 让 gunicorn 在崩溃/重启时自动重启
- 在进行重大更改前创建 Droplet 快照($0.06/GiB/月)作为保障