From b358dbdab158753a57c1f4082fae7f811a31956e Mon Sep 17 00:00:00 2001 From: xiaoquan <838115837@qq.com> Date: Mon, 1 Jun 2026 21:01:22 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E4=BD=BF=E7=94=A8=20Gitea=20Secrets=20?= =?UTF-8?q?=E7=AE=A1=E7=90=86=E5=85=A8=E9=83=A8=E5=AF=86=E9=92=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - deploy.yml 从 secrets 动态生成 .env,部署后自动删除 - docker-compose.prod.yml 支持全部业务配置注入(短信/微信/支付宝等) - .env.example 只保留 GITEA_RUNNER_TOKEN,其他密钥全部迁移到 Secrets - 更新 deploy/README.md 文档,完整列出 Secrets 配置清单 服务器上不再存储任何密码文件,安全性大幅提升 Co-Authored-By: Claude Opus 4.8 --- .gitea/workflows/deploy.yml | 52 ++++++++++++++++++++++----- apps/server/.env.example | 2 +- deploy/README.md | 52 +++++++++++++++++++++++---- deploy/docker/.env.example | 10 ++---- deploy/docker/docker-compose.prod.yml | 23 ++++++++++-- deploy/docker/docker-compose.test.yml | 5 +-- 6 files changed, 117 insertions(+), 27 deletions(-) diff --git a/.gitea/workflows/deploy.yml b/.gitea/workflows/deploy.yml index b3958fa..67de75e 100644 --- a/.gitea/workflows/deploy.yml +++ b/.gitea/workflows/deploy.yml @@ -66,17 +66,43 @@ jobs: steps: - uses: actions/checkout@v4 + - name: Generate .env from secrets + run: | + cat > deploy/docker/.env.prod << 'EOF' + PROD_DB_PASSWORD=${{ secrets.PROD_DB_PASSWORD }} + PROD_JWT_SECRET=${{ secrets.PROD_JWT_SECRET }} + PROD_JWT_EXPIRES_IN=${{ secrets.PROD_JWT_EXPIRES_IN }} + PROD_JWT_REFRESH_EXPIRES_IN=${{ secrets.PROD_JWT_REFRESH_EXPIRES_IN }} + PROD_SMS_ACCESS_KEY_ID=${{ secrets.PROD_SMS_ACCESS_KEY_ID }} + PROD_SMS_ACCESS_KEY_SECRET=${{ secrets.PROD_SMS_ACCESS_KEY_SECRET }} + PROD_SMS_SIGN_NAME=${{ secrets.PROD_SMS_SIGN_NAME }} + PROD_SMS_TEMPLATE_CODE=${{ secrets.PROD_SMS_TEMPLATE_CODE }} + PROD_WECHAT_APPID=${{ secrets.PROD_WECHAT_APPID }} + PROD_WECHAT_SECRET=${{ secrets.PROD_WECHAT_SECRET }} + PROD_WECHAT_MCHID=${{ secrets.PROD_WECHAT_MCHID }} + PROD_WECHAT_SERIAL_NO=${{ secrets.PROD_WECHAT_SERIAL_NO }} + PROD_WECHAT_APIV3_KEY=${{ secrets.PROD_WECHAT_APIV3_KEY }} + PROD_WECHAT_PRIVATE_KEY=${{ secrets.PROD_WECHAT_PRIVATE_KEY }} + PROD_WECHAT_PAY_NOTIFY_URL=${{ secrets.PROD_WECHAT_PAY_NOTIFY_URL }} + PROD_WECHAT_REFUND_NOTIFY_URL=${{ secrets.PROD_WECHAT_REFUND_NOTIFY_URL }} + PROD_ALIPAY_APPID=${{ secrets.PROD_ALIPAY_APPID }} + PROD_ALIPAY_PRIVATE_KEY=${{ secrets.PROD_ALIPAY_PRIVATE_KEY }} + PROD_API_BASE_URL=${{ secrets.PROD_API_BASE_URL }} + EOF + chmod 600 deploy/docker/.env.prod + - name: Deploy to production run: | echo "部署到生产环境..." cd deploy/docker - docker-compose -f docker-compose.prod.yml down --remove-orphans - docker-compose -f docker-compose.prod.yml build --parallel - docker-compose -f docker-compose.prod.yml up -d + docker-compose -f docker-compose.prod.yml --env-file .env.prod down --remove-orphans + docker-compose -f docker-compose.prod.yml --env-file .env.prod build --parallel + docker-compose -f docker-compose.prod.yml --env-file .env.prod up -d docker image prune -f echo "等待服务启动..." sleep 10 - docker-compose -f docker-compose.prod.yml ps + docker-compose -f docker-compose.prod.yml --env-file .env.prod ps + rm -f .env.prod deploy-test: runs-on: [self-hosted, rent-deploy] @@ -85,14 +111,24 @@ jobs: steps: - uses: actions/checkout@v4 + - name: Generate .env from secrets + run: | + cat > deploy/docker/.env.test << 'EOF' + TEST_DB_PASSWORD=${{ secrets.TEST_DB_PASSWORD }} + TEST_JWT_SECRET=${{ secrets.TEST_JWT_SECRET }} + TEST_API_BASE_URL=${{ secrets.TEST_API_BASE_URL }} + EOF + chmod 600 deploy/docker/.env.test + - name: Deploy to test run: | echo "部署到测试环境..." cd deploy/docker - docker-compose -f docker-compose.test.yml down --remove-orphans - docker-compose -f docker-compose.test.yml build --parallel - docker-compose -f docker-compose.test.yml up -d + docker-compose -f docker-compose.test.yml --env-file .env.test down --remove-orphans + docker-compose -f docker-compose.test.yml --env-file .env.test build --parallel + docker-compose -f docker-compose.test.yml --env-file .env.test up -d docker image prune -f echo "等待服务启动..." sleep 10 - docker-compose -f docker-compose.test.yml ps + docker-compose -f docker-compose.test.yml --env-file .env.test ps + rm -f .env.test diff --git a/apps/server/.env.example b/apps/server/.env.example index 202659e..28ec26c 100644 --- a/apps/server/.env.example +++ b/apps/server/.env.example @@ -2,7 +2,7 @@ DB_HOST=localhost DB_PORT=3306 DB_USERNAME=root -DB_PASSWORD=quan131735 +DB_PASSWORD=xxx DB_DATABASE=rent_platform # Redis配置 diff --git a/deploy/README.md b/deploy/README.md index c0a4b77..242d935 100644 --- a/deploy/README.md +++ b/deploy/README.md @@ -64,16 +64,16 @@ scripts/ ```bash # 将代码克隆到服务器 -git clone <你的GitLab仓库地址> ~/rent-platform +git clone <你的Gitea仓库地址> ~/rent-platform cd ~/rent-platform -# 运行初始化(安装 Docker、创建网络、启动网关) +# 运行初始化(安装 Docker、创建网络、启动 Gitea + 网关) bash scripts/setup-server.sh ``` 脚本会自动完成: - 安装 Docker、Docker Compose、Git、pnpm -- 创建 `.env` 文件并提示你填写密码 +- 启动 Gitea + Act Runner - 创建 Docker 网络(rent-prod、rent-test) - 启动 Gateway Nginx @@ -148,7 +148,47 @@ docker logs rent-act-runner 在 Gitea → **Settings → Actions → Runners** 页面应能看到 `rent-deploy-runner` 已注册并在线。 -### 第 3 步:推送代码到 Gitea +### 第 3 步:配置 Secrets(密钥安全) + +> 所有密钥通过 Gitea Secrets 管理,服务器上不存储任何密码文件。 + +Gitea → **仓库 → Settings → Actions → Secrets**,添加以下密钥: + +**生产环境:** + +| Secret 名 | 说明 | 示例 | +|-----------|------|------| +| `PROD_DB_PASSWORD` | 数据库密码 | 强密码 | +| `PROD_JWT_SECRET` | JWT 密钥 | 随机字符串 | +| `PROD_JWT_EXPIRES_IN` | Token 过期时间 | `2h` | +| `PROD_JWT_REFRESH_EXPIRES_IN` | 刷新 Token 过期 | `7d` | +| `PROD_SMS_ACCESS_KEY_ID` | 阿里云 AK | 短信服务 | +| `PROD_SMS_ACCESS_KEY_SECRET` | 阿里云 SK | 短信服务 | +| `PROD_SMS_SIGN_NAME` | 短信签名 | 品居会 | +| `PROD_SMS_TEMPLATE_CODE` | 短信模板编码 | SMS_xxx | +| `PROD_WECHAT_APPID` | 微信 AppID | wx1234... | +| `PROD_WECHAT_SECRET` | 微信 Secret | 微信密钥 | +| `PROD_WECHAT_MCHID` | 微信商户号 | 1234567890 | +| `PROD_WECHAT_SERIAL_NO` | 证书序列号 | 微信支付 | +| `PROD_WECHAT_APIV3_KEY` | APIv3 密钥 | 32 位字符串 | +| `PROD_WECHAT_PRIVATE_KEY` | 商户私钥 | PEM 内容 | +| `PROD_WECHAT_PAY_NOTIFY_URL` | 支付回调 | `https://api.pinzhuhui.com/...` | +| `PROD_WECHAT_REFUND_NOTIFY_URL` | 退款回调 | `https://api.pinzhuhui.com/...` | +| `PROD_ALIPAY_APPID` | 支付宝 AppID | 2021xxx | +| `PROD_ALIPAY_PRIVATE_KEY` | 支付宝私钥 | 密钥内容 | +| `PROD_API_BASE_URL` | API 地址 | `https://api.pinzhuhui.com` | + +**测试环境:** + +| Secret 名 | 说明 | +|-----------|------| +| `TEST_DB_PASSWORD` | 测试数据库密码 | +| `TEST_JWT_SECRET` | 测试 JWT 密钥 | +| `TEST_API_BASE_URL` | `https://api-test.pinzhuhui.com` | + +> 暂时没有的配置(如微信支付、支付宝)可以先不填,流水线会使用空值默认。 + +### 第 4 步:推送代码到 Gitea ```bash # 添加 Gitea 远程仓库 @@ -160,7 +200,7 @@ git push gitea test git push gitea prod ``` -### 第 4 步:自动部署触发 +### 第 5 步:自动部署触发 ```bash # 推送 test 分支 → 自动部署测试环境 @@ -170,7 +210,7 @@ git push gitea test git push gitea prod ``` -流水线:install → build → deploy +流水线:install → build → generate .env from secrets → deploy 在 Gitea → **仓库 → Actions** 页面查看实时日志。 diff --git a/deploy/docker/.env.example b/deploy/docker/.env.example index 43736b0..d605774 100644 --- a/deploy/docker/.env.example +++ b/deploy/docker/.env.example @@ -1,10 +1,4 @@ -# ===== 生产环境 ===== -PROD_DB_PASSWORD=change_me_in_production -PROD_JWT_SECRET=change_me_in_production - -# ===== 测试环境 ===== -TEST_DB_PASSWORD=change_me_in_test -TEST_JWT_SECRET=change_me_in_test - # ===== Gitea Act Runner ===== +# 注册 Runner 时从 Gitea Web 界面获取 token 填入这里 +# 其他所有密钥通过 Gitea → Settings → Actions → Secrets 管理 GITEA_RUNNER_TOKEN=change_me diff --git a/deploy/docker/docker-compose.prod.yml b/deploy/docker/docker-compose.prod.yml index 8ff04d5..d77bf34 100644 --- a/deploy/docker/docker-compose.prod.yml +++ b/deploy/docker/docker-compose.prod.yml @@ -52,14 +52,33 @@ services: environment: NODE_ENV: production PORT: 3000 + # Docker 内部网络 DB_HOST: mysql DB_PORT: 3306 DB_USERNAME: root - DB_PASSWORD: ${PROD_DB_PASSWORD:-rent123456} DB_DATABASE: rent_platform REDIS_HOST: redis REDIS_PORT: 6379 - JWT_SECRET: ${PROD_JWT_SECRET:-change_this_in_production} + # 从 .env.prod 注入的密钥 + DB_PASSWORD: ${PROD_DB_PASSWORD} + JWT_SECRET: ${PROD_JWT_SECRET} + JWT_EXPIRES_IN: ${PROD_JWT_EXPIRES_IN:-2h} + JWT_REFRESH_EXPIRES_IN: ${PROD_JWT_REFRESH_EXPIRES_IN:-7d} + SMS_ACCESS_KEY_ID: ${PROD_SMS_ACCESS_KEY_ID:-} + SMS_ACCESS_KEY_SECRET: ${PROD_SMS_ACCESS_KEY_SECRET:-} + SMS_SIGN_NAME: ${PROD_SMS_SIGN_NAME:-} + SMS_TEMPLATE_CODE: ${PROD_SMS_TEMPLATE_CODE:-} + WECHAT_APPID: ${PROD_WECHAT_APPID:-} + WECHAT_SECRET: ${PROD_WECHAT_SECRET:-} + WECHAT_MCHID: ${PROD_WECHAT_MCHID:-} + WECHAT_SERIAL_NO: ${PROD_WECHAT_SERIAL_NO:-} + WECHAT_APIV3_KEY: ${PROD_WECHAT_APIV3_KEY:-} + WECHAT_PRIVATE_KEY: ${PROD_WECHAT_PRIVATE_KEY:-} + WECHAT_PAY_NOTIFY_URL: ${PROD_WECHAT_PAY_NOTIFY_URL:-} + WECHAT_REFUND_NOTIFY_URL: ${PROD_WECHAT_REFUND_NOTIFY_URL:-} + ALIPAY_APPID: ${PROD_ALIPAY_APPID:-} + ALIPAY_PRIVATE_KEY: ${PROD_ALIPAY_PRIVATE_KEY:-} + API_BASE_URL: ${PROD_API_BASE_URL:-http://localhost:3000} depends_on: mysql: condition: service_healthy diff --git a/deploy/docker/docker-compose.test.yml b/deploy/docker/docker-compose.test.yml index 70e50dc..e7a58fe 100644 --- a/deploy/docker/docker-compose.test.yml +++ b/deploy/docker/docker-compose.test.yml @@ -55,11 +55,12 @@ services: DB_HOST: mysql DB_PORT: 3306 DB_USERNAME: root - DB_PASSWORD: ${TEST_DB_PASSWORD:-rent123456} DB_DATABASE: rent_platform REDIS_HOST: redis REDIS_PORT: 6379 - JWT_SECRET: ${TEST_JWT_SECRET:-change_this_in_test} + DB_PASSWORD: ${TEST_DB_PASSWORD} + JWT_SECRET: ${TEST_JWT_SECRET} + API_BASE_URL: ${TEST_API_BASE_URL:-http://localhost:3001} depends_on: mysql: condition: service_healthy