Files
hfb_sys/deploy

生产部署说明

目标访问地址:

https://主站域名          # CADDY_DOMAIN,哈夫币系统
https://选号网域名        # CADDY_SHOW_DOMAIN(可选),hfb_show 静态选号站
https://monitor.主站域名  # Beszel 监控

生产部署使用 Caddy 作为公网入口,只暴露宿主机 80443 端口。Caddy 会自动申请和续签 HTTPS 证书,并直接托管前端静态资源(主站 dist 与可选的选号网 show-dist 在构建 Caddy 镜像时打入);后端、MySQL、Redis、MinIO 均通过 Docker 内网通信。选号网与主站共用同一 backend,浏览器访问选号网域名下的 /api/* 由 Caddy 反代到本机 backend不会直连数据库

部署前请确认:

  • 主站域名 A 记录已解析到服务器公网 IP;启用选号网时,选号网域名也要解析到同一 IP。
  • 服务器安全组或防火墙已放行 80/tcp443/tcp
  • 服务器上没有其他服务占用 80443
  • 国内服务器如需对外访问,请先确认域名备案和云厂商限制。

1. 准备环境变量

cp backend/.env.prod.example backend/.env

编辑 backend/.env,至少替换以下占位值:

CADDY_DOMAIN
CADDY_EMAIL
MYSQL_ROOT_PASSWORD
MYSQL_PASSWORD
MYSQL_DSN
JWT_SECRET
MINIO_ROOT_USER
MINIO_ROOT_PASSWORD
STORAGE_ACCESS_KEY_ID
STORAGE_SECRET_ACCESS_KEY
BACKEND_UID
BACKEND_GID

BACKEND_UIDBACKEND_GID 填写服务器业务用户的数值 ID,例如:

id -u yml
id -g yml

后端容器会使用该 UID/GID 运行。部署脚本由 root 执行时会自动把已有日志修正为该属主;非 root 执行且发现旧的 root 日志时,会给出需要执行的 chown 命令后停止。

同机部署选号网(hfb_show,可选)

backend/.env 增加(域名不要带 https://):

CADDY_SHOW_DOMAIN=show.example.com
HFB_SHOW_DIR=../hfb_show

要求:

  1. 服务器上 hfb_showhfb_sys 同级目录(或 HFB_SHOW_DIR 指向真实路径)。
  2. 部署机有 Docker 即可;不必安装 Node/npm(无 npm 时脚本用 node:24-alpine 容器构建选号网)。
  3. 选号网域名 DNS 已指向本机。

一键脚本会自动:

  • npm ci && npm run build 选号网;
  • dist 同步到 deploy/caddy/show-dist
  • 生成 Caddy 站点配置 deploy/caddy/conf.d/show.caddy
  • 构建 Caddy 镜像时打入主站 + 选号网静态资源;
  • 为选号网域名申请 HTTPS,并把 /api/* 反代到 backend:8080

不配置 CADDY_SHOW_DOMAIN 则行为与原来一致,仅部署主站。

如果正式对外运营,还需要配置真实短信和实名服务,避免继续使用测试配置。

2. 一键部署

./scripts/deploy-prod.sh

脚本会自动完成:

  • 检查 backend/.env 是否仍指向 127.0.0.1localhost 或占位值。
  • 使用内置 MinIO 时,检查 STORAGE_ACCESS_KEY_ID / STORAGE_SECRET_ACCESS_KEY 是否和 MINIO_ROOT_USER / MINIO_ROOT_PASSWORD 一致。
  • 构建并启动生产容器。
  • 使用配置的非 root UID/GID 运行后端,并检查日志目录属主。
  • 通过 Caddy 自动申请或续签 HTTPS 证书。
  • 等待 MySQL、Redis、MinIO 就绪。
  • 按顺序执行尚未应用的数据库迁移。
  • 重启后端并检查 https://你的域名/api/health

如需部署完成后直接跟随查看后端日志:

./scripts/deploy-prod.sh --logs

后端运行日志会写入宿主机:

backend/logs/app-YYYY-MM-DD.log

测试阶段需要清空并重建数据库时:

./scripts/deploy-prod.sh --reset-db

3. 手动启动服务

set -a
source backend/.env
set +a
docker compose -f deploy/docker-compose.prod.yml up -d --build

手动执行 docker compose 时需要先导出 CADDY_DOMAINCADDY_EMAIL,否则 Caddy 无法读取证书域名配置。优先推荐使用一键部署脚本,它会自动从 backend/.env 导出这两个变量。

4. 手动执行数据库迁移

通常直接使用一键部署脚本即可。确实需要手动迁移时,使用后端镜像内置的 goose:

MYSQL_DSN="$(awk -F= '$1=="MYSQL_DSN"{sub(/^[^=]*=/,""); print; exit}' backend/.env)"
case "$MYSQL_DSN" in
  *multiStatements=*) GOOSE_DSN="$MYSQL_DSN" ;;
  *\?*) GOOSE_DSN="${MYSQL_DSN}&multiStatements=true" ;;
  *) GOOSE_DSN="${MYSQL_DSN}?multiStatements=true" ;;
esac

docker compose -f deploy/docker-compose.prod.yml run --rm --no-deps backend \
  /app/goose -dir /app/migrations mysql "$GOOSE_DSN" up

5. 验证

curl https://主站域名/health
curl https://主站域名/api/health
# 若启用了选号网:
curl -I https://选号网域名/
curl https://选号网域名/api/health
curl "https://选号网域名/api/listings?page=1&page_size=1"

浏览器访问:

https://主站域名
https://主站域名/你配置的后台入口/login
https://选号网域名          # 选号网首页

Caddy 证书和 ACME 账号数据保存在 Docker 卷 caddy_datacaddy_config 中。不要随意删除这两个卷,否则 Caddy 会重新申请证书,频繁重建可能触发证书签发频率限制。