diff --git a/docs/superpowers/plans/2026-03-17-domain-deployment-plan.md b/docs/superpowers/plans/2026-03-17-domain-deployment-plan.md new file mode 100644 index 0000000..33cb9b9 --- /dev/null +++ b/docs/superpowers/plans/2026-03-17-domain-deployment-plan.md @@ -0,0 +1,937 @@ +# 域名部署实施计划 + +> **For agentic workers:** REQUIRED: Use superpowers:subagent-driven-development (if subagents available) or superpowers:executing-plans to implement this plan. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** 将情绪博物馆所有服务迁移到域名 lifescript.happylifeos.com,配置 HTTPS SSL 证书,并实现自动续期。 + +**Architecture:** +- 前端应用通过 Nginx 托管,使用相对路径 API 调用 +- 后端 API 通过 Nginx 反向代理暴露 +- WebSocket 通过 Nginx 升级协议代理 +- SSL 证书使用 Let's Encrypt 通过 certbot 申请,配置 systemd timer 自动续期 + +**Tech Stack:** Spring Boot, Vue 3, React, Nginx, Let's Encrypt certbot, Python 3 + +--- + +## Chunk 1: SSL 证书申请脚本 + +### Task 1: 创建 SSL 证书申请 Python 脚本 + +**Files:** +- Create: `tools/deploy-ssl-cert.py` + +- [ ] **Step 1: 创建 Python 脚本文件** + +```python +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +SSL 证书申请与自动续期脚本 +使用 certbot 工具申请 Let's Encrypt 证书并配置 nginx +""" + +import argparse +import subprocess +import sys +from pathlib import Path + +DOMAIN = "lifescript.happylifeos.com" +CERT_PATH = f"/etc/letsencrypt/live/{DOMAIN}/fullchain.pem" +KEY_PATH = f"/etc/letsencrypt/live/{DOMAIN}/privkey.pem" + + +def log_info(msg): + print(f"\033[32m[INFO]\033[0m {msg}") + + +def log_warn(msg): + print(f"\033[33m[WARN]\033[0m {msg}") + + +def log_error(msg): + print(f"\033[31m[ERROR]\033[0m {msg}") + + +def run_command(cmd, check=True): + """执行 shell 命令""" + try: + result = subprocess.run( + cmd, shell=True, check=check, capture_output=False, text=True + ) + return result.returncode == 0 + except subprocess.CalledProcessError as e: + log_error(f"命令执行失败:{e}") + return False + + +def check_certbot(): + """检查 certbot 是否安装""" + log_info("检查 certbot 是否安装...") + if not run_command("which certbot", check=False): + log_error("certbot 未安装,请先安装:apt install certbot python3-certbot-nginx") + return False + log_info("certbot 已安装") + return True + + +def check_nginx(): + """检查 nginx 配置是否正确""" + log_info("检查 nginx 配置...") + if not run_command("nginx -t", check=False): + log_error("nginx 配置有误,请先修复") + return False + log_info("nginx 配置正确") + return True + + +def apply_certificate(dry_run=False): + """申请 SSL 证书""" + log_info(f"开始为 {DOMAIN} 申请 SSL 证书...") + + cmd = f"certbot --nginx -d {DOMAIN} --non-interactive --agree-tos --email admin@happylifeos.com" + if dry_run: + cmd += " --dry-run" + log_info(f"[DRY RUN] 执行:{cmd}") + + if run_command(cmd): + log_info("证书申请成功") + return True + else: + log_error("证书申请失败") + return False + + +def setup_auto_renewal(): + """配置自动续期""" + log_info("配置证书自动续期...") + + # 检查是否已存在 systemd timer + if run_command("systemctl list-timers | grep certbot", check=False): + log_info("certbot 自动续期 timer 已存在") + return True + + # 启用 systemd timer + if run_command("systemctl enable certbot.timer && systemctl start certbot.timer"): + log_info("已启用 certbot 自动续期 timer") + return True + else: + log_warn("systemd timer 配置失败,尝试配置 cron 任务") + return setup_cron_renewal() + + +def setup_cron_renewal(): + """配置 cron 自动续期""" + cron_job = "0 3 1 * * certbot renew --quiet --deploy-hook 'systemctl reload nginx'" + log_info(f"添加 cron 任务:{cron_job}") + + # 添加到 crontab + result = subprocess.run( + f"(crontab -l 2>/dev/null | grep -v '{DOMAIN}'; echo '{cron_job}') | crontab -", + shell=True, capture_output=True, text=True + ) + + if result.returncode == 0: + log_info("cron 任务添加成功") + return True + else: + log_error("cron 任务添加失败") + return False + + +def verify_certificate(): + """验证证书是否有效""" + log_info("验证 SSL 证书...") + cmd = f'echo | openssl s_client -connect {DOMAIN}:443 -servername {DOMAIN} 2>/dev/null | openssl x509 -noout -dates' + + result = subprocess.run(cmd, shell=True, capture_output=True, text=True) + if result.returncode == 0: + log_info(f"证书信息:\n{result.stdout}") + return True + else: + log_warn("无法验证证书(可能域名 DNS 尚未生效)") + return False + + +def main(): + parser = argparse.ArgumentParser(description="SSL 证书申请与自动续期脚本") + parser.add_argument("--dry-run", action="store_true", help="模拟运行,不实际申请证书") + parser.add_argument("--renew", action="store_true", help="手动续期证书") + parser.add_argument("--verify", action="store_true", help="验证证书状态") + parser.add_argument("--setup-renewal", action="store_true", help="仅配置自动续期") + args = parser.parse_args() + + # 验证模式 + if args.verify: + verify_certificate() + return 0 + + # 仅配置自动续期 + if args.setup_renewal: + setup_auto_renewal() + return 0 + + # 手动续期 + if args.renew: + run_command("certbot renew --force-renewal") + run_command("systemctl reload nginx") + return 0 + + # 完整流程 + log_info("=== SSL 证书申请流程 ===") + + if not check_certbot(): + return 1 + + if not check_nginx(): + return 1 + + if not apply_certificate(dry_run=args.dry_run): + return 1 + + if not args.dry_run: + setup_auto_renewal() + verify_certificate() + + log_info("=== SSL 证书申请完成 ===") + return 0 + + +if __name__ == "__main__": + sys.exit(main()) +``` + +- [ ] **Step 2: 添加文件执行权限** + +```bash +chmod +x tools/deploy-ssl-cert.py +``` + +- [ ] **Step 3: 添加 Python 脚本元信息** + +在文件顶部注释中添加: +```python +""" +Author: [创建人姓名] +Created: 2026-03-17 +Purpose: SSL 证书申请与自动续期 - 使用 certbot 配置 Let's Encrypt 证书 +""" +``` + +- [ ] **Step 4: 提交** + +```bash +git add tools/deploy-ssl-cert.py +git commit -m "feat: 添加 SSL 证书申请与自动续期脚本" +``` + +--- + +## Chunk 2: 前端环境配置文件修改 + +### Task 2: 修改用户前端 (web) 生产环境配置 + +**Files:** +- Modify: `web/.env.production` + +- [ ] **Step 1: 读取当前文件内容** + +- [ ] **Step 2: 修改为域名配置** + +```env +# 生产环境配置 +VITE_APP_ENV=prod +VITE_APP_TITLE=情绪博物馆 +VITE_APP_VERSION=1.0.0 + +# API 配置 - 使用相对路径,通过 nginx 代理 +VITE_API_BASE_URL=/api +VITE_WS_BASE_URL=/ws +VITE_UPLOAD_URL=/api/upload + +# 调试配置 +VITE_DEBUG=false +VITE_MOCK=false + +# 其他配置 +VITE_APP_DESCRIPTION=情绪博物馆 Web 系统 +``` + +- [ ] **Step 3: 提交** + +```bash +git add web/.env.production +git commit -m "config: 更新 web 前端生产环境配置为域名访问" +``` + +### Task 3: 修改管理后台 (web-admin) 生产环境配置 + +**Files:** +- Modify: `web-admin/.env.production` + +- [ ] **Step 1: 读取当前文件内容** + +- [ ] **Step 2: 修改为域名配置** + +```env +# 生产环境配置 +VITE_APP_TITLE=情绪博物馆管理后台 +# 生产环境使用相对路径,通过 nginx 代理到后端服务 +VITE_APP_BASE_API=/api +``` + +- [ ] **Step 3: 提交** + +```bash +git add web-admin/.env.production +git commit -m "config: 更新管理后台生产环境配置为域名访问" +``` + +### Task 4: 修改 Life-Script 生产环境配置 + +**Files:** +- Modify: `life-script/.env.production` + +- [ ] **Step 1: 读取当前文件内容** + +- [ ] **Step 2: 修改为域名配置** + +```env +# 生产环境配置 +VITE_API_BASE_URL=/api +``` + +- [ ] **Step 3: 提交** + +```bash +git add life-script/.env.production +git commit -m "config: 更新 Life-Script 生产环境配置为域名访问" +``` + +--- + +## Chunk 3: Nginx 配置文件修改 + +### Task 5: 创建新的 Nginx 配置文件 + +**Files:** +- Modify: `conf/emotion-museum.conf` + +- [ ] **Step 1: 备份当前配置文件** + +```bash +cp conf/emotion-museum.conf conf/emotion-museum.conf.backup +``` + +- [ ] **Step 2: 修改 Nginx 配置为域名版本** + +```nginx +# Emotion Museum - 域名部署配置 +# 域名:lifescript.happylifeos.com +# 配置路径:/etc/nginx/sites-available/lifescript.happylifeos.com.conf + +# HTTP 服务器 - 强制跳转 HTTPS +server { + listen 80; + server_name lifescript.happylifeos.com; + + # 强制跳转 HTTPS + return 301 https://$server_name$request_uri; +} + +# HTTPS 服务器 +server { + listen 443 ssl http2; + server_name lifescript.happylifeos.com; + + # SSL 证书配置 + ssl_certificate /etc/letsencrypt/live/lifescript.happylifeos.com/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/lifescript.happylifeos.com/privkey.pem; + + # SSL 优化配置 + ssl_protocols TLSv1.2 TLSv1.3; + ssl_prefer_server_ciphers on; + ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384; + ssl_session_cache shared:SSL:10m; + ssl_session_timeout 10m; + + # HSTS (可选,生产环境建议开启) + # add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; + + # 根路径 - 用户前端应用 + location / { + alias /data/www/emotion-museum/; + autoindex off; + + # 处理 Vue Router 的 history 模式 + try_files $uri $uri/ /index.html; + + # HTML 文件不缓存 + location ~ \.html?$ { + add_header Cache-Control "no-cache, no-store, must-revalidate"; + add_header Pragma "no-cache"; + add_header Expires "0"; + } + + # 静态资源缓存 1 年 + location ~ \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ { + add_header Cache-Control "public, max-age=31536000, immutable"; + expires 1y; + } + } + + # 管理后台应用路径 + location /emotion-museum-admin/ { + alias /data/www/emotion-museum-admin/; + autoindex off; + + # 处理 Vue Router 的 history 模式 + try_files $uri $uri/ /emotion-museum-admin/index.html; + + # HTML 文件不缓存 + location ~ \.html?$ { + add_header Cache-Control "no-cache, no-store, must-revalidate"; + add_header Pragma "no-cache"; + add_header Expires "0"; + } + + # 静态资源缓存 1 年 + location ~ \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ { + add_header Cache-Control "public, max-age=31536000, immutable"; + expires 1y; + } + } + + # 处理不带末尾斜杠的 /emotion-museum-admin 请求 + location = /emotion-museum-admin { + rewrite ^(.*)$ $1/ permanent; + } + + # Life-Script 应用路径 + location /life-script/ { + alias /data/www/life-script/; + autoindex off; + + # 处理 React Router 的 history 模式 + try_files $uri $uri/ /life-script/index.html; + + # HTML 文件不缓存 + location ~ \.html?$ { + add_header Cache-Control "no-cache, no-store, must-revalidate"; + add_header Pragma "no-cache"; + add_header Expires "0"; + } + + # 静态资源缓存 1 年 + location ~ \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ { + add_header Cache-Control "public, max-age=31536000, immutable"; + expires 1y; + } + } + + # 处理不带末尾斜杠的 /life-script 请求 + location = /life-script { + rewrite ^ /life-script/ last; + } + + # 后端 API 代理 + location /api { + proxy_pass http://127.0.0.1:19089; + 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_connect_timeout 60s; + proxy_send_timeout 60s; + proxy_read_timeout 60s; + } + + # WebSocket 代理 + location /ws { + proxy_pass http://127.0.0.1:19089; + 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; + + # WebSocket 超时设置 + proxy_connect_timeout 7d; + proxy_send_timeout 7d; + proxy_read_timeout 7d; + } + + # 健康检查端点 + location /health { + access_log off; + return 200 "healthy\n"; + add_header Content-Type text/plain; + } + + # 禁止访问敏感文件 + location ~ /\. { + deny all; + access_log off; + log_not_found off; + } + + access_log /var/log/nginx/lifescript_access.log; + error_log /var/log/nginx/lifescript_error.log; +} +``` + +- [ ] **Step 3: 提交** + +```bash +git add conf/emotion-museum.conf +git commit -m "config: 更新 nginx 配置为域名访问,添加 HTTPS SSL 支持" +``` + +--- + +## Chunk 4: 部署脚本修改 + +### Task 6: 创建新域名下的一键部署脚本 + +**Files:** +- Create: `deploy-to-prod.sh` + +- [ ] **Step 1: 创建部署脚本** + +```bash +#!/bin/bash + +# 情绪博物馆 - 域名部署脚本 +# 域名:lifescript.happylifeos.com +# 使用方法:bash deploy-to-prod.sh [ssl|frontend|admin|life-script|backend|all] + +set -e + +# 颜色定义 +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' + +# 日志函数 +log_info() { + echo -e "${GREEN}[INFO]${NC} $1" +} + +log_warn() { + echo -e "${YELLOW}[WARN]${NC} $1" +} + +log_error() { + echo -e "${RED}[ERROR]${NC} $1" +} + +log_section() { + echo "" + echo -e "${BLUE}╔════════════════════════════════════════════════════════════════╗${NC}" + echo -e "${BLUE}║${NC} $1" + echo -e "${BLUE}╚════════════════════════════════════════════════════════════════╝${NC}" + echo "" +} + +# 服务器配置 +SERVER_IP="101.200.208.45" +USERNAME="root" +DOMAIN="lifescript.happylifeos.com" + +# SSL 证书申请 +deploy_ssl() { + log_section "申请 SSL 证书" + + if [ ! -f "tools/deploy-ssl-cert.py" ]; then + log_error "SSL 证书脚本不存在:tools/deploy-ssl-cert.py" + return 1 + fi + + log_info "在服务器上执行 SSL 证书申请..." + scp tools/deploy-ssl-cert.py ${USERNAME}@${SERVER_IP}:/tmp/deploy-ssl-cert.py + ssh ${USERNAME}@${SERVER_IP} "python3 /tmp/deploy-ssl-cert.py" + + if [ $? -eq 0 ]; then + log_info "✅ SSL 证书申请完成" + return 0 + else + log_error "❌ SSL 证书申请失败" + return 1 + fi +} + +# 部署后端 +deploy_backend() { + log_section "部署后端服务" + + if [ ! -f "backend-single/deploy.sh" ]; then + log_error "后端部署脚本不存在" + return 1 + fi + + log_info "执行后端部署..." + cd backend-single + bash deploy.sh remote + local result=$? + cd .. + + if [ $result -eq 0 ]; then + log_info "✅ 后端部署完成" + return 0 + else + log_error "❌ 后端部署失败" + return 1 + fi +} + +# 部署前端 +deploy_frontend() { + log_section "部署用户前端" + + if [ ! -f "web/deploy.sh" ]; then + log_error "前端部署脚本不存在" + return 1 + fi + + log_info "执行前端部署..." + cd web + bash deploy.sh + local result=$? + cd .. + + if [ $result -eq 0 ]; then + log_info "✅ 前端部署完成" + return 0 + else + log_error "❌ 前端部署失败" + return 1 + fi +} + +# 部署管理后台 +deploy_admin() { + log_section "部署管理后台" + + if [ ! -f "web-admin/deploy.sh" ]; then + log_error "管理后台部署脚本不存在" + return 1 + fi + + log_info "执行管理后台部署..." + cd web-admin + bash deploy.sh + local result=$? + cd .. + + if [ $result -eq 0 ]; then + log_info "✅ 管理后台部署完成" + return 0 + else + log_error "❌ 管理后台部署失败" + return 1 + fi +} + +# 部署 Life-Script +deploy_life_script() { + log_section "部署 Life-Script" + + if [ ! -f "life-script/deploy.sh" ]; then + log_error "Life-Script 部署脚本不存在" + return 1 + fi + + log_info "执行 Life-Script 部署..." + cd life-script + bash deploy.sh + local result=$? + cd .. + + if [ $result -eq 0 ]; then + log_info "✅ Life-Script 部署完成" + return 0 + else + log_error "❌ Life-Script 部署失败" + return 1 + fi +} + +# 部署 Nginx 配置 +deploy_nginx() { + log_section "部署 Nginx 配置" + + if [ ! -f "conf/emotion-museum.conf" ]; then + log_error "Nginx 配置文件不存在" + return 1 + fi + + log_info "上传 Nginx 配置文件..." + scp conf/emotion-museum.conf ${USERNAME}@${SERVER_IP}:/etc/nginx/sites-available/${DOMAIN}.conf + + log_info "启用站点配置..." + ssh ${USERNAME}@${SERVER_IP} "ln -snf /etc/nginx/sites-available/${DOMAIN}.conf /etc/nginx/sites-enabled/${DOMAIN}.conf" + + log_info "移除默认配置(如果存在冲突)..." + ssh ${USERNAME}@${SERVER_IP} "rm -f /etc/nginx/sites-enabled/default" + + log_info "验证 Nginx 配置..." + if ssh ${USERNAME}@${SERVER_IP} "nginx -t"; then + log_info "Nginx 配置验证通过" + ssh ${USERNAME}@${SERVER_IP} "systemctl reload nginx" + log_info "✅ Nginx 配置重载完成" + return 0 + else + log_error "❌ Nginx 配置验证失败" + return 1 + fi +} + +# 主程序 +main() { + DEPLOY_TYPE="${1:-all}" + + log_section "情绪博物馆 - 域名部署" + log_info "域名:https://${DOMAIN}" + log_info "部署类型:${DEPLOY_TYPE}" + log_info "部署时间:$(date '+%Y-%m-%d %H:%M:%S')" + + case "$DEPLOY_TYPE" in + ssl) + deploy_ssl + ;; + backend) + deploy_backend + ;; + frontend) + deploy_frontend + ;; + admin) + deploy_admin + ;; + life-script) + deploy_life_script + ;; + nginx) + deploy_nginx + ;; + all) + deploy_ssl + deploy_nginx + deploy_backend + deploy_frontend + deploy_admin + deploy_life_script + ;; + *) + log_error "无效的部署类型:$DEPLOY_TYPE" + echo "使用方法:bash deploy-to-prod.sh [ssl|backend|frontend|admin|life-script|nginx|all]" + exit 1 + ;; + esac + + log_section "部署完成" + + if [ "$DEPLOY_TYPE" = "all" ] || [ "$DEPLOY_TYPE" = "ssl" ]; then + log_info "📋 验证 SSL 证书:运行 python3 tools/deploy-ssl-cert.py --verify" + fi + + if [ "$DEPLOY_TYPE" = "all" ] || [ "$DEPLOY_TYPE" = "nginx" ]; then + log_info "🌐 访问地址:" + log_info " 用户前端:https://${DOMAIN}/" + log_info " 管理后台:https://${DOMAIN}/emotion-museum-admin/" + log_info " Life-Script: https://${DOMAIN}/life-script/" + log_info " API 地址:https://${DOMAIN}/api" + log_info " WebSocket: wss://${DOMAIN}/ws" + fi +} + +main "$@" +``` + +- [ ] **Step 2: 添加执行权限** + +```bash +chmod +x deploy-to-prod.sh +``` + +- [ ] **Step 3: 添加元信息** + +在文件顶部添加: +```bash +#!/bin/bash +# Author: [创建人姓名] +# Created: 2026-03-17 +# Purpose: 域名部署入口脚本 - 支持 SSL 证书申请、前端、后端、nginx 配置部署 +``` + +- [ ] **Step 4: 提交** + +```bash +git add deploy-to-prod.sh +git commit -m "feat: 添加域名一键部署脚本" +``` + +### Task 7: 修改用户前端部署脚本 + +**Files:** +- Modify: `web/deploy.sh` + +- [ ] **Step 1: 读取当前文件** + +- [ ] **Step 2: 修改远程路径和访问地址提示** + +将访问地址提示修改为: +```bash +echo "✅ 部署完成!" +echo "📱 访问地址:https://lifescript.happylifeos.com/" +``` + +- [ ] **Step 3: 提交** + +```bash +git add web/deploy.sh +git commit -m "config: 更新前端部署脚本访问地址提示" +``` + +### Task 8: 修改管理后台部署脚本 + +**Files:** +- Modify: `web-admin/deploy.sh` + +- [ ] **Step 1: 读取当前文件** + +- [ ] **Step 2: 修改访问地址提示** + +将访问地址提示修改为: +```bash +echo "✅ 管理后台部署完成!" +echo "🔧 访问地址:https://lifescript.happylifeos.com/emotion-museum-admin/" +``` + +- [ ] **Step 3: 提交** + +```bash +git add web-admin/deploy.sh +git commit -m "config: 更新管理后台部署脚本访问地址提示" +``` + +--- + +## Chunk 5: 后端配置与验证 + +### Task 9: 检查并修改后端 CORS 配置 + +**Files:** +- Modify: `backend-single/src/main/resources/application.yml` (或相应配置文件) + +- [ ] **Step 1: 读取当前后端配置文件** + +检查 CORS 配置是否允许新域名访问 + +- [ ] **Step 2: 如需修改,添加域名白名单** + +确保 CORS 配置包含 `https://lifescript.happylifeos.com` + +- [ ] **Step 3: 提交** + +```bash +git add backend-single/src/main/resources/application.yml +git commit -m "config: 更新 CORS 配置允许新域名访问" +``` + +### Task 10: 执行部署验证 + +**Files:** +- 无需修改文件 + +- [ ] **Step 1: 本地类型检查** + +```bash +cd web && npm run type-check +cd ../web-admin && npm run type-check +cd ../life-script && npm run type-check +``` + +- [ ] **Step 2: 推送代码到服务器** + +```bash +git push origin master +``` + +- [ ] **Step 3: 执行 SSL 证书申请** + +```bash +bash deploy-to-prod.sh ssl +``` + +- [ ] **Step 4: 执行完整部署** + +```bash +bash deploy-to-prod.sh all +``` + +- [ ] **Step 5: 浏览器验证** + +使用浏览器访问以下地址验证: +- https://lifescript.happylifeos.com/ +- https://lifescript.happylifeos.com/emotion-museum-admin/ +- https://lifescript.happylifeos.com/life-script/ +- https://lifescript.happylifeos.com/api/health + +- [ ] **Step 6: 验证浏览器 Console 无错误** + +确保所有页面: +- ✅ 正常加载 +- ✅ 无 JavaScript 错误 +- ✅ API 请求成功 +- ✅ WebSocket 连接成功 + +--- + +## 部署总结 + +### 文件清单 + +| 文件 | 操作 | 说明 | +|------|------|------| +| `tools/deploy-ssl-cert.py` | 创建 | SSL 证书申请与自动续期脚本 | +| `web/.env.production` | 修改 | 前端 API 配置改为相对路径 | +| `web-admin/.env.production` | 修改 | 管理后台 API 配置改为相对路径 | +| `life-script/.env.production` | 修改 | Life-Script API 配置改为相对路径 | +| `conf/emotion-museum.conf` | 修改 | Nginx 域名配置 | +| `deploy-to-prod.sh` | 创建 | 域名部署入口脚本 | +| `web/deploy.sh` | 修改 | 更新访问地址提示 | +| `web-admin/deploy.sh` | 修改 | 更新访问地址提示 | + +### 部署命令 + +```bash +# 1. 提交所有配置变更 +git add . +git commit -m "chore: 域名部署配置更新" +git push + +# 2. 申请 SSL 证书 +bash deploy-to-prod.sh ssl + +# 3. 部署所有服务 +bash deploy-to-prod.sh all +``` + +### 验证检查清单 + +- [ ] SSL 证书有效且自动续期已配置 +- [ ] HTTPS 强制跳转生效 +- [ ] 用户前端正常访问 +- [ ] 管理后台正常访问 +- [ ] Life-Script 正常访问 +- [ ] API 代理正常 +- [ ] WebSocket 连接正常 +- [ ] 浏览器 Console 无错误 +- [ ] 所有静态资源正确加载