diff --git a/apps/mini-user/README.md b/apps/mini-user/README.md index aeb33c7..0b050ad 100644 --- a/apps/mini-user/README.md +++ b/apps/mini-user/README.md @@ -18,7 +18,7 @@ pnpm --filter @dukang/mini-user dev:weapp | 环节 | 文件 | 说明 | |------|------|------| -| **编译注入** | `config/index.ts` → `defineConstants.TARO_APP_API_ORIGIN` | 本地默认 `http://localhost:3000`;`NODE_ENV=production` 默认 `https://dkapi.runxian.top`;可用 `VITE_API_TARGET` 覆盖 | +| **编译注入** | `config/index.ts` → `defineConstants.TARO_APP_API_ORIGIN` | 本地默认 `http://localhost:3000`;`NODE_ENV=production` 默认 `https://api.dukanghaoke.com`;可用 `VITE_API_TARGET` 覆盖 | | **运行时拼装** | `src/lib/api.ts` → `resolveApiBase()` | `{origin}/api/v1` | ### 微信登录 `invalid code` @@ -45,10 +45,10 @@ pnpm --filter @dukang/mini-user dev:weapp **连远程 API**: ```bash -$env:VITE_API_TARGET="https://dkapi.runxian.top"; pnpm --filter @dukang/mini-user dev +$env:VITE_API_TARGET="https://api.dukanghaoke.com"; pnpm --filter @dukang/mini-user dev ``` -并在 `dkapi.runxian.top` 所在服务器配置 `WX_MINI_APP_ID=wxda31c8e8e85051e7` 及对应 AppSecret。 +并在 `api.dukanghaoke.com` 所在服务器配置 `WX_MINI_APP_ID=wxda31c8e8e85051e7` 及对应 AppSecret。 ## 页面结构(18 页) diff --git a/apps/mini-user/config/index.ts b/apps/mini-user/config/index.ts index f7a0f1e..cda66a7 100644 --- a/apps/mini-user/config/index.ts +++ b/apps/mini-user/config/index.ts @@ -5,7 +5,7 @@ import { defineConfig } from '@tarojs/cli'; /** 小程序/H5 请求的后端 origin(不含 /api);本地默认本机,生产构建默认远程 */ const API_ORIGIN = process.env.VITE_API_TARGET ?? - (process.env.NODE_ENV === 'production' ? 'https://dkapi.runxian.top' : 'http://localhost:3000'); + (process.env.NODE_ENV === 'production' ? 'https://api.dukanghaoke.com' : 'http://localhost:3000'); const requireFromApp = createRequire(path.resolve(__dirname, '../package.json')); diff --git a/deploy/enable-dukanghaoke-api-ssl.sh b/deploy/enable-dukanghaoke-api-ssl.sh new file mode 100644 index 0000000..81af7b8 --- /dev/null +++ b/deploy/enable-dukanghaoke-api-ssl.sh @@ -0,0 +1,47 @@ +#!/usr/bin/env bash +# 启用 api.dukanghaoke.com:扩证书 + 装 nginx 配置 +set -euo pipefail + +DOMAIN_API=api.dukanghaoke.com +CERT_NAME=user.dukanghaoke.com +EMAIL="${CERTBOT_EMAIL:-admin@dukanghaoke.com}" +APP_ROOT="${APP_ROOT:-/opt/dukang}" +NGINX_SRC="$APP_ROOT/deploy/nginx-dukanghaoke.conf" +NGINX_DST="/etc/nginx/sites-available/dukang" + +mkdir -p /var/www/certbot/.well-known/acme-challenge +mkdir -p /var/log/nginx/dukang + +echo "==> 1. 临时 HTTP 放行 api 域名(便于 http-01)" +# 先写入含 api 的 80 server,若证书尚未含 api,443 块可暂用现有证书 +if [[ -f "$NGINX_SRC" ]]; then + install -m 644 "$NGINX_SRC" "$NGINX_DST" + ln -sfn "$NGINX_DST" /etc/nginx/sites-enabled/dukang +fi +nginx -t +systemctl reload nginx + +echo "==> 2. 扩展证书加入 $DOMAIN_API" +certbot certonly --nginx \ + --cert-name "$CERT_NAME" \ + --expand \ + -d user.dukanghaoke.com \ + -d shop.dukanghaoke.com \ + -d partner.dukanghaoke.com \ + -d admin.dukanghaoke.com \ + -d api.dukanghaoke.com \ + --email "$EMAIL" \ + --agree-tos \ + --non-interactive \ + --keep-until-expiring + +echo "==> 3. 重载 nginx" +nginx -t +systemctl reload nginx + +echo "==> 4. 健康检查" +sleep 1 +curl -sf -o /dev/null -w "api-https:%{http_code} content-type:%{content_type}\n" \ + "https://${DOMAIN_API}/api/v1/health" +curl -sf "https://${DOMAIN_API}/api/v1/health"; echo +echo "==> 完成" diff --git a/deploy/nginx-deploy-webhook.conf b/deploy/nginx-deploy-webhook.conf index 82b8454..9c775e9 100644 --- a/deploy/nginx-deploy-webhook.conf +++ b/deploy/nginx-deploy-webhook.conf @@ -1,4 +1,4 @@ -# 杜康好客 — CodeUp Webhook 反代(挂到 dkapi.runxian.top 443/80 server 块内) +# 杜康好客 — CodeUp Webhook 反代(挂到 api.dukanghaoke.com 443/80 server 块内) # setup-webhook.sh 会自动 include 此文件 location = /hooks/deploy { diff --git a/deploy/nginx-dukanghaoke.conf b/deploy/nginx-dukanghaoke.conf new file mode 100644 index 0000000..65497c9 --- /dev/null +++ b/deploy/nginx-dukanghaoke.conf @@ -0,0 +1,185 @@ +# 杜康好客 — dukanghaoke.com +# HTTP → HTTPS +server { + listen 80; + server_name user.dukanghaoke.com shop.dukanghaoke.com partner.dukanghaoke.com admin.dukanghaoke.com api.dukanghaoke.com; + + location ^~ /.well-known/acme-challenge/ { + root /var/www/certbot; + default_type "text/plain"; + } + + location / { + return 301 https://$host$request_uri; + } +} + +# api.dukanghaoke.com → 8090 +server { + listen 443 ssl; + http2 on; + server_name api.dukanghaoke.com; + + ssl_certificate /etc/letsencrypt/live/user.dukanghaoke.com/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/user.dukanghaoke.com/privkey.pem; + ssl_protocols TLSv1.2 TLSv1.3; + ssl_ciphers HIGH:!aNULL:!MD5; + + client_max_body_size 50m; + + include /opt/dukang/deploy/nginx-deploy-webhook.conf; + + location / { + proxy_pass http://127.0.0.1:8090; + proxy_http_version 1.1; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header Connection ""; + } +} + +# user.dukanghaoke.com → 8091 +server { + listen 443 ssl; + http2 on; + server_name user.dukanghaoke.com; + + ssl_certificate /etc/letsencrypt/live/user.dukanghaoke.com/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/user.dukanghaoke.com/privkey.pem; + ssl_protocols TLSv1.2 TLSv1.3; + ssl_ciphers HIGH:!aNULL:!MD5; + + client_max_body_size 50m; + + location /api/ { + proxy_pass http://127.0.0.1:8090; + proxy_http_version 1.1; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header Connection ""; + } + + location / { + proxy_pass http://127.0.0.1:8091; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection 'upgrade'; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_cache_bypass $http_upgrade; + } +} + +# shop.dukanghaoke.com → 8092 +server { + listen 443 ssl; + http2 on; + server_name shop.dukanghaoke.com; + + ssl_certificate /etc/letsencrypt/live/user.dukanghaoke.com/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/user.dukanghaoke.com/privkey.pem; + ssl_protocols TLSv1.2 TLSv1.3; + ssl_ciphers HIGH:!aNULL:!MD5; + + client_max_body_size 50m; + + location /api/ { + proxy_pass http://127.0.0.1:8090; + proxy_http_version 1.1; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header Connection ""; + } + + location / { + proxy_pass http://127.0.0.1:8092; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection 'upgrade'; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_cache_bypass $http_upgrade; + } +} + +# partner.dukanghaoke.com → 8093 +server { + listen 443 ssl; + http2 on; + server_name partner.dukanghaoke.com; + + ssl_certificate /etc/letsencrypt/live/user.dukanghaoke.com/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/user.dukanghaoke.com/privkey.pem; + ssl_protocols TLSv1.2 TLSv1.3; + ssl_ciphers HIGH:!aNULL:!MD5; + + client_max_body_size 50m; + + location /api/ { + proxy_pass http://127.0.0.1:8090; + proxy_http_version 1.1; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header Connection ""; + } + + location / { + proxy_pass http://127.0.0.1:8093; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection 'upgrade'; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_cache_bypass $http_upgrade; + } +} + +# admin.dukanghaoke.com → 8094 +server { + listen 443 ssl; + http2 on; + server_name admin.dukanghaoke.com; + + ssl_certificate /etc/letsencrypt/live/user.dukanghaoke.com/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/user.dukanghaoke.com/privkey.pem; + ssl_protocols TLSv1.2 TLSv1.3; + ssl_ciphers HIGH:!aNULL:!MD5; + + client_max_body_size 50m; + + location /api/ { + proxy_pass http://127.0.0.1:8090; + proxy_http_version 1.1; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header Connection ""; + } + + location / { + proxy_pass http://127.0.0.1:8094; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection 'upgrade'; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_cache_bypass $http_upgrade; + } +} diff --git a/deploy/remote-release.sh b/deploy/remote-release.sh index cde0476..8bbb5c2 100644 --- a/deploy/remote-release.sh +++ b/deploy/remote-release.sh @@ -47,7 +47,7 @@ export NODE_OPTIONS="${NODE_OPTIONS:---max-old-space-size=8192}" export TARO_H5_PUBLIC_PATH="${TARO_H5_PUBLIC_PATH:-/user/}" export TARO_H5_ROUTER_BASENAME="${TARO_H5_ROUTER_BASENAME:-/user}" # C 端 H5 编译期注入的 API origin(勿落到 localhost) -export VITE_API_TARGET="${VITE_API_TARGET:-https://dkapi.runxian.top}" +export VITE_API_TARGET="${VITE_API_TARGET:-https://api.dukanghaoke.com}" pnpm approve-builds --all 2>/dev/null || true pnpm install --frozen-lockfile 2>/dev/null || pnpm install diff --git a/deploy/setup-webhook.sh b/deploy/setup-webhook.sh index 16d2ad9..efdf9a1 100644 --- a/deploy/setup-webhook.sh +++ b/deploy/setup-webhook.sh @@ -30,13 +30,25 @@ HOOK_CONF="$DEPLOY_DIR/nginx-deploy-webhook.conf" rm -f /etc/nginx/conf.d/dukang-deploy-webhook.conf MARKER="include $HOOK_CONF;" -for conf in /etc/nginx/conf.d/dukang-runxian.conf /etc/nginx/conf.d/dukang-runxian-ssl.conf; do - if [[ -f "$conf" ]] && grep -q 'server_name dkapi.runxian.top' "$conf"; then - # 清理旧错误 include - sed -i '\|include /etc/nginx/conf.d/dukang-deploy-webhook.conf;|d' "$conf" +for conf in \ + /etc/nginx/sites-available/dukang \ + /etc/nginx/conf.d/dukang-runxian.conf \ + /etc/nginx/conf.d/dukang-runxian-ssl.conf +do + if [[ ! -f "$conf" ]]; then + continue + fi + # 清理旧错误 include + sed -i '\|include /etc/nginx/conf.d/dukang-deploy-webhook.conf;|d' "$conf" + if grep -q 'server_name api.dukanghaoke.com' "$conf"; then + if ! grep -qF "$MARKER" "$conf"; then + sed -i "/server_name api.dukanghaoke.com;/a\\ $MARKER" "$conf" + echo " 已 patch $conf (api.dukanghaoke.com)" + fi + elif grep -q 'server_name dkapi.runxian.top' "$conf"; then if ! grep -qF "$MARKER" "$conf"; then sed -i "/server_name dkapi.runxian.top;/a\\ $MARKER" "$conf" - echo " 已 patch $conf" + echo " 已 patch $conf (dkapi.runxian.top)" fi fi done @@ -62,14 +74,14 @@ SECRET="$(grep DEPLOY_WEBHOOK_SECRET "$ENV_FILE" | cut -d= -f2- | tr -d '\"')" echo "" echo "==========================================" echo " Webhook 已就绪" -echo " URL: https://dkapi.runxian.top/hooks/deploy" +echo " URL: https://api.dukanghaoke.com/hooks/deploy" echo " Secret: $SECRET" echo " Branch: dev (refs/heads/dev)" echo " Log: $LOG_DIR/deploy.log" echo "==========================================" echo "" echo "CodeUp 配置:仓库 → 设置 → Webhooks → 添加" -echo " URL: https://dkapi.runxian.top/hooks/deploy" +echo " URL: https://api.dukanghaoke.com/hooks/deploy" echo " Secret Token: (与上方 Secret 相同)" echo " 触发事件: Push events" echo " 分支过滤: dev" diff --git a/server/dukang-api/.env.example b/server/dukang-api/.env.example index e5edb11..1a166ff 100644 --- a/server/dukang-api/.env.example +++ b/server/dukang-api/.env.example @@ -50,7 +50,7 @@ WX_MCH_PRIVATE_KEY= WX_API_V3_KEY= # 微信平台公钥证书 PEM(生产环境必填,用于回调验签;开发可暂留空) WX_PLATFORM_CERT= -WX_PAY_NOTIFY_URL=https://dkapi.runxian.top/api/v1/callbacks/wechat/pay +WX_PAY_NOTIFY_URL=https://api.dukanghaoke.com/api/v1/callbacks/wechat/pay # 腾讯位置服务(逆地理编码,微信定位展示城市) TENCENT_LBS_KEY= diff --git a/server/dukang-api/.env.production.example b/server/dukang-api/.env.production.example index ee56f8a..ddc926e 100644 --- a/server/dukang-api/.env.production.example +++ b/server/dukang-api/.env.production.example @@ -37,7 +37,7 @@ WX_MCH_SERIAL_NO= WX_MCH_PRIVATE_KEY= WX_API_V3_KEY= WX_PLATFORM_CERT= -WX_PAY_NOTIFY_URL=https://dkapi.runxian.top/api/v1/callbacks/wechat/pay +WX_PAY_NOTIFY_URL=https://api.dukanghaoke.com/api/v1/callbacks/wechat/pay OSS_ACCESS_KEY_ID= OSS_ACCESS_KEY_SECRET=