在 VPS 上使用 Docker 部署 Django:分步指南

发布: (2025年12月27日 GMT+8 00:54)
13 分钟阅读
原文: Dev.to

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:

本地测试

  1. 安装 Docker(如果尚未安装)。
  2. 运行:
docker compose up

Django 应用将可通过 http://localhost:8000 访问。
确保在迁移到生产环境之前本地一切正常。

生产就绪的镜像工作流

上面的 compose 文件非常适合开发,但在生产环境中并不理想,因为服务器会在每次部署时重新构建镜像。在生产环境中你应该:

  1. 在本地(或 CI)构建镜像。

    docker build -t my-django-app .
  2. 将其推送到容器注册表(例如 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 在教程中是可以的,但在实际项目中请考虑使用语义化版本或提交哈希。

  3. 使用 CI/CD 流水线(例如 GitHub Actions)自动化此步骤。我有一篇单独的文章专门讨论该主题。

设置 VPS

1️⃣ 选择 VPS 提供商

我们在另一篇文章中对比了几家廉价提供商。Hetzner 以性价比高、可靠性强、性能优秀而脱颖而出。使用我们的联盟链接还能获得 20 欧元 的额度。

2️⃣ 为 VPS 选配规格

最小可用套餐 开始(例如 1 vCPU、2 GB RAM)。随着流量增长,随时可以向上扩容。

3️⃣ 服务器准备

  1. 创建新服务器(Ubuntu 22.04 LTS 是个稳妥的选择)。

  2. 更新系统

    sudo apt update && sudo apt upgrade -y
  3. 安装 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
  4. 创建非 root 用户(可选但推荐)

    sudo adduser deployer
    sudo usermod -aG docker deployer
  5. 配置防火墙(UFW)

    sudo ufw allow OpenSSH
    sudo ufw allow 80/tcp      # HTTP
    sudo ufw allow 443/tcp     # HTTPS
    sudo ufw enable

4️⃣ 部署应用

  1. 登录服务器 并克隆你的仓库(或直接拉取镜像)。

    git clone https://github.com/YOUR_GITHUB_USERNAME/YOUR_REPO_NAME.git
    cd YOUR_REPO_NAME
  2. 创建 .env 文件,填写 Django 与 PostgreSQL 的配置(如 DJANGO_SECRET_KEYPOSTGRES_PASSWORD 等)。

  3. 创建 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:
  4. 启动容器堆栈

    docker compose -f docker-compose.prod.yml up -d
  5. 使用 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 -d

    Caddy 将自动从 Let’s Encrypt 获取并续订 TLS 证书。

回顾检查清单

  • Docker 化 Django 应用(Dockerfiledocker-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:

服务器启动后 – 首要步骤

  1. 通过 SSH 连接

    ssh root@your-server-ip

    your-server-ip 替换为提供商仪表板或欢迎邮件中显示的 IP 地址。

  2. 服务器加固

    • 禁用 root 登录(使用具有 sudo 权限的普通用户)。
    • 使用 SSH 密钥代替密码。
    • 设置防火墙(UFW 或 iptables)。
    • 保持系统更新(apt update && apt upgrade -y)。
    • 安装 fail2ban 以阻止暴力破解尝试。
    • 考虑运行经过审查的加固脚本——但务必确保了解其作用。
  3. 网络层防火墙(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 等)实现自动化部署。

回顾 – 本指南中使用的组件

ComponentPurpose
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 负责大部分繁重工作。当流量增长时,你可以将服务拆分到不同机器上,添加负载均衡器,或迁移到托管平台——但对于多数中小型项目而言,上述配置已经足够。祝编码愉快!

Back to Blog

相关文章

阅读更多 »