diff --git a/deploy/_diag_wx_key.mjs b/deploy/_diag_wx_key.mjs deleted file mode 100644 index 9bccaa3..0000000 --- a/deploy/_diag_wx_key.mjs +++ /dev/null @@ -1,77 +0,0 @@ -#!/usr/bin/env node -const fs = require('fs'); -const crypto = require('crypto'); -const path = process.argv[2] || '/opt/dukang/server/dukang-api/.env.production'; - -function stripQuotes(s) { - const t = s.trim(); - if ((t.startsWith('"') && t.endsWith('"')) || (t.startsWith("'") && t.endsWith("'"))) { - return t.slice(1, -1); - } - return t; -} - -function parseEnvValue(text, key) { - const re = new RegExp(`^${key}=(.*)$`, 'm'); - const m = text.match(re); - if (!m) return null; - return stripQuotes(m[1]); -} - -function tryKey(name, key) { - const literalN = (key.match(/\\n/g) || []).length; - const realN = (key.match(/\n/g) || []).length; - const hasBegin = /BEGIN (RSA )?PRIVATE KEY/.test(key); - try { - crypto.createPrivateKey(key); - console.log(`${name}: OK begin=${hasBegin} literalN=${literalN} realN=${realN} len=${key.length}`); - return true; - } catch (e) { - console.log( - `${name}: FAIL ${e.message} begin=${hasBegin} literalN=${literalN} realN=${realN} len=${key.length} head=${JSON.stringify(key.slice(0, 48))}`, - ); - return false; - } -} - -const text = fs.readFileSync(path, 'utf8'); -const raw = parseEnvValue(text, 'WX_MCH_PRIVATE_KEY'); -if (!raw) { - console.log('MISSING WX_MCH_PRIVATE_KEY in', path); - process.exit(1); -} - -console.log('file=', path); -console.log('MOCK_PAY=', parseEnvValue(text, 'MOCK_PAY')); -console.log('WX_MINI_APP_ID=', parseEnvValue(text, 'WX_MINI_APP_ID')); -console.log('WX_APP_ID=', parseEnvValue(text, 'WX_APP_ID')); -console.log('WX_MCH_ID=', parseEnvValue(text, 'WX_MCH_ID')); -console.log('WX_PAY_NOTIFY_URL=', parseEnvValue(text, 'WX_PAY_NOTIFY_URL')); - -const variants = { - as_is: raw, - unescape_n: raw.replace(/\\n/g, '\n'), - unescape_twice: raw.replace(/\\\\n/g, '\\n').replace(/\\n/g, '\n'), - strip_cr_unesc: raw.replace(/\\n/g, '\n').replace(/\r/g, ''), - // dotenv style sometimes leaves surrounding quotes in process.env - quoted_unesc: stripQuotes(raw).replace(/\\n/g, '\n'), -}; - -let ok = false; -for (const [name, key] of Object.entries(variants)) { - if (tryKey(name, key)) ok = true; -} - -// also simulate dotenv load -try { - const dotenv = require('dotenv'); - const parsed = dotenv.parse(text); - const fromDotenv = parsed.WX_MCH_PRIVATE_KEY || ''; - console.log('dotenv_raw_literalN=', (fromDotenv.match(/\\n/g) || []).length, 'realN=', (fromDotenv.match(/\n/g) || []).length); - tryKey('dotenv_as_is', fromDotenv); - tryKey('dotenv_unescape', fromDotenv.replace(/\\n/g, '\n')); -} catch (e) { - console.log('dotenv skip', e.message); -} - -process.exit(ok ? 0 : 2); diff --git a/deploy/enable-api-lingshi-ssl.sh b/deploy/enable-api-lingshi-ssl.sh deleted file mode 100644 index e028a91..0000000 --- a/deploy/enable-api-lingshi-ssl.sh +++ /dev/null @@ -1,65 +0,0 @@ -#!/usr/bin/env bash -# 为 api.lingshivip.cn 申请 DNS 证书并启用 HTTPS -set -euo pipefail -SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" -SSL_DIR="/etc/nginx/ssl/api.lingshivip.cn" -NGINX_CONF="/etc/nginx/conf.d/dukang-lingshivip.conf" - -mkdir -p "$SSL_DIR" /var/www/certbot/.well-known/acme-challenge - -echo "==> 1. 发起 DNS 验证(需先在 DNSPod 添加 TXT 记录)" -~/.acme.sh/acme.sh --issue -d api.lingshivip.cn --dns \ - --yes-I-know-dns-manual-mode-enough-go-ahead-please \ - --server letsencrypt || true - -echo "" -echo "请在 DNSPod 添加上述 TXT 记录后,执行:" -echo " $0 --renew" -echo "" - -if [[ "${1:-}" != "--renew" ]]; then - exit 0 -fi - -echo "==> 2. 继续 DNS 验证并签发证书" -~/.acme.sh/acme.sh --renew -d api.lingshivip.cn --yes-I-know-dns-manual-mode-enough-go-ahead-please - -echo "==> 3. 安装证书到 nginx 目录" -install -m 644 ~/.acme.sh/api.lingshivip.cn_ecc/fullchain.cer "$SSL_DIR/fullchain.cer" -install -m 600 ~/.acme.sh/api.lingshivip.cn_ecc/api.lingshivip.cn.key "$SSL_DIR/api.lingshivip.cn.key" - -echo "==> 4. 更新 nginx 并重载" -cp "$SCRIPT_DIR/nginx-lingshivip.conf" "$NGINX_CONF" -python3 - <<'PY' -from pathlib import Path -p = Path("/etc/nginx/conf.d/dukang-lingshivip.conf") -text = p.read_text() -old = """ 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 ""; - } -} - -# API 独立域名 HTTPS""" -new = """ location / { - return 301 https://$host$request_uri; - } -} - -# API 独立域名 HTTPS""" -if old not in text: - raise SystemExit("nginx api http redirect patch failed") -p.write_text(text.replace(old, new, 1)) -PY - -nginx -t -systemctl reload nginx - -echo "==> 5. 健康检查" -curl -sf -o /dev/null -w "api-https:%{http_code}\n" https://api.lingshivip.cn/api/v1/health -echo "==> api.lingshivip.cn HTTPS 已启用" diff --git a/deploy/enable-runxian-apex-ssl.sh b/deploy/enable-runxian-apex-ssl.sh deleted file mode 100644 index 5284292..0000000 --- a/deploy/enable-runxian-apex-ssl.sh +++ /dev/null @@ -1,59 +0,0 @@ -#!/usr/bin/env bash -# runxian.top 裸域名申请 Let's Encrypt 并启用 HTTPS -set -euo pipefail - -SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" -DOMAIN=runxian.top -EMAIL="${CERTBOT_EMAIL:-admin@runxian.top}" - -echo "==> 检查 DNS: $DOMAIN" -ip="$(dig +short "$DOMAIN" A @223.5.5.5 | tail -1)" -if [[ -z "$ip" ]]; then - echo "ERROR: $DOMAIN 无 A 记录,请先在 DNS 添加指向本机公网 IP(当前服务器: $(curl -sf ifconfig.me || echo unknown))" - exit 1 -fi -echo " $DOMAIN -> $ip" - -mkdir -p /var/www/certbot /var/log/nginx/dukang - -# 若尚未有证书,先部署仅 HTTP 的配置以便 ACME 校验 -if [[ ! -f /etc/letsencrypt/live/runxian.top/fullchain.pem ]]; then - echo "==> 临时 HTTP 配置(用于 ACME)..." - cat > /etc/nginx/conf.d/dukang-runxian-apex.conf <<'EOF' -server { - listen 80; - server_name runxian.top; - root /opt/dukang-haoke/public; - index index.html; - location ^~ /.well-known/acme-challenge/ { - root /var/www/certbot; - default_type "text/plain"; - } - location ~ ^/MP_verify_.*\.txt$ { - default_type text/plain; - access_log off; - } - location / { - try_files $uri $uri/ =404; - } -} -EOF - nginx -t - systemctl reload nginx -fi - -echo "==> 申请证书..." -certbot certonly --webroot -w /var/www/certbot \ - --cert-name runxian.top \ - -d runxian.top \ - --non-interactive --agree-tos -m "$EMAIL" - -echo "==> 切换 HTTPS 配置..." -install -m 644 "$SCRIPT_DIR/nginx-runxian-apex.conf" /etc/nginx/conf.d/dukang-runxian-apex.conf -nginx -t -systemctl reload nginx - -echo "==> 验证..." -code="$(curl -sf -o /dev/null -w '%{http_code}' "https://$DOMAIN/MP_verify_ayPJ4CQqbUcec3jX.txt" || echo fail)" -echo " https://$DOMAIN/MP_verify_ayPJ4CQqbUcec3jX.txt -> $code" -echo "==> runxian.top HTTPS 已启用" diff --git a/deploy/enable-runxian-dukang-ssl.sh b/deploy/enable-runxian-dukang-ssl.sh deleted file mode 100644 index 046495e..0000000 --- a/deploy/enable-runxian-dukang-ssl.sh +++ /dev/null @@ -1,57 +0,0 @@ -#!/usr/bin/env bash -# 为杜康 runxian.top 申请 Let's Encrypt 并切换 HTTPS 配置 -# 三端 H5 统一入口 user.runxian.top/{user,shop,partner}/ -set -euo pipefail - -SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" -DOMAINS=( - user.runxian.top - shop.runxian.top - partner.runxian.top - webadmin.runxian.top - dkapi.runxian.top -) - -echo "==> 检查 DNS 解析到本机..." -for d in "${DOMAINS[@]}"; do - ip="$(dig +short "$d" @223.5.5.5 | tail -1)" - if [[ -z "$ip" ]]; then - echo "ERROR: $d 无 A 记录,请先在 DNS 添加指向本机公网 IP" - exit 1 - fi - echo " $d -> $ip" -done - -mkdir -p /var/www/certbot /var/log/nginx/dukang - -echo "==> 申请证书..." -certbot certonly --webroot -w /var/www/certbot \ - --cert-name user.runxian.top \ - -d user.runxian.top \ - -d shop.runxian.top \ - -d partner.runxian.top \ - -d webadmin.runxian.top \ - -d dkapi.runxian.top \ - --non-interactive --agree-tos -m admin@runxian.top || { - echo "certbot 失败,请确认 DNS 已生效且 80 端口可从公网访问" - exit 1 -} - -echo "==> 切换 nginx HTTPS 配置..." -install -m 644 "$SCRIPT_DIR/nginx-runxian-dukang-ssl.conf" /etc/nginx/conf.d/dukang-runxian.conf -nginx -t -systemctl reload nginx - -echo "==> 验证..." -for url in \ - https://user.runxian.top/user/ \ - https://user.runxian.top/shop/ \ - https://user.runxian.top/partner/ \ - https://shop.runxian.top/ \ - https://webadmin.runxian.top/ \ - https://dkapi.runxian.top/api/v1/health; do - code="$(curl -sf -o /dev/null -w '%{http_code}' "$url" || echo fail)" - echo " $url -> $code" -done - -echo "==> runxian.top 杜康域名 HTTPS 已启用(H5 统一入口 user.runxian.top)" diff --git a/deploy/nginx-ai-mirror-http.conf b/deploy/nginx-ai-mirror-http.conf deleted file mode 100644 index 1a9b700..0000000 --- a/deploy/nginx-ai-mirror-http.conf +++ /dev/null @@ -1,33 +0,0 @@ -map $host $dukang_h5_port { - user.ai-mirror.xyz 8091; - shop.ai-mirror.xyz 8092; - partner.ai-mirror.xyz 8093; -} - -# HTTP — 证书申请期间先提供 HTTP 服务 -server { - listen 80; - server_name user.ai-mirror.xyz shop.ai-mirror.xyz partner.ai-mirror.xyz; - - location /.well-known/acme-challenge/ { - root /var/www/certbot; - } - - 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; - } - - location / { - proxy_pass http://127.0.0.1:$dukang_h5_port; - 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; - } -} diff --git a/deploy/nginx-ai-mirror.conf b/deploy/nginx-ai-mirror.conf deleted file mode 100644 index 7d39051..0000000 --- a/deploy/nginx-ai-mirror.conf +++ /dev/null @@ -1,54 +0,0 @@ -# 杜康好客 H5 三端 — ai-mirror.xyz -# API 内部端口 8090;H5 分别 8091/8092/8093 - -map $host $dukang_h5_port { - user.ai-mirror.xyz 8091; - shop.ai-mirror.xyz 8092; - partner.ai-mirror.xyz 8093; -} - -# HTTP → HTTPS -server { - listen 80; - server_name user.ai-mirror.xyz shop.ai-mirror.xyz partner.ai-mirror.xyz; - location /.well-known/acme-challenge/ { - root /var/www/certbot; - } - location / { - return 301 https://$host$request_uri; - } -} - -server { - listen 443 ssl; - server_name user.ai-mirror.xyz shop.ai-mirror.xyz partner.ai-mirror.xyz; - - access_log /var/log/nginx/dukang/access.log main; - error_log /var/log/nginx/dukang/error.log warn; - - ssl_certificate /etc/letsencrypt/live/user.ai-mirror.xyz/fullchain.pem; - ssl_certificate_key /etc/letsencrypt/live/user.ai-mirror.xyz/privkey.pem; - ssl_protocols TLSv1.2 TLSv1.3; - ssl_prefer_server_ciphers on; - - client_max_body_size 20m; - - 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:$dukang_h5_port; - 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; - } -} diff --git a/deploy/nginx-lingshivip-http.conf b/deploy/nginx-lingshivip-http.conf deleted file mode 100644 index 4da8d6a..0000000 --- a/deploy/nginx-lingshivip-http.conf +++ /dev/null @@ -1,105 +0,0 @@ -# 证书申请期间 — lingshivip.cn HTTP(api HTTPS 证书就绪后换 nginx-lingshivip.conf) - -map $host $dukang_lingshi_port { - user.lingshivip.cn 8091; - shop.lingshivip.cn 8092; - partner.lingshivip.cn 8093; - admin.lingshivip.cn 8094; -} - -server { - listen 80; - server_name user.lingshivip.cn shop.lingshivip.cn partner.lingshivip.cn; - - location ^~ /.well-known/acme-challenge/ { - root /var/www/certbot; - default_type "text/plain"; - } - - location / { - return 301 https://$host$request_uri; - } -} - -server { - listen 80; - server_name api.lingshivip.cn; - - location ^~ /.well-known/acme-challenge/ { - root /var/www/certbot; - default_type "text/plain"; - } - - 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 ""; - } -} - -server { - listen 80; - server_name admin.lingshivip.cn; - - location ^~ /.well-known/acme-challenge/ { - root /var/www/certbot; - default_type "text/plain"; - } - - 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 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; - } -} - -server { - listen 443 ssl; - server_name user.lingshivip.cn shop.lingshivip.cn partner.lingshivip.cn; - - access_log /var/log/nginx/dukang/lingshi.access.log main; - error_log /var/log/nginx/dukang/lingshi.error.log warn; - - ssl_certificate /etc/letsencrypt/live/user.lingshivip.cn/fullchain.pem; - ssl_certificate_key /etc/letsencrypt/live/user.lingshivip.cn/privkey.pem; - ssl_protocols TLSv1.2 TLSv1.3; - ssl_prefer_server_ciphers on; - - client_max_body_size 20m; - - 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:$dukang_lingshi_port; - 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; - } -} diff --git a/deploy/nginx-lingshivip.conf b/deploy/nginx-lingshivip.conf deleted file mode 100644 index 1efb64b..0000000 --- a/deploy/nginx-lingshivip.conf +++ /dev/null @@ -1,135 +0,0 @@ -# 杜康好客 — lingshivip.cn 五端 + API -# API 8090;H5 8091/8092/8093;admin-web 8094 - -map $host $dukang_lingshi_port { - user.lingshivip.cn 8091; - shop.lingshivip.cn 8092; - partner.lingshivip.cn 8093; - admin.lingshivip.cn 8094; -} - -# HTTP → HTTPS(H5 三端) -server { - listen 80; - server_name user.lingshivip.cn shop.lingshivip.cn partner.lingshivip.cn; - - location ^~ /.well-known/acme-challenge/ { - root /var/www/certbot; - default_type "text/plain"; - } - - location / { - return 301 https://$host$request_uri; - } -} - -# API:证书就绪前 HTTP 直连;就绪后改走 HTTPS server -server { - listen 80; - server_name api.lingshivip.cn; - - location ^~ /.well-known/acme-challenge/ { - root /var/www/certbot; - default_type "text/plain"; - } - - 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 ""; - } -} - -# admin 待 DNS + 证书就绪前先走 HTTP -server { - listen 80; - server_name admin.lingshivip.cn; - - location ^~ /.well-known/acme-challenge/ { - root /var/www/certbot; - default_type "text/plain"; - } - - 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 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; - } -} - -# API 独立域名 HTTPS(证书:/etc/nginx/ssl/api.lingshivip.cn/) -server { - listen 443 ssl; - server_name api.lingshivip.cn; - - access_log /var/log/nginx/dukang/lingshi-api.access.log main; - error_log /var/log/nginx/dukang/lingshi-api.error.log warn; - - ssl_certificate /etc/nginx/ssl/api.lingshivip.cn/fullchain.cer; - ssl_certificate_key /etc/nginx/ssl/api.lingshivip.cn/api.lingshivip.cn.key; - ssl_protocols TLSv1.2 TLSv1.3; - ssl_prefer_server_ciphers on; - - client_max_body_size 20m; - - 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 ""; - } -} - -server { - listen 443 ssl; - server_name user.lingshivip.cn shop.lingshivip.cn partner.lingshivip.cn; - - access_log /var/log/nginx/dukang/lingshi.access.log main; - error_log /var/log/nginx/dukang/lingshi.error.log warn; - - ssl_certificate /etc/letsencrypt/live/user.lingshivip.cn/fullchain.pem; - ssl_certificate_key /etc/letsencrypt/live/user.lingshivip.cn/privkey.pem; - ssl_protocols TLSv1.2 TLSv1.3; - ssl_prefer_server_ciphers on; - - client_max_body_size 20m; - - 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:$dukang_lingshi_port; - 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; - } -} diff --git a/deploy/nginx-runxian-apex.conf b/deploy/nginx-runxian-apex.conf deleted file mode 100644 index 74fdd4d..0000000 --- a/deploy/nginx-runxian-apex.conf +++ /dev/null @@ -1,53 +0,0 @@ -# runxian.top 裸域名 — 静态公共资源(微信域名校验等) -# HTTP: 保留 MP_verify + ACME;其余跳转 HTTPS -# HTTPS: deploy/enable-runxian-apex-ssl.sh 申请证书后启用 - -server { - listen 80; - server_name runxian.top; - - access_log /var/log/nginx/dukang/runxian-apex.access.log main; - error_log /var/log/nginx/dukang/runxian-apex.error.log warn; - - root /opt/dukang-haoke/public; - index index.html; - - location ^~ /.well-known/acme-challenge/ { - root /var/www/certbot; - default_type "text/plain"; - } - - location ~ ^/MP_verify_.*\.txt$ { - default_type text/plain; - access_log off; - } - - location / { - return 301 https://$host$request_uri; - } -} - -server { - listen 443 ssl; - server_name runxian.top; - - access_log /var/log/nginx/dukang/runxian-apex.access.log main; - error_log /var/log/nginx/dukang/runxian-apex.error.log warn; - - ssl_certificate /etc/letsencrypt/live/runxian.top/fullchain.pem; - ssl_certificate_key /etc/letsencrypt/live/runxian.top/privkey.pem; - ssl_protocols TLSv1.2 TLSv1.3; - ssl_prefer_server_ciphers on; - - root /opt/dukang-haoke/public; - index index.html; - - location ~ ^/MP_verify_.*\.txt$ { - default_type text/plain; - access_log off; - } - - location / { - try_files $uri $uri/ =404; - } -} diff --git a/deploy/nginx-runxian-dukang-ssl.conf b/deploy/nginx-runxian-dukang-ssl.conf deleted file mode 100644 index 85f6e78..0000000 --- a/deploy/nginx-runxian-dukang-ssl.conf +++ /dev/null @@ -1,218 +0,0 @@ -# 杜康好客 — runxian.top HTTPS -# 执行: deploy/enable-runxian-dukang-ssl.sh -# 三端 H5 统一入口 user.runxian.top/{user,shop,partner}/ - -server { - listen 80; - server_name user.runxian.top shop.runxian.top partner.runxian.top m.runxian.top; - - location ^~ /.well-known/acme-challenge/ { - root /var/www/certbot; - default_type "text/plain"; - } - - location / { - return 301 https://user.runxian.top$request_uri; - } -} - -server { - listen 443 ssl; - server_name m.runxian.top; - - ssl_certificate /etc/letsencrypt/live/user.runxian.top/fullchain.pem; - ssl_certificate_key /etc/letsencrypt/live/user.runxian.top/privkey.pem; - ssl_protocols TLSv1.2 TLSv1.3; - - return 301 https://user.runxian.top$request_uri; -} - -server { - listen 443 ssl; - server_name user.runxian.top; - - access_log /var/log/nginx/dukang/runxian-h5.access.log main; - error_log /var/log/nginx/dukang/runxian-h5.error.log warn; - - ssl_certificate /etc/letsencrypt/live/user.runxian.top/fullchain.pem; - ssl_certificate_key /etc/letsencrypt/live/user.runxian.top/privkey.pem; - ssl_protocols TLSv1.2 TLSv1.3; - ssl_prefer_server_ciphers on; - - client_max_body_size 20m; - - location ~ ^/MP_verify_.*\.txt$ { - root /opt/dukang-haoke/apps/mini-user/dist; - default_type text/plain; - access_log off; - } - - 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 = / { - return 302 /user/; - } - - # Taro 路由页是 /pages/xxx/index;补全短路径,避免 UniversalRouter 404 白屏 - location ~ ^/user/pages/([^/]+)/?$ { - return 302 /user/pages/$1/index$is_args$args; - } - - location /user/ { - rewrite ^/user/(.*)$ /$1 break; - proxy_pass http://127.0.0.1:8091; - proxy_http_version 1.1; - # serve 若仍发出绝对 Location:/pages/...,补回 /user 前缀 - proxy_redirect / /user/; - 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; - } - - location /shop/ { - rewrite ^/shop/(.*)$ /$1 break; - proxy_pass http://127.0.0.1:8092; - 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; - } - - location /partner/ { - rewrite ^/partner/(.*)$ /$1 break; - proxy_pass http://127.0.0.1:8093; - 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; - } - - # 旧 C 端根路径书签(无 /user 前缀)→ /user/... - location / { - return 302 /user$request_uri; - } -} - -server { - listen 443 ssl; - server_name shop.runxian.top; - - ssl_certificate /etc/letsencrypt/live/user.runxian.top/fullchain.pem; - ssl_certificate_key /etc/letsencrypt/live/user.runxian.top/privkey.pem; - ssl_protocols TLSv1.2 TLSv1.3; - - return 301 https://user.runxian.top/shop$request_uri; -} - -server { - listen 443 ssl; - server_name partner.runxian.top; - - ssl_certificate /etc/letsencrypt/live/user.runxian.top/fullchain.pem; - ssl_certificate_key /etc/letsencrypt/live/user.runxian.top/privkey.pem; - ssl_protocols TLSv1.2 TLSv1.3; - - return 301 https://user.runxian.top/partner$request_uri; -} - -server { - listen 80; - server_name dkapi.runxian.top; - - location ^~ /.well-known/acme-challenge/ { - root /var/www/certbot; - default_type "text/plain"; - } - - include /opt/dukang-haoke/deploy/nginx-deploy-webhook.conf; - - location / { - return 301 https://$host$request_uri; - } -} - -server { - listen 443 ssl; - server_name dkapi.runxian.top; - - access_log /var/log/nginx/dukang/runxian-api.access.log main; - error_log /var/log/nginx/dukang/runxian-api.error.log warn; - - ssl_certificate /etc/letsencrypt/live/user.runxian.top/fullchain.pem; - ssl_certificate_key /etc/letsencrypt/live/user.runxian.top/privkey.pem; - ssl_protocols TLSv1.2 TLSv1.3; - ssl_prefer_server_ciphers on; - - client_max_body_size 20m; - - include /opt/dukang-haoke/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 ""; - } -} - -server { - listen 80; - server_name webadmin.runxian.top; - - location ^~ /.well-known/acme-challenge/ { - root /var/www/certbot; - default_type "text/plain"; - } - - location / { - return 301 https://$host$request_uri; - } -} - -server { - listen 443 ssl; - server_name webadmin.runxian.top; - - access_log /var/log/nginx/dukang/runxian-admin.access.log main; - error_log /var/log/nginx/dukang/runxian-admin.error.log warn; - - ssl_certificate /etc/letsencrypt/live/user.runxian.top/fullchain.pem; - ssl_certificate_key /etc/letsencrypt/live/user.runxian.top/privkey.pem; - ssl_protocols TLSv1.2 TLSv1.3; - ssl_prefer_server_ciphers on; - - client_max_body_size 20m; - - 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 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; - } -} diff --git a/deploy/nginx-runxian-dukang.conf b/deploy/nginx-runxian-dukang.conf deleted file mode 100644 index 4acd06e..0000000 --- a/deploy/nginx-runxian-dukang.conf +++ /dev/null @@ -1,154 +0,0 @@ -# 杜康好客 — runxian.top(HTTP) -# 三端 H5 统一入口 user.runxian.top/{user,shop,partner}/(微信网页授权单域名) -# shop/partner 子域名 301 到 user.runxian.top 路径;webadmin → 8094;dkapi → 8090 - -server { - listen 80; - server_name user.runxian.top; - - access_log /var/log/nginx/dukang/runxian-h5.access.log main; - error_log /var/log/nginx/dukang/runxian-h5.error.log warn; - - client_max_body_size 20m; - - location ^~ /.well-known/acme-challenge/ { - root /var/www/certbot; - default_type "text/plain"; - } - - location ~ ^/MP_verify_.*\.txt$ { - root /opt/dukang-haoke/apps/mini-user/dist; - default_type text/plain; - access_log off; - } - - 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 = / { - return 302 /user/; - } - - location ~ ^/user/pages/([^/]+)/?$ { - return 302 /user/pages/$1/index$is_args$args; - } - - location /user/ { - rewrite ^/user/(.*)$ /$1 break; - proxy_pass http://127.0.0.1:8091; - proxy_http_version 1.1; - proxy_redirect / /user/; - 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; - } - - location /shop/ { - rewrite ^/shop/(.*)$ /$1 break; - proxy_pass http://127.0.0.1:8092; - 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; - } - - location /partner/ { - rewrite ^/partner/(.*)$ /$1 break; - proxy_pass http://127.0.0.1:8093; - 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; - } - - location / { - return 302 /user$request_uri; - } -} - -server { - listen 80; - server_name shop.runxian.top; - return 301 http://user.runxian.top/shop$request_uri; -} - -server { - listen 80; - server_name partner.runxian.top; - return 301 http://user.runxian.top/partner$request_uri; -} - -server { - listen 80; - server_name m.runxian.top; - return 301 http://user.runxian.top$request_uri; -} - -server { - listen 80; - server_name dkapi.runxian.top; - - access_log /var/log/nginx/dukang/runxian-api.access.log main; - error_log /var/log/nginx/dukang/runxian-api.error.log warn; - - client_max_body_size 20m; - - location ^~ /.well-known/acme-challenge/ { - root /var/www/certbot; - default_type "text/plain"; - } - - 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 ""; - } -} - -server { - listen 80; - server_name webadmin.runxian.top; - - access_log /var/log/nginx/dukang/runxian-admin.access.log main; - error_log /var/log/nginx/dukang/runxian-admin.error.log warn; - - client_max_body_size 20m; - - location ^~ /.well-known/acme-challenge/ { - root /var/www/certbot; - default_type "text/plain"; - } - - 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 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; - } -} diff --git a/deploy/remote-continue-m-domain.sh b/deploy/remote-continue-m-domain.sh deleted file mode 100644 index 3ad2743..0000000 --- a/deploy/remote-continue-m-domain.sh +++ /dev/null @@ -1,39 +0,0 @@ -#!/usr/bin/env bash -# 续部署:user.runxian.top 统一路径入口 + nginx 切换 -set -euo pipefail - -APP_ROOT="${APP_ROOT:-/opt/dukang-haoke}" -H5_BASE="https://user.runxian.top" - -cd "$APP_ROOT" - -echo "==> 1. PM2 重启(H5 dist 已含 /user|shop|partner/ 路径)" -pm2 restart dukang-api dukang-h5-user dukang-h5-shop dukang-h5-partner dukang-admin-web -pm2 save - -echo "==> 2. 安装 nginx HTTPS 配置" -install -m 644 "$APP_ROOT/deploy/nginx-runxian-dukang-ssl.conf" /etc/nginx/conf.d/dukang-runxian.conf -nginx -t -systemctl reload nginx - -echo "==> 3. 更新 USER_H5_URL" -ENV_FILE="$APP_ROOT/server/dukang-api/.env.production" -if grep -q '^USER_H5_URL=' "$ENV_FILE"; then - sed -i "s|^USER_H5_URL=.*|USER_H5_URL=${H5_BASE}/user|" "$ENV_FILE" -else - echo "USER_H5_URL=${H5_BASE}/user" >> "$ENV_FILE" -fi -pm2 restart dukang-api - -echo "==> 4. 验证" -for url in \ - "${H5_BASE}/user/" \ - "${H5_BASE}/shop/" \ - "${H5_BASE}/partner/" \ - "https://shop.runxian.top/" \ - "https://dkapi.runxian.top/api/v1/health"; do - code="$(curl -sk -o /dev/null -w '%{http_code}' "$url" || echo fail)" - echo " $url -> $code" -done - -echo "==> user.runxian.top 统一部署完成" diff --git a/deploy/remote-continue.sh b/deploy/remote-continue.sh deleted file mode 100644 index c075873..0000000 --- a/deploy/remote-continue.sh +++ /dev/null @@ -1,57 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -APP_ROOT="/opt/dukang-haoke" -DEPLOY_DIR="$APP_ROOT/deploy" - -echo "==> install api deps only" -cd "$APP_ROOT" -export NODE_OPTIONS="--max-old-space-size=1024" -pnpm install --filter @dukang/api... --filter @dukang/domain --filter @dukang/shared-types - -echo "==> env" -cat > "$APP_ROOT/server/dukang-api/.env.production" <<'ENV' -DATABASE_URL="mysql://dukang:Dukang2026!@localhost:3306/dukang_haoke" -REDIS_URL="redis://localhost:6379" -JWT_SECRET="gky4CNZgwdrYoDIDy4AWBiJRa4WX2ax8STe3TEG93Ht" -JWT_EXPIRES_IN="7d" -PORT=8090 -MOCK_SMS=true -MOCK_SMS_CODE=123456 -MOCK_PAY=true -MOCK_DELIVERY_AUTO=true -AUTO_APPROVE_STORE=true -ENV - -echo "==> prisma" -cd "$APP_ROOT/server/dukang-api" -pnpm prisma:generate -npx prisma db push --accept-data-loss -pnpm prisma:seed - -echo "==> serve" -npm install -g serve - -echo "==> pm2" -mkdir -p /var/log/nginx/dukang /var/www/certbot -pm2 delete dukang-api dukang-h5-user dukang-h5-shop dukang-h5-partner 2>/dev/null || true -pm2 start "$DEPLOY_DIR/ecosystem.config.cjs" -pm2 save - -echo "==> ssl" -if [ ! -f /etc/letsencrypt/live/user.ai-mirror.xyz/fullchain.pem ]; then - certbot certonly --webroot -w /var/www/certbot \ - -d user.ai-mirror.xyz -d shop.ai-mirror.xyz -d partner.ai-mirror.xyz \ - --non-interactive --agree-tos -m admin@ai-mirror.xyz -fi - -echo "==> nginx" -cp "$DEPLOY_DIR/nginx-ai-mirror.conf" /etc/nginx/conf.d/dukang-ai-mirror.conf -nginx -t -systemctl reload nginx - -echo "==> DONE" -pm2 list -ss -tlnp | grep -E '809[0-3]' || true -curl -s -o /dev/null -w "user:%{http_code}\n" http://127.0.0.1:8091/ -curl -s -o /dev/null -w "api:%{http_code}\n" http://127.0.0.1:8090/api/v1/health 2>/dev/null || curl -s -o /dev/null -w "api:%{http_code}\n" http://127.0.0.1:8090/ diff --git a/deploy/remote-setup.sh b/deploy/remote-setup.sh deleted file mode 100644 index 67d8c64..0000000 --- a/deploy/remote-setup.sh +++ /dev/null @@ -1,79 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -APP_ROOT="/opt/dukang-haoke" -DEPLOY_DIR="$(cd "$(dirname "$0")" && pwd)" - -echo "==> 1. 安装 MySQL(如未安装)" -if ! command -v mysqld &>/dev/null; then - dnf install -y mysql-server - systemctl enable --now mysqld - sleep 3 -fi - -echo "==> 2. 配置 MySQL 数据库" -mysql -uroot -e "CREATE DATABASE IF NOT EXISTS dukang_haoke CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;" 2>/dev/null || true -mysql -uroot -e "CREATE USER IF NOT EXISTS 'dukang'@'localhost' IDENTIFIED BY 'Dukang2026!';" 2>/dev/null || \ - mysql -uroot -e "ALTER USER 'dukang'@'localhost' IDENTIFIED BY 'Dukang2026!';" 2>/dev/null || true -mysql -uroot -e "GRANT ALL PRIVILEGES ON dukang_haoke.* TO 'dukang'@'localhost'; FLUSH PRIVILEGES;" 2>/dev/null || true - -echo "==> 3. 启用 pnpm" -corepack enable -corepack prepare pnpm@11.2.2 --activate - -echo "==> 4. 安装依赖并构建" -cd "$APP_ROOT" -pnpm install --frozen-lockfile 2>/dev/null || pnpm install -pnpm build - -echo "==> 5. 写入 API 生产环境变量" -cat > "$APP_ROOT/server/dukang-api/.env.production" <<'ENV' -DATABASE_URL="mysql://dukang:Dukang2026!@localhost:3306/dukang_haoke" -REDIS_URL="redis://localhost:6379" -JWT_SECRET="gky4CNZgwdrYoDIDy4AWBiJRa4WX2ax8STe3TEG93Ht" -JWT_EXPIRES_IN="7d" -PORT=8090 -MOCK_SMS=true -MOCK_SMS_CODE=123456 -MOCK_PAY=true -MOCK_DELIVERY_AUTO=true -AUTO_APPROVE_STORE=true -ENV - -echo "==> 6. 初始化数据库" -cd "$APP_ROOT/server/dukang-api" -pnpm prisma:generate -npx prisma db push --accept-data-loss -pnpm prisma:seed - -echo "==> 7. 安装 serve(静态服务)" -npm install -g serve - -echo "==> 8. 启动 PM2 进程" -mkdir -p /var/log/nginx/dukang /var/www/certbot -pm2 delete dukang-api dukang-h5-user dukang-h5-shop dukang-h5-partner 2>/dev/null || true -pm2 start "$DEPLOY_DIR/ecosystem.config.cjs" -pm2 save - -echo "==> 9. 申请 SSL 证书" -if [ ! -f /etc/letsencrypt/live/user.ai-mirror.xyz/fullchain.pem ]; then - certbot certonly --webroot -w /var/www/certbot \ - -d user.ai-mirror.xyz \ - -d shop.ai-mirror.xyz \ - -d partner.ai-mirror.xyz \ - --non-interactive --agree-tos -m admin@ai-mirror.xyz || \ - certbot certonly --nginx \ - -d user.ai-mirror.xyz \ - -d shop.ai-mirror.xyz \ - -d partner.ai-mirror.xyz \ - --non-interactive --agree-tos -m admin@ai-mirror.xyz -fi - -echo "==> 10. 配置 Nginx" -cp "$DEPLOY_DIR/nginx-ai-mirror.conf" /etc/nginx/conf.d/dukang-ai-mirror.conf -nginx -t -systemctl reload nginx - -echo "==> 部署完成" -pm2 list -ss -tlnp | grep -E '809[0-3]' || true diff --git a/deploy/server.env.machine b/deploy/server.env.machine deleted file mode 100644 index c5acb1f..0000000 --- a/deploy/server.env.machine +++ /dev/null @@ -1,4 +0,0 @@ -# 服务器机器相关(可合并到 .env.production 的参考项) -PORT=8090 -DATABASE_URL="mysql://dukang:Dukang2026!@localhost:3306/dukang_haoke" -REDIS_URL="redis://localhost:6379" diff --git a/deploy/setup-webhook.sh b/deploy/setup-webhook.sh index efdf9a1..74b3610 100644 --- a/deploy/setup-webhook.sh +++ b/deploy/setup-webhook.sh @@ -2,7 +2,7 @@ # 在服务器上执行:安装 Webhook 自动发版 set -euo pipefail -APP_ROOT="${APP_ROOT:-/opt/dukang-haoke}" +APP_ROOT="${APP_ROOT:-/opt/dukang}" DEPLOY_DIR="$APP_ROOT/deploy" ENV_FILE="$DEPLOY_DIR/auto-release.env" LOG_DIR="/var/log/dukang" @@ -30,28 +30,14 @@ 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/sites-available/dukang \ - /etc/nginx/conf.d/dukang-runxian.conf \ - /etc/nginx/conf.d/dukang-runxian-ssl.conf -do - if [[ ! -f "$conf" ]]; then - continue +NGINX_SITE="/etc/nginx/sites-available/dukang" +if [[ -f "$NGINX_SITE" ]]; then + sed -i '\|include /etc/nginx/conf.d/dukang-deploy-webhook.conf;|d' "$NGINX_SITE" + if grep -q 'server_name api.dukanghaoke.com' "$NGINX_SITE" && ! grep -qF "$MARKER" "$NGINX_SITE"; then + sed -i "/server_name api.dukanghaoke.com;/a\\ $MARKER" "$NGINX_SITE" + echo " 已 patch $NGINX_SITE (api.dukanghaoke.com)" 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 (dkapi.runxian.top)" - fi - fi -done +fi nginx -t systemctl reload nginx