00 / 00

Docker 部署

用 Dockerfile 部署到 Zeabur、自有服务器或容器平台。

Docker 部署适合需要自管运行时镜像的场景,例如自有 VPS、K8s,或团队已经有统一容器平台。01MVP 默认生产部署可以直接看 Zeabur 部署

Docker 路径使用 Vite Plus 构建 @01mvp/web,并运行 products/01mvp/apps/web/dist 生产产物。生产密钥优先在运行时注入,不要把真实密钥写入镜像层或提交到仓库。

Zeabur Docker 模式

连接仓库

在 Zeabur 控制台创建服务,连接 Git 仓库。

配置构建

在服务设置中:

  • 工作目录设为仓库根目录
  • 启用 Dockerfile 部署模式
  • 设置环境变量:
ZBPACK_APP_DIR=products/01mvp/apps/web
ZBPACK_DOCKERFILE_NAME=Dockerfile

Zeabur 会使用仓库根目录的 Dockerfile 构建镜像。完整的变量同步、域名和 Cloudflare 配置见 Zeabur 部署

在 Zeabur Variables 中用平台域名变量生成公开 URL,不要把某个固定站点写进镜像:

VITE_WEB_URL=https://${ZEABUR_WEB_DOMAIN}
VITE_SERVER_URL=https://${ZEABUR_WEB_DOMAIN}/api

ZEABUR_WEB_DOMAIN 是域名本身,不带协议和尾部斜杠;Dockerfile 在没有显式 VITE_WEB_URL 时也会用它生成构建期 URL。

配置运行时环境变量

在 Zeabur 服务的 "Variables" 页面添加生产环境变量。变量名与部署指南一致。

Zeabur 提供的内置变量如 PORT 会自动注入,无需手动配置。VITE_WEB_URLVITE_SERVER_URL 需要同时存在于构建期和运行时,因为前端包会在构建时读取它们,服务端登录、邮件和回调也会在运行时读取它们。

绑定域名

在 Zeabur 服务的 "Networking" 页面绑定自定义域名,并在 DNS 侧配置 CNAME 指向 Zeabur 提供的地址。

部署并验证

触发部署,等待构建完成。检查服务日志确认 TanStack Start server 启动正常,再按部署后验证逐项检查。

自建服务器部署

适用于自有 VPS、K8s 或其他容器平台。

构建镜像

在仓库根目录执行:

docker build -f Dockerfile -t 01mvp-start:latest \
  --build-arg VITE_WEB_URL="https://your-domain.com" \
  --build-arg VITE_SERVER_URL="https://your-domain.com/api" \
  --build-arg DATABASE_URL="postgresql://postgres:postgres@localhost:5432/build-placeholder" \
  --build-arg BETTER_AUTH_SECRET="replace-with-at-least-32-characters" \
  .

--build-arg 会进入构建历史和缓存。这里的 DATABASE_URLBETTER_AUTH_SECRET 只用于构建期校验,占位值即可;真实生产密钥应在运行容器时通过环境变量、平台 Secret 或 docker buildx build --secret 注入。

如果构建平台提供 ZEABUR_WEB_DOMAIN,Dockerfile 可以从它推导 VITE_WEB_URLVITE_SERVER_URL;自建服务器没有这个变量时必须显式传入上面的两个 build arg。

运行容器

docker run -d \
  --name 01mvp-start \
  -p 7001:7001 \
  -e DATABASE_URL="postgresql://..." \
  -e BETTER_AUTH_SECRET="your-secret" \
  -e VITE_WEB_URL="https://your-domain.com" \
  -e VITE_SERVER_URL="https://your-domain.com/api" \
  -e OPENAI_API_KEY="your-key" \
  -e OPENAI_BASE_URL="https://api.deepseek.com" \
  -e OPENAI_MODEL="deepseek-v4-flash" \
  01mvp-start:latest

容器默认监听 7001,平台也可以通过 PORT 覆盖。运行命令为:

node /app/products/01mvp/apps/web/scripts/start-node.mjs

docker-compose 参考

先从 .env.docker.example 复制一份 .env.docker,把域名、数据库和密钥换成当前环境的值。

services:
  01mvp-start:
    build:
      context: .
      dockerfile: Dockerfile
    ports:
      - "7001:7001"
    env_file:
      - .env.docker
    restart: unless-stopped
    depends_on:
      - db

  db:
    image: postgres:16-alpine
    environment:
      POSTGRES_USER: user
      POSTGRES_PASSWORD: pass
      POSTGRES_DB: mvp
    volumes:
      - pgdata:/var/lib/postgresql/data

volumes:
  pgdata:

Dockerfile 构建流程

Dockerfile 的构建流程如下:

安装 Vite Plus Linux CLI,并复制 package.jsonpnpm-lock.yamlpnpm-workspace.yaml 以及各 workspace 的 package.json

执行 vp install --frozen-lockfile --ignore-scripts,让依赖层可以被 Docker 缓存。

复制完整源码,执行 vpr @01mvp/web#build(或根目录短写 vpr @01mvp/web#build),生成 products/01mvp/apps/web/dist/serverproducts/01mvp/apps/web/dist/client

使用 node:24-slim 作为运行时镜像,复制 products/01mvp/apps/web/dist、启动脚本、依赖和数据库 migration 文件,以非 root 用户启动服务。

生产迁移

Docker 部署不要把数据库迁移放进镜像 build。当前模板默认使用显式迁移:部署生产容器前运行 vpr @01mvp/product#db:deploy,执行已经提交的 migration 文件。

如果你在生产机器内执行,先确认当前 shell 连接的是生产库:

node -e 'const u=new URL(process.env.DATABASE_URL); console.log(u.host, u.pathname)'

常见问题

上线检查

  • 镜像使用 Dockerfile 构建
  • 生产密钥通过运行时环境变量注入
  • 容器端口 7001 已映射到外部入口
  • VITE_WEB_URLVITE_SERVER_URL 指向生产域名
  • 生产 migration 文件已提交,启动日志无迁移失败
  • 容器日志无启动错误
  • 域名、HTTPS、登录、上传和邮件已验证

这篇文档有问题?