在 VPS 上使用 Docker 部署 Django:分步指南
Source: Dev.to
本指南适合谁?
- 您对自托管感兴趣,并想学习基础知识。
- 您想运行小型或副业项目,而无需为昂贵的托管服务付费。
- 您想在托管费用上省钱。
谁应该跳过本指南?
- 您需要 最快速的入门方式(例如,托管的 PaaS)。
- 您想要 避免持续的维护。
- 您需要运行 关键任务工作负载,且对服务器管理不熟悉。
想要一种简单、托管的入门方式吗? 查看我们的产品:sliplane.io.
前置条件
| 要求 | 细节 |
|---|---|
| Django 应用 | 已准备好容器化 |
| VPS 账户 | Hetzner(或其他任何首选提供商) |
| 域名 | 用于 SSL 终止和反向代理 |
| Docker 知识 | 基本了解(可选但有帮助) |
我们将使用 Docker 将 Django 应用容器化,并使用 PostgreSQL 作为数据库。部署将使用 Docker Compose 完成,并使用 Caddy 作为反向代理,实现自动 SSL。
为什么使用 Docker?
Docker 让你在 Dockerfile 中定义 Django 应用所需的一切。随后,你可以启动一个已安装所有依赖的隔离容器,避免 “在我机器上可以运行” 的问题。
- 一致的环境 – 相同的 Python 版本、相同的系统库。
- 独立的服务 – 在不同容器中运行 Django 和 PostgreSQL,避免依赖冲突。
- 庞大的生态系统 – 为数据库、缓存、Web 服务器等提供预构建镜像。
如果想深入了解,请参阅我的 [Django 在 Docker 中的教程]。
TL;DR – 最小化 Docker 设置
在 Django 项目的根目录下创建两个文件:
Dockerfile
# ---------- Stage 1: Builder ----------
FROM python:3.13-slim AS builder
# Create and set the app directory
RUN mkdir /app
WORKDIR /app
# Optimize Python
ENV PYTHONDONTWRITEBYTECODE=1 \
PYTHONUNBUFFERED=1
# Upgrade pip
RUN pip install --upgrade pip
# Cache dependencies
COPY requirements.txt /app/
RUN pip install --no-cache-dir -r requirements.txt
# ---------- Stage 2: Production ----------
FROM python:3.13-slim
# Create a non‑root user and app directory
RUN useradd -m -r appuser && \
mkdir /app && \
chown -R appuser /app
# Copy Python packages from builder
COPY --from=builder /usr/local/lib/python3.13/site-packages/ /usr/local/lib/python3.13/site-packages/
COPY --from=builder /usr/local/bin/ /usr/local/bin/
WORKDIR /app
# Copy application code (preserve ownership)
COPY --chown=appuser:appuser . .
# Optimize Python (again, for the final image)
ENV PYTHONDONTWRITEBYTECODE=1 \
PYTHONUNBUFFERED=1
# Switch to non‑root user
USER appuser
# Expose the port Django will run on
EXPOSE 8000
# Start the app with Gunicorn
CMD ["gunicorn", "--bind", "0.0.0.0:8000", "--workers", "3", "myproject.wsgi:application"]
docker-compose.yml
services:
web:
build: .
ports:
- "8000:8000"
env_file:
- .env
depends_on:
- db
db:
image: postgres:17
volumes:
- postgres_data:/var/lib/postgresql/data
env_file:
- .env
volumes:
postgres_data:
本地测试
- 安装 Docker(如果尚未安装)。
- 运行:
docker compose up
Django 应用将可通过 http://localhost:8000 访问。
确保在迁移到生产环境之前本地一切正常。
生产就绪的镜像工作流
上面的 compose 文件非常适合开发,但在生产环境中并不理想,因为服务器会在每次部署时重新构建镜像。在生产环境中你应该:
-
在本地(或 CI)构建镜像。
docker build -t my-django-app . -
将其推送到容器注册表(例如 GitHub Container Registry,GHCR)。
# 认证 echo $GITHUB_TOKEN | docker login ghcr.io -u YOUR_GITHUB_USERNAME --password-stdin # 标记并推送 docker tag my-django-app ghcr.io/YOUR_GITHUB_USERNAME/YOUR_REPO_NAME:latest docker push ghcr.io/YOUR_GITHUB_USERNAME/YOUR_REPO_NAME:latest使用
latest在教程中是可以的,但在实际项目中请考虑使用语义化版本或提交哈希。 -
使用 CI/CD 流水线(例如 GitHub Actions)自动化此步骤。我有一篇单独的文章专门讨论该主题。
设置 VPS
1️⃣ 选择 VPS 提供商
我们在另一篇文章中对比了几家廉价提供商。Hetzner 以性价比高、可靠性强、性能优秀而脱颖而出。使用我们的联盟链接还能获得 20 欧元 的额度。
2️⃣ 为 VPS 选配规格
从 最小可用套餐 开始(例如 1 vCPU、2 GB RAM)。随着流量增长,随时可以向上扩容。
3️⃣ 服务器准备
-
创建新服务器(Ubuntu 22.04 LTS 是个稳妥的选择)。
-
更新系统
sudo apt update && sudo apt upgrade -y -
安装 Docker 与 Docker Compose
# 安装 Docker curl -fsSL https://get.docker.com -o get-docker.sh sudo sh get-docker.sh # 设置 Docker 开机自启 sudo systemctl enable docker # 安装 Docker Compose(v2 插件) sudo apt install -y docker-compose-plugin -
创建非 root 用户(可选但推荐)
sudo adduser deployer sudo usermod -aG docker deployer -
配置防火墙(UFW)
sudo ufw allow OpenSSH sudo ufw allow 80/tcp # HTTP sudo ufw allow 443/tcp # HTTPS sudo ufw enable
4️⃣ 部署应用
-
登录服务器 并克隆你的仓库(或直接拉取镜像)。
git clone https://github.com/YOUR_GITHUB_USERNAME/YOUR_REPO_NAME.git cd YOUR_REPO_NAME -
创建
.env文件,填写 Django 与 PostgreSQL 的配置(如DJANGO_SECRET_KEY、POSTGRES_PASSWORD等)。 -
创建
docker-compose.prod.yml,使用预构建的镜像而不是本地构建:version: "3.9" services: web: image: ghcr.io/YOUR_GITHUB_USERNAME/YOUR_REPO_NAME:latest env_file: - .env depends_on: - db restart: unless-stopped db: image: postgres:17 volumes: - postgres_data:/var/lib/postgresql/data env_file: - .env restart: unless-stopped volumes: postgres_data: -
启动容器堆栈
docker compose -f docker-compose.prod.yml up -d -
使用 Caddy 作为反向代理(自动处理 HTTPS)。创建
Caddyfile:yourdomain.com { reverse_proxy web:8000 }然后在 compose 文件中加入 Caddy:
services: caddy: image: caddy:2 ports: - "80:80" - "443:443" volumes: - ./Caddyfile:/etc/caddy/Caddyfile - caddy_data:/data restart: unless-stopped volumes: caddy_data:再次部署:
docker compose -f docker-compose.prod.yml up -dCaddy 将自动从 Let’s Encrypt 获取并续订 TLS 证书。
回顾检查清单
- Docker 化 Django 应用(
Dockerfile、docker-compose.yml)。 - 构建并推送镜像到容器注册表(GHCR)。
- 选择并配置 VPS(推荐 Hetzner)。
- 在服务器上安装 Docker 与 Docker Compose。
- 创建面向生产的
docker-compose.prod.yml。 - 设置环境变量(
.env)。 - 使用
docker compose up -d部署堆栈。 - 添加 Caddy 反向代理以实现 HTTPS。
现在,您已经在廉价的 VPS 上运行了完整的自托管 Django 应用,具备自动化 SSL 和干净、可复现的部署流水线。 🎉
祝自托管愉快!
小型 Django + Postgres VPS 快速入门清单
你会惊讶于一个基础 VPS 能做到的程度——Postgres 数据库和一个小型 Django 应用只需要 1 GB 内存就能运行。以后随时可以扩容。先保持简单:在同一台服务器上同时运行数据库和 Django 应用(参见我们关于在单个 VPS 上运行多个应用的指南)。只有在真正需要扩展时才考虑更复杂的部署方案。
1. 我希望 VPS 位于哪里?
2. 处理器架构 – x86 还是 ARM?
- ARM 越来越受欢迎,因为它更便宜,但我们遇到过供应不足和偶发的软件兼容性问题。
- 我们通常坚持使用 x86。如果你在 x86 上开发,却在 ARM 上部署,可能会遇到意想不到的问题。
- VPS 的好处在于:只为服务器运行的时间付费,所以你可以用几分钱测试一下 ARM 服务器,必要时再切回 x86。
3. 共享还是独享?
- 先使用共享,必要时再升级。
- 共享服务器通常更慢且可能不稳定,因此供应商的选择很重要。
- 使用 Hetzner 时,我们的体验不错——共享服务器的性能一直稳定可靠。
4. 我应该选择哪种操作系统?
- Ubuntu(最新 LTS 版)是安全的默认选择——我们就是在它上面学习的,社区支持最广。
- 各发行版之间的差异大多是 偏好 的问题。如果不确定,选 Ubuntu。
- 总的来说,选大众化的系统,这样在需要帮助时更容易在网上找到答案。
Source:
服务器启动后 – 首要步骤
-
通过 SSH 连接
ssh root@your-server-ip将
your-server-ip替换为提供商仪表板或欢迎邮件中显示的 IP 地址。 -
服务器加固
- 禁用 root 登录(使用具有
sudo权限的普通用户)。 - 使用 SSH 密钥代替密码。
- 设置防火墙(UFW 或 iptables)。
- 保持系统更新(
apt update && apt upgrade -y)。 - 安装 fail2ban 以阻止暴力破解尝试。
- 考虑运行经过审查的加固脚本——但务必确保了解其作用。
- 禁用 root 登录(使用具有
-
网络层防火墙(Hetzner)
- 仅允许 22(SSH)、80(HTTP) 和 443(HTTPS) 端口。
- 将 Hetzner 防火墙 与本地防火墙一起使用 可以节省资源,并在流量到达服务器前进行拦截(在 Docker 可能绕过本地规则时尤为有用)。
安装 Docker
# Remove old versions
sudo apt-get remove docker docker-engine docker.io containerd runc
# Set up the repository
sudo apt-get update
sudo apt-get install \
ca-certificates \
curl \
gnupg \
lsb-release
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | \
sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] \
https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-compose-plugin
验证安装:
docker --version
docker compose version
使用 Docker Compose 部署 Django 应用
1. 准备环境变量
在服务器上的项目目录中创建一个 .env 文件(切勿将此文件提交到 Git):
POSTGRES_DB=mydb
POSTGRES_USER=myuser
POSTGRES_PASSWORD=mypassword
DATABASE_URL=postgres://myuser:mypassword@db:5432/mydb
DJANGO_SECRET_KEY=your-secret-key
提示: 为了实现生产级安全,建议使用 Docker secrets 而不是普通的
.env文件。
2. 生产就绪的 docker‑compose.yml
services:
web:
image: ghcr.io/YOUR_GITHUB_USERNAME/YOUR_REPO_NAME:latest
ports:
- "8000:8000"
env_file:
- .env
depends_on:
- db
db:
image: postgres:17
volumes:
- postgres_data:/var/lib/postgresql/data
env_file:
- .env
caddy:
image: caddy:2.10.2
restart: unless-stopped
cap_add:
- NET_ADMIN
ports:
- "80:80"
- "443:443"
volumes:
- $PWD/conf:/etc/caddy
- caddy_data:/data
- caddy_config:/config
volumes:
postgres_data:
caddy_data:
caddy_config:
3. 配置 Caddy
在 docker‑compose.yml 同级目录下创建 conf 文件夹,并在其中添加 Caddyfile:
yourdomain.com {
reverse_proxy web:8000
}
将 yourdomain.com 替换为你的实际域名。
Caddy 会自动为该域名获取 Let’s Encrypt 证书。
4. 将 DNS 指向 VPS
为你的域名添加指向 VPS IP 地址的 A(或 AAAA)记录。解析通常在几分钟内完成。
5. 启动整个堆栈
docker compose up -d
现在你应该可以通过 https://yourdomain.com 访问你的 Django 应用。
6. 部署新版本
docker compose pull web # 拉取最新镜像
docker compose up -d web # 仅重启 web 服务
你可以使用 CI/CD 流水线(GitHub Actions、GitLab CI 等)实现自动化部署。
回顾 – 本指南中使用的组件
| Component | Purpose |
|---|---|
| Docker | 将 Django 应用容器化 |
| Docker Compose | 编排 Django、Postgres 和 Caddy |
| Postgres | 关系型数据库 |
| Caddy | 反向代理 + 自动 TLS |
| Hetzner firewall | 网络层流量过滤 |
| UFW / iptables | 主机层防火墙 |
| fail2ban | 保护 SSH 及其他服务免受暴力攻击 |
| .env file (or Docker secrets) | 存储敏感配置 |
最后思考
在普通 VPS 上部署 Django 既便宜又快速,是学习基础设施的绝佳方式。先保持简单,及早进行安全加固,让 Docker 和 Caddy 负责大部分繁重工作。当流量增长时,你可以将服务拆分到不同机器上,添加负载均衡器,或迁移到托管平台——但对于多数中小型项目而言,上述配置已经足够。祝编码愉快!