From 0413d2715ce7c071e130871c357ac2de13466941 Mon Sep 17 00:00:00 2001 From: Superuser Date: Sat, 16 May 2026 23:27:24 +0800 Subject: [PATCH] =?UTF-8?q?init:=20ALiYunManager=20=E5=9F=BA=E7=A1=80?= =?UTF-8?q?=E8=AE=BE=E6=96=BD=E9=A1=B9=E7=9B=AE=20=E2=80=94=20nginx?= =?UTF-8?q?=E9=85=8D=E7=BD=AE/docker-compose/=E9=83=A8=E7=BD=B2=E6=96=87?= =?UTF-8?q?=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .env.example | 21 + .gitignore | 29 + 20260514-claude.txt | 160 ++++++ Git.md | 766 +++++++++++++++++++++++++++ Makefile | 57 ++ PROJECT_CONTEXT.md | 334 ++++++++++++ QUICKSTART.md | 122 +++++ README.md | 175 ++++++ deploy.sh | 81 +++ docker-compose.main-nginx-only.yml | 29 + docker-compose.override.yml | 26 + docker-compose.yml | 89 ++++ nginx/conf.d/dash.conf | 62 +++ nginx/conf.d/git.conf | 35 ++ nginx/conf.d/miniapp-api.conf | 42 ++ nginx/conf.d/miniapp-web.conf | 36 ++ nginx/conf.d/port-based-example.conf | 64 +++ nginx/conf.d/resume-api.conf | 43 ++ nginx/conf.d/resume-web.conf | 36 ++ nginx/conf.d/ssl-template.conf | 40 ++ nginx/logs/.gitkeep | 0 nginx/nginx.conf | 43 ++ nginx/ssl/.gitkeep | 0 scripts/backup.sh | 36 ++ scripts/init-server.sh | 108 ++++ scripts/logrotate-nginx | 13 + scripts/setup-ssl.sh | 96 ++++ scripts/update-service.sh | 47 ++ 28 files changed, 2590 insertions(+) create mode 100644 .env.example create mode 100644 .gitignore create mode 100644 20260514-claude.txt create mode 100644 Git.md create mode 100644 Makefile create mode 100644 PROJECT_CONTEXT.md create mode 100644 QUICKSTART.md create mode 100644 README.md create mode 100644 deploy.sh create mode 100644 docker-compose.main-nginx-only.yml create mode 100644 docker-compose.override.yml create mode 100644 docker-compose.yml create mode 100644 nginx/conf.d/dash.conf create mode 100644 nginx/conf.d/git.conf create mode 100644 nginx/conf.d/miniapp-api.conf create mode 100644 nginx/conf.d/miniapp-web.conf create mode 100644 nginx/conf.d/port-based-example.conf create mode 100644 nginx/conf.d/resume-api.conf create mode 100644 nginx/conf.d/resume-web.conf create mode 100644 nginx/conf.d/ssl-template.conf create mode 100644 nginx/logs/.gitkeep create mode 100644 nginx/nginx.conf create mode 100644 nginx/ssl/.gitkeep create mode 100644 scripts/backup.sh create mode 100644 scripts/init-server.sh create mode 100644 scripts/logrotate-nginx create mode 100644 scripts/setup-ssl.sh create mode 100644 scripts/update-service.sh diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..124c538 --- /dev/null +++ b/.env.example @@ -0,0 +1,21 @@ +# 环境变量配置示例 +# 复制此文件为 .env 后修改 + +# 域名配置 +DOMAIN_RESUME_WEB=me.dxz99wyr.cn +DOMAIN_MINIAPP_WEB=www.dxz99wyr.cn +DOMAIN_RESUME_API=api-resume.dxz99wyr.cn +DOMAIN_MINIAPP_API=api-miniapp.dxz99wyr.cn +DOMAIN_GIT=git.dxz99wyr.cn +DOMAIN_DASH=dash.dxz99wyr.cn + +# -- 待开发服务(上线时取消注释) -- +# DOMAIN_IMG=img.dxz99wyr.cn +# DOMAIN_LOGS=logs.dxz99wyr.cn + +# 主 Nginx 端口 +NGINX_HTTP_PORT=80 +NGINX_HTTPS_PORT=443 + +# 时区 +TZ=Asia/Shanghai diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0544573 --- /dev/null +++ b/.gitignore @@ -0,0 +1,29 @@ +# 环境变量文件(包含敏感信息) +.env + +# SSL 证书 +nginx/ssl/*.pem +nginx/ssl/*.crt +nginx/ssl/*.key + +# 日志文件 +nginx/logs/*.log +nginx/logs/*/ + +# 独立仓库的服务代码(各有自己的 Git 仓库) +services/me_jianliweb/ +services/resume-api/ +services/miniapp-web/ +services/miniapp-api/ + +# 运行时数据 +*.zip +*.tar.gz + +# IDE +.idea/ +.vscode/ +.claude/ + +# Git 子目录 +**/.git/ diff --git a/20260514-claude.txt b/20260514-claude.txt new file mode 100644 index 0000000..563692b --- /dev/null +++ b/20260514-claude.txt @@ -0,0 +1,160 @@ +================================================================================ + 阿里云多服务 Docker 部署方案 - 2026年5月14日 +================================================================================ + +一、服务器信息 +-------------------------------------------------------------------------------- + 公网 IP: 8.136.137.59 + 域名: dxz99wyr.cn + 系统: Ubuntu 5.15.0-174-generic + SSH密钥: D:\003_Project\小程序连接.pem + 项目路径: /opt/ALiYunManager + +二、架构设计 +-------------------------------------------------------------------------------- + 阿里云服务器 (8.136.137.59) + │ + beian-nginx (:80) ← 现有,已在运行 + │ + ├── api-miniapp.dxz99wyr.cn → main-nginx (:8080) + │ │ + │ 主 Nginx (Docker) + │ ┌──────────┬──────────┬──────────┐ + │ │ │ │ │ + │ resume. miniapp. api-resume. api-miniapp. + │ dxz99wyr. dxz99wyr. dxz99wyr.cn dxz99wyr.cn + │ cn cn │ │ + │ (占位) host.docker. + │ internal:3000 + │ │ + │ quanyixiaozhushou-app + │ (小程序后端, 3000端口) + │ + └── /quanyi → 静态页面 (原有服务) + +三、子域名规划 +-------------------------------------------------------------------------------- + 域名 用途 当前状态 + ───────────────────────────────────────────────────────── + resume.dxz99wyr.cn 个人简历网站 占位页面已部署 + miniapp.dxz99wyr.cn 小程序网站 占位页面已部署 + api-resume.dxz99wyr.cn 个人简历后台 占位页面已部署 + api-miniapp.dxz99wyr.cn 小程序后台 已接入真实后端 (3000) + + DNS 解析: 以上4个子域名 A 记录均指向 8.136.137.59 + +四、Docker 容器 +-------------------------------------------------------------------------------- + 容器名 端口映射 说明 + ───────────────────────────────────────────────────────── + beian-nginx 80:80, 443:443 现有,80入口 + quanyixiaozhushou-app 3000:3000 小程序后端 + quanyixiaozhushou-mongo 27018:27017 MongoDB + main-nginx 8080:80, 8443:443 主 Nginx (新) + resume-web 80 (内部) 简历网站占位 + miniapp-web 80 (内部) 小程序网站占位 + resume-api 80 (内部) 简历后台占位 + miniapp-api 80 (内部) 小程序后台占位 + + Docker 网络: aliyun-app-network (bridge) + beian-nginx 在 beian-docker_default 网络 + +五、访问链路 +-------------------------------------------------------------------------------- + 小程序后端: + 用户 → api-miniapp.dxz99wyr.cn (DNS) + → beian-nginx (:80) + → main-nginx (:8080) + → host.docker.internal:3000 (本地回环) + → quanyixiaozhushou-app (:3000) + + 简历网站: + 用户 → resume.dxz99wyr.cn → beian-nginx (:80) → main-nginx (:8080) → resume-web (:80) + + 简历后台: + 用户 → api-resume.dxz99wyr.cn → beian-nginx (:80) → main-nginx (:8080) → resume-api (:80) + + ⚠ 注:beian-nginx 目前只配了 api-miniapp 的中转, + 其他三个子域名还未配置中转,后续需要补充。 + +六、配置文件位置 +-------------------------------------------------------------------------------- + 项目目录: /opt/ALiYunManager/ + ├── docker-compose.yml 完整部署配置 + ├── docker-compose.main-nginx-only.yml 仅主 Nginx + ├── docker-compose.override.yml 开发覆盖 + ├── .env / .env.example 环境变量 (端口8080) + ├── nginx/ + │ ├── nginx.conf 主 Nginx 核心配置 + │ └── conf.d/ + │ ├── resume-web.conf 简历网站反向代理 + │ ├── miniapp-web.conf 小程序网站反向代理 + │ ├── resume-api.conf 简历后台反向代理 + │ ├── miniapp-api.conf 小程序后台反向代理 (→3000) + │ ├── ssl-template.conf HTTPS 模板 + │ └── port-based-example.conf 端口模式示例 + └── services/ + ├── resume-web/ (前端占位) + ├── miniapp-web/ (前端占位) + ├── resume-api/ (后端占位) + └── miniapp-api/ (后端占位) + + beian-nginx 配置: /opt/beian-docker/nginx.conf + beian-nginx 备份: /opt/beian-docker/nginx.conf.bak + +七、beian-nginx 中转配置要点 +-------------------------------------------------------------------------------- + - 添加了 server 块监听 api-miniapp.dxz99wyr.cn + - 反向代理到 172.19.0.1:8080 (Docker 网关 = 宿主机) + - 保留原有的 default_server 和 /quanyi 路径 + - master nginx 模板路径: /opt/beian-docker/nginx.conf → /etc/nginx/conf.d/default.conf + +八、端口说明 +-------------------------------------------------------------------------------- + 端口 开放给外网 用途 + ───────────────────────────────────── + 22 是 SSH + 80 是 HTTP 入口 (beian-nginx) + 443 是 HTTPS 入口 (beian-nginx) + 3000 否 (已关闭) 小程序后端 (仅本地回环访问) + 8080 否 主 Nginx (内部) + 8443 否 主 Nginx HTTPS (内部) + +九、常用命令 +-------------------------------------------------------------------------------- + # 部署/管理 + docker compose up -d 启动所有服务 + docker compose down 停止所有服务 + docker compose restart nginx 重启主 Nginx + docker compose exec nginx nginx -s reload 重载配置 (不重启) + docker compose ps 查看服务状态 + docker compose logs -f nginx 查看日志 + + # beian-nginx + docker exec beian-nginx nginx -t 测试配置 + docker exec beian-nginx nginx -s reload 重载配置 + + # 单个服务更新 + ./scripts/update-service.sh resume-web + +十、后续需要完成的工作 +-------------------------------------------------------------------------------- + 1. [ ] beian-nginx 补充剩下 3 个子域名的中转配置 + (resume, miniapp, api-resume) + 2. [ ] 各服务替换占位页面为真实代码 + 3. [ ] 配置 HTTPS (Certbot + SSL证书) + 4. [ ] 申请 SSL 证书覆盖 4 个子域名 + 5. [ ] 配置日志轮转 (logrotate) + 6. [ ] 阿里云 DNS: 确认 4 个子域名 A 记录都已添加 + +十一、重要提醒 +-------------------------------------------------------------------------------- + - 主 Nginx (main-nginx) 当前在 8080 端口,不对外网开放 + - 3000 端口已关闭外网访问,只走本地回环,更安全 + - 各服务容器内部始终用 80 端口,添加新服务不需要改端口 + - beian-nginx 配置修改前记得备份 (已有 .bak) + - 所有脚本已添加执行权限 + +================================================================================ + 记录时间: 2026-05-14 21:35 +================================================================================ diff --git a/Git.md b/Git.md new file mode 100644 index 0000000..5b03452 --- /dev/null +++ b/Git.md @@ -0,0 +1,766 @@ +# Git 私有仓库 + 自动部署流水线 (AI可读) + +> 基于阿里云服务器 `8.136.137.59`,部署 Gitea 私有 Git 仓库 + Webhook 自动部署流水线。 +> 遵循现有架构:beian-nginx → main-nginx → 服务容器。 +> **所有 Git 相关文件统一放在 `/home/Git/`,能容器化的全部容器化。** + +--- + +## 一、架构总览 + +``` +外网 git.dxz99wyr.cn + │ + ▼ +beian-nginx (:80/:443) + │ 新增: git.dxz99wyr.cn → 172.19.0.1:8080 + ▼ +main-nginx (:8080) + │ 新增: git.dxz99wyr.cn → gitea:3000 + ▼ +┌─────────────────────────────────────────────┐ +│ gitea (Docker) │ +│ 镜像: gitea/gitea:latest │ +│ 内部端口: 3000 (Web UI) │ +│ 内部端口: 22 (SSH Git) → 宿主机映射 2222 │ +│ 数据卷: /home/Git/gitea/data → /data │ +│ 网络: aliyun-app-network │ +└──────────┬──────────────────────────────────┘ + │ Webhook POST (push 事件) + │ URL: http://webhook:9000/hooks/xxx + ▼ +┌─────────────────────────────────────────────┐ +│ webhook (Docker / 自定义镜像) │ +│ 内部端口: 9000 │ +│ 内置: git + docker CLI + webhook 二进制 │ +│ 收到 push → 执行对应脚本 │ +│ 网络: aliyun-app-network │ +│ 挂载: docker.sock(操控宿主机 Docker) │ +│ /home/Git/webhook/ → 配置只读 │ +│ /opt/ALiYunManager/ → 更新代码+重载 │ +│ /opt/services/ → 更新各服务代码 │ +│ /home/Git/logs/ → 部署日志 │ +└──────────┬──────────────────────────────────┘ + │ git clone/pull(Docker 内网 HTTP) + │ http://${GITEA_TOKEN}@gitea:3000/... + │ docker-compose up -d(通过 docker.sock) + ▼ + ┌──────┴──────┬──────────┐ + │ │ │ +resume-web resume-api 其他服务... + (自动拉代码、构建、重启) +``` + +### 端口规划 + +| 端口 | 用途 | 对外网 | 说明 | +|------|------|--------|------| +| `2222` | Git SSH 克隆/推送(开发者用) | 开放 | gitea 容器 22 → 宿主机 2222 | +| `3000` | Gitea Web UI(容器内部) | 不开放 | 仅 Docker 网络内,通过 nginx 代理 | +| `9000` | Webhook 接收器(容器内部) | 不开放 | 仅 Docker 网络内,gitea 调用 | + +> 2222 端口需要在阿里云安全组和服务器防火墙中放行。 + +### 宿主机文件总览(仅 `/home/Git/` 目录) + +``` +/home/Git/ +├── gitea/ +│ ├── docker-compose.yml # Gitea 容器定义 +│ └── data/ # Gitea 全部数据(SQLite + 仓库 + 配置) +├── webhook/ +│ ├── Dockerfile # 自定义镜像(git + docker CLI + webhook) +│ ├── docker-compose.yml # Webhook 容器定义 +│ ├── hooks.json # Webhook 路由规则 +│ ├── .env # GITEA_TOKEN 等敏感变量 +│ └── scripts/ # 各服务部署脚本 +│ ├── deploy-common.sh +│ ├── deploy-resume-web.sh +│ ├── deploy-resume-api.sh +│ ├── deploy-aliyun-manager.sh +│ └── deploy-miniapp-web.sh +└── logs/ + └── deploy.log # 部署历史日志 +``` + +> 除此之外无需在宿主机创建其他文件。SSH 密钥、Git 配置等均在 Docker 容器内部处理。 + +--- + +## 二、部署步骤 + +### 步骤 1:服务器环境准备 + +```bash +ssh -i "D:\003_Project\小程序连接.pem" root@8.136.137.59 + +# 创建目录结构(一次性) +mkdir -p /home/Git/gitea/data +mkdir -p /home/Git/webhook/scripts +mkdir -p /home/Git/logs + +# 放行 Git SSH 端口 +ufw allow 2222/tcp +# 阿里云安全组也需要添加 2222 入方向规则 +``` + +### 步骤 2:部署 Gitea 容器 + +创建 `/home/Git/gitea/docker-compose.yml`: + +```yaml +version: "3.8" + +services: + gitea: + image: gitea/gitea:latest + container_name: gitea + restart: always + environment: + - USER_UID=1000 + - USER_GID=1000 + - GITEA__server__DOMAIN=git.dxz99wyr.cn + - GITEA__server__SSH_DOMAIN=8.136.137.59 + - GITEA__server__SSH_PORT=2222 + - GITEA__server__ROOT_URL=https://git.dxz99wyr.cn + - GITEA__server__HTTP_PORT=3000 + - GITEA__server__DISABLE_SSH=false + - GITEA__database__DB_TYPE=sqlite3 + - GITEA__repository__ENABLE_PUSH_CREATE_USER=true + - GITEA__repository__ENABLE_PUSH_CREATE_ORG=true + - GITEA__service__DISABLE_REGISTRATION=true + ports: + - "2222:22" + volumes: + - /home/Git/gitea/data:/data + - /etc/timezone:/etc/timezone:ro + - /etc/localtime:/etc/localtime:ro + networks: + - gitea-network + +networks: + gitea-network: + driver: bridge + name: aliyun-app-network +``` + +```bash +cd /home/Git/gitea +docker-compose up -d + +# 验证 +docker-compose ps +docker-compose logs -f +``` + +### 步骤 3:配置 Nginx 反向代理 + +#### 3a. main-nginx 配置 — 已存在,确认即可 + +文件 `nginx/conf.d/git.conf`(已在项目中创建): + +```nginx +server { + listen 80; + server_name git.dxz99wyr.cn; + + access_log /var/log/nginx/git.access.log main; + error_log /var/log/nginx/git.error.log warn; + + location / { + proxy_pass http://gitea:3000; + 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 Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + proxy_read_timeout 300s; + proxy_send_timeout 300s; + client_max_body_size 512m; + } +} +``` + +#### 3b. 重载 main-nginx + +```bash +cd /opt/ALiYunManager +docker-compose exec nginx nginx -t && docker-compose exec nginx nginx -s reload +``` + +#### 3c. beian-nginx 追加中转 + +```bash +# 备份 +cp /opt/beian-docker/nginx.conf /opt/beian-docker/nginx.conf.bak.$(date +%Y%m%d_%H%M) + +# 编辑配置,追加以下 server 块 +vim /opt/beian-docker/nginx.conf +``` + +在 `http {}` 内追加: + +```nginx +# Gitea 私有 Git 仓库 +server { + listen 80; + server_name git.dxz99wyr.cn; + + location / { + proxy_pass http://172.19.0.1:8080; + 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_read_timeout 300s; + proxy_send_timeout 300s; + client_max_body_size 512m; + } +} +``` + +```bash +docker exec beian-nginx nginx -t && docker exec beian-nginx nginx -s reload +``` + +### 步骤 4:DNS 解析 + +阿里云域名控制台添加: + +| 记录类型 | 主机记录 | 记录值 | +|---------|---------|--------| +| A | git | 8.136.137.59 | + +### 步骤 5:初始化 Gitea + +1. 浏览器访问 `http://git.dxz99wyr.cn` +2. 首次访问进入安装页(大部分配置已由 docker-compose.yml 环境变量预设) +3. 设置管理员账号: + - 用户名:`admin` + - 密码:**设置强密码并牢记** + - 邮箱:`admin@dxz99wyr.cn` +4. 点击「安装 Gitea」 + +### 步骤 6:创建 Gitea 访问令牌(供 Webhook 脚本拉取代码用) + +1. Gitea Web UI → 右上角头像 → **Settings** → **Applications** +2. **Generate New Token**: + - Token Name:`deploy-token` + - 权限:勾选 `read:repository` +3. 复制生成的 Token(只显示一次),保存备用 + +### 步骤 7:创建仓库 + +在 Gitea Web UI 中创建: + +| 仓库名 | 用途 | +|--------|------| +| `aliyun-manager` | ALiYunManager 部署项目 | +| `resume-web` | 个人简历前端 | +| `resume-api` | 个人简历后台 | +| `miniapp-web` | 小程序前端 | +| `miniapp-api` | 小程序后台 | + +--- + +## 三、Webhook 自动部署流水线 + +``` +git push → Gitea → Webhook POST → webhook:9000/hooks/xxx → 对应脚本 → clone/pull → docker-compose 重建 +``` + +### 步骤 8:构建 Webhook 自定义镜像 + +创建 `/home/Git/webhook/Dockerfile`: + +```dockerfile +# ============================================ +# Webhook 接收器自定义镜像 +# 内置: docker CLI + git + bash + webhook 二进制 +# ============================================ +FROM docker:cli + +RUN apk add --no-cache git bash curl + +ARG WEBHOOK_VERSION=2.8.1 +ADD https://github.com/adnanh/webhook/releases/download/${WEBHOOK_VERSION}/webhook-linux-amd64.tar.gz /tmp/ +RUN tar -xzf /tmp/webhook-linux-amd64.tar.gz -C /usr/local/bin/ webhook && \ + chmod +x /usr/local/bin/webhook && \ + rm /tmp/webhook-linux-amd64.tar.gz + +WORKDIR /opt/webhook + +ENTRYPOINT ["/usr/local/bin/webhook"] +``` + +### 步骤 9:创建 Webhook 配置文件 + +#### 9a. 环境变量 `/home/Git/webhook/.env` + +```bash +# Gitea 访问令牌(步骤 6 中生成的) +GITEA_TOKEN=粘贴你的token到这里 + +# 各个 Webhook Secret(随机生成,与 Gitea Webhook 设置保持一致) +SECRET_RESUME_WEB=resume-web-deploy-secret +SECRET_RESUME_API=resume-api-deploy-secret +SECRET_ALIYUN_MANAGER=aliyun-manager-deploy-secret +SECRET_MINIAPP_WEB=miniapp-web-deploy-secret +``` + +#### 9b. Webhook 路由 `/home/Git/webhook/hooks.json` + +```json +[ + { + "id": "resume-web", + "execute-command": "/opt/webhook/scripts/deploy-resume-web.sh", + "command-working-directory": "/opt/webhook/scripts", + "trigger-rule": { + "match": { + "type": "value", + "value": "resume-web-deploy-secret", + "parameter": { + "source": "payload", + "name": "secret" + } + } + } + }, + { + "id": "resume-api", + "execute-command": "/opt/webhook/scripts/deploy-resume-api.sh", + "command-working-directory": "/opt/webhook/scripts", + "trigger-rule": { + "match": { + "type": "value", + "value": "resume-api-deploy-secret", + "parameter": { + "source": "payload", + "name": "secret" + } + } + } + }, + { + "id": "aliyun-manager", + "execute-command": "/opt/webhook/scripts/deploy-aliyun-manager.sh", + "command-working-directory": "/opt/webhook/scripts", + "trigger-rule": { + "match": { + "type": "value", + "value": "aliyun-manager-deploy-secret", + "parameter": { + "source": "payload", + "name": "secret" + } + } + } + }, + { + "id": "miniapp-web", + "execute-command": "/opt/webhook/scripts/deploy-miniapp-web.sh", + "command-working-directory": "/opt/webhook/scripts", + "trigger-rule": { + "match": { + "type": "value", + "value": "miniapp-web-deploy-secret", + "parameter": { + "source": "payload", + "name": "secret" + } + } + } + } +] +``` + +#### 9c. docker-compose `/home/Git/webhook/docker-compose.yml` + +```yaml +version: "3.8" + +services: + webhook: + build: . + image: webhook-receiver:latest + container_name: webhook + restart: always + ports: + - "9000:9000" + env_file: + - .env + volumes: + # Webhook 配置(只读) + - /home/Git/webhook/hooks.json:/opt/webhook/hooks.json:ro + - /home/Git/webhook/scripts:/opt/webhook/scripts:ro + # 部署日志(读写) + - /home/Git/logs:/opt/webhook/logs + # 宿主机 Docker 控制权 + - /var/run/docker.sock:/var/run/docker.sock + # 各项目代码目录(用于 git pull 更新) + - /opt/ALiYunManager:/opt/ALiYunManager + - /opt/services/resume-web:/opt/services/resume-web + - /opt/services/resume-api:/opt/services/resume-api + - /opt/services/miniapp-web:/opt/services/miniapp-web + networks: + - webhook-network + command: + - "-hooks=/opt/webhook/hooks.json" + - "-verbose" + - "-hot-reload" + +networks: + webhook-network: + driver: bridge + name: aliyun-app-network +``` + +> **说明**: +> - `-hot-reload`:修改 hooks.json 后无需重启容器 +> - 代码目录挂载:webhook 容器直接 git pull 到这些目录,然后通过 docker.sock 执行 docker-compose +> - 容器内部通过 HTTP 访问 gitea:`http://gitea:3000`,无需 SSH + +#### 9d. 通用部署函数 `/home/Git/webhook/scripts/deploy-common.sh` + +```bash +#!/bin/bash +# ============================================ +# 通用部署函数库 +# 被各服务脚本 source 引用 +# 运行在 webhook 容器内 +# ============================================ + +set -e + +LOG_DIR="/opt/webhook/logs" +TIMESTAMP=$(date +"%Y-%m-%d %H:%M:%S") + +log() { + local SERVICE=$1 + local MESSAGE=$2 + echo "[$TIMESTAMP] [$SERVICE] $MESSAGE" | tee -a "$LOG_DIR/deploy.log" +} + +# 从 Gitea 拉取最新代码(Docker 内网 HTTP) +# 参数: REPO_NAME GIT_DIR BRANCH +# 使用 GITEA_TOKEN 环境变量认证 +clone_or_pull() { + local REPO_NAME=$1 + local GIT_DIR=$2 + local BRANCH=${3:-main} + + local REPO_URL="http://${GITEA_TOKEN}@gitea:3000/admin/${REPO_NAME}.git" + + if [ -d "$GIT_DIR/.git" ]; then + log "git" "拉取最新代码: ${REPO_NAME} → ${GIT_DIR} (分支: ${BRANCH})" + cd "$GIT_DIR" + git fetch origin + git reset --hard "origin/${BRANCH}" + else + log "git" "克隆仓库: ${REPO_NAME} → ${GIT_DIR} (分支: ${BRANCH})" + git clone -b "$BRANCH" "$REPO_URL" "$GIT_DIR" + fi +} + +# 重建并重启 Docker 服务 +# 参数: COMPOSE_DIR SERVICE_NAME +docker_rebuild() { + local COMPOSE_DIR=$1 + local SERVICE_NAME=$2 + + cd "$COMPOSE_DIR" + + if [ -f "Dockerfile" ]; then + log "$SERVICE_NAME" "构建镜像..." + docker-compose build "$SERVICE_NAME" + fi + + log "$SERVICE_NAME" "重启容器..." + docker-compose up -d --no-deps --force-recreate "$SERVICE_NAME" + + log "$SERVICE_NAME" "部署完成" +} +``` + +> **关键点**:`clone_or_pull` 使用 `http://${GITEA_TOKEN}@gitea:3000/...` 格式, +> Gitea 和 webhook 同属 `aliyun-app-network`,直接用容器名 `gitea:3000` 通信, +> 不经过外网,也不需要 SSH。 + +#### 9e. 各服务部署脚本 + +**个人简历前端** `/home/Git/webhook/scripts/deploy-resume-web.sh`: + +```bash +#!/bin/bash +source /opt/webhook/scripts/deploy-common.sh + +SERVICE="resume-web" +REPO_NAME="resume-web" +GIT_DIR="/opt/services/resume-web" +BRANCH="main" + +log "$SERVICE" "========== 开始部署 ==========" +clone_or_pull "$REPO_NAME" "$GIT_DIR" "$BRANCH" +docker_rebuild "$GIT_DIR" "$SERVICE" +log "$SERVICE" "========== 部署完成 ==========" +``` + +**个人简历后台** `/home/Git/webhook/scripts/deploy-resume-api.sh`: + +```bash +#!/bin/bash +source /opt/webhook/scripts/deploy-common.sh + +SERVICE="resume-api" +REPO_NAME="resume-api" +GIT_DIR="/opt/services/resume-api" +BRANCH="main" + +log "$SERVICE" "========== 开始部署 ==========" +clone_or_pull "$REPO_NAME" "$GIT_DIR" "$BRANCH" +docker_rebuild "$GIT_DIR" "$SERVICE" +log "$SERVICE" "========== 部署完成 ==========" +``` + +**ALiYunManager(nginx 配置部署)** `/home/Git/webhook/scripts/deploy-aliyun-manager.sh`: + +```bash +#!/bin/bash +source /opt/webhook/scripts/deploy-common.sh + +SERVICE="aliyun-manager" +REPO_NAME="aliyun-manager" +GIT_DIR="/opt/ALiYunManager" +BRANCH="main" + +log "$SERVICE" "========== 开始部署 ==========" +clone_or_pull "$REPO_NAME" "$GIT_DIR" "$BRANCH" + +cd "$GIT_DIR" + +# 重载 main-nginx 配置(不重启容器,零停机) +docker-compose exec -T nginx nginx -t && docker-compose exec -T nginx nginx -s reload +log "$SERVICE" "main-nginx 配置已重载" + +log "$SERVICE" "========== 部署完成 ==========" +``` + +**小程序前端** `/home/Git/webhook/scripts/deploy-miniapp-web.sh`: + +```bash +#!/bin/bash +source /opt/webhook/scripts/deploy-common.sh + +SERVICE="miniapp-web" +REPO_NAME="miniapp-web" +GIT_DIR="/opt/services/miniapp-web" +BRANCH="main" + +log "$SERVICE" "========== 开始部署 ==========" +clone_or_pull "$REPO_NAME" "$GIT_DIR" "$BRANCH" +docker_rebuild "$GIT_DIR" "$SERVICE" +log "$SERVICE" "========== 部署完成 ==========" +``` + +### 步骤 10:构建并启动 Webhook 容器 + +```bash +# 赋予脚本执行权限 +chmod +x /home/Git/webhook/scripts/*.sh + +# 构建自定义镜像并启动 +cd /home/Git/webhook +docker-compose build +docker-compose up -d + +# 验证 +docker-compose ps +docker-compose logs -f +``` + +--- + +## 四、Gitea Webhook 配置 + +对每个仓库,在 Gitea Web UI 中操作: + +### 配置步骤 + +1. 进入仓库 → **Settings** → **Webhooks** +2. 点击 **Add Webhook** → 选择 **Gitea** +3. 填写: + +| 字段 | 值 | +|------|-----| +| Target URL | `http://webhook:9000/hooks/resume-web`(对应 hooks.json 中的 id) | +| HTTP Method | `POST` | +| POST Content Type | `application/json` | +| Secret | `resume-web-deploy-secret`(与 hooks.json 和 .env 一致) | +| Trigger On | 勾选 **Push** | + +4. 点击 **Add Webhook** +5. 点击 **Test Delivery** 验证 + +### 各仓库 Webhook 配置汇总 + +| 仓库 | Target URL | Secret | +|------|-----------|--------| +| `resume-web` | `http://webhook:9000/hooks/resume-web` | `resume-web-deploy-secret` | +| `resume-api` | `http://webhook:9000/hooks/resume-api` | `resume-api-deploy-secret` | +| `aliyun-manager` | `http://webhook:9000/hooks/aliyun-manager` | `aliyun-manager-deploy-secret` | +| `miniapp-web` | `http://webhook:9000/hooks/miniapp-web` | `miniapp-web-deploy-secret` | + +> Gitea 和 webhook 同属 `aliyun-app-network`,用容器名 `webhook` 直接通信。 + +--- + +## 五、本地开发环境配置 + +### 个人 Git 配置 + +```bash +git config --global user.name "Your Name" +git config --global user.email "your-email@example.com" +``` + +### SSH 密钥(用于 git push) + +```bash +# 生成密钥(如果还没有) +ssh-keygen -t ed25519 -C "your-email@example.com" + +# 将公钥添加到 Gitea +cat ~/.ssh/id_ed25519.pub +# Gitea Web UI → Settings → SSH/GPG Keys → Add Key 粘贴 +``` + +### 关联远程仓库并推送 + +```bash +# 以 resume-web 为例 +cd D:\003_Project\ALiYunManager\services\resume-web + +git init +git add . +git commit -m "init" + +# 添加远程仓库(走 SSH,端口 2222) +git remote add origin ssh://git@8.136.137.59:2222/admin/resume-web.git + +# 推送(此后每次推送自动触发服务器部署) +git push -u origin main +``` + +### SSH 别名(可选,简化地址) + +编辑 `~/.ssh/config`: + +``` +Host gitea + HostName 8.136.137.59 + Port 2222 + User git + IdentityFile ~/.ssh/id_ed25519 +``` + +之后: + +```bash +git clone gitea:admin/resume-web.git +``` + +### 日常开发流程 + +```bash +git add . +git commit -m "feat: 更新xxx" +git push +# ↑ 推送后自动触发 Webhook → 服务器自动拉代码并部署,无需手动 ssh +``` + +--- + +## 六、安全设计 + +| 措施 | 说明 | +|------|------| +| 禁用公开注册 | `DISABLE_REGISTRATION=true` | +| Webhook 仅内网可达 | 9000 端口无宿主机映射,仅 Docker 网络内 gitea 可调用 | +| 独立 Secret | 每个仓库使用不同的 Webhook Secret | +| 令牌最小权限 | Gitea Token 仅勾选 `read:repository`,只能拉代码 | +| Token 存于 .env | 不硬编码在脚本中,`.env` 文件权限 600 | +| docker.sock 隔离 | webhook 是唯一挂载 docker.sock 的辅助容器,不对外暴露端口 | + +--- + +## 七、完整部署清单(执行顺序) + +| # | 操作 | 位置 | +|---|------|------| +| 1 | `mkdir -p /home/Git/{gitea/data,webhook/scripts,logs}` | 服务器 | +| 2 | 部署 Gitea 容器 | `/home/Git/gitea/docker-compose.yml` | +| 3 | 重载 main-nginx(git.conf 已就绪) | `/opt/ALiYunManager/` | +| 4 | beian-nginx 追加 git 中转 + 重载 | `/opt/beian-docker/nginx.conf` | +| 5 | DNS 添加 `git` A 记录 → `8.136.137.59` | 阿里云控制台 | +| 6 | Gitea Web 安装 + 管理员注册 | `http://git.dxz99wyr.cn` | +| 7 | 生成 Gitea Access Token (read:repository) | Gitea Settings → Applications | +| 8 | 创建各项目仓库 | Gitea Web UI | +| 9 | 填写 `/home/Git/webhook/.env`(GITEA_TOKEN + Secrets)| 服务器 | +| 10 | 写入 hooks.json + 各部署脚本 | `/home/Git/webhook/` | +| 11 | 构建自定义镜像 + 启动 webhook 容器 | `/home/Git/webhook/` | +| 12 | 每个仓库配置 Webhook | Gitea Web UI | +| 13 | 本地推送测试自动部署 | 开发机 | + +--- + +## 八、故障排查 + +### Webhook 不触发 + +```bash +docker logs webhook -f +# Gitea Web UI → Settings → Webhooks → Recent Deliveries 查看投递状态 +``` + +### 部署脚本报错 + +```bash +# 查看部署日志 +tail -f /home/Git/logs/deploy.log + +# 进入容器手动测试 +docker exec -it webhook sh +cd /opt/webhook/scripts +bash deploy-resume-web.sh +``` + +### Git clone 认证失败 + +```bash +# 检查 Token 是否正确 +docker exec webhook env | grep GITEA_TOKEN + +# 测试容器内能否访问 Gitea +docker exec webhook curl -s http://gitea:3000/api/v1/version +``` + +### Gitea 无法访问 + +```bash +docker ps | grep gitea +docker network inspect aliyun-app-network | grep gitea +docker logs gitea -f +``` + +--- + +## 九、ICP 备案提醒 + +`git.dxz99wyr.cn` 页面底部中间必须显示: +`浙ICP备2026030774号-1` 并链接到 `https://beian.miit.gov.cn` + +配置方式:Gitea 管理后台 → 自定义 → Footer HTML。 diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..cf5ef50 --- /dev/null +++ b/Makefile @@ -0,0 +1,57 @@ +# ============================================ +# Makefile - 简化常用操作 +# ============================================ + +.PHONY: help deploy up down restart status logs reload ssl init backup update + +help: + @echo "可用命令:" + @echo " make deploy - 首次部署所有服务" + @echo " make up - 启动服务" + @echo " make down - 停止服务" + @echo " make restart - 重启所有服务" + @echo " make status - 查看服务状态" + @echo " make logs - 查看主 Nginx 日志" + @echo " make reload - 重载 Nginx 配置(不重启)" + @echo " make ssl - 配置 SSL 证书" + @echo " make init - 初始化服务器(安装 Docker)" + @echo " make backup - 备份配置" + @echo " make update S=xxx - 更新指定服务" + +deploy: + ./deploy.sh + +up: + docker-compose up -d + +down: + docker-compose down + +restart: + docker-compose restart + +status: + docker-compose ps + +logs: + docker-compose logs -f nginx + +reload: + docker-compose exec nginx nginx -s reload + +ssl: + ./scripts/setup-ssl.sh + +init: + ./scripts/init-server.sh + +backup: + ./scripts/backup.sh + +update: + @if [ -z "$(S)" ]; then \ + echo "用法: make update S=resume-web"; \ + echo "可用服务: resume-web, miniapp-web, resume-api, miniapp-api"; \ + exit 1; \ + fi + ./scripts/update-service.sh $(S) diff --git a/PROJECT_CONTEXT.md b/PROJECT_CONTEXT.md new file mode 100644 index 0000000..5503965 --- /dev/null +++ b/PROJECT_CONTEXT.md @@ -0,0 +1,334 @@ +# ALiYunManager 项目上下文 (AI可读) + +> 本文档供 AI 助手快速理解项目部署环境、架构和服务状态,避免做出与现有环境冲突的操作。 + +--- + +## 一、服务器信息 + +| 项目 | 值 | +|------|-----| +| 公网 IP | `8.136.137.59` | +| 根域名 | `dxz99wyr.cn` | +| 操作系统 | Ubuntu (5.15.0-174-generic) | +| SSH 连接命令 | `ssh -i "D:\003_Project\小程序连接.pem" root@8.136.137.59` | +| SSH 密钥路径 | `D:\003_Project\小程序连接.pem` | +| 服务器项目路径 | `/opt/ALiYunManager` | + +--- + +## 二、全量子域名规划 + +### 已部署 / 进行中 + +| 子域名 | 用途 | 类型 | 状态 | +|--------|------|------|------| +| `me.dxz99wyr.cn` | 个人简历网站 | 前端 | 🔧 进行中 | +| `www.dxz99wyr.cn` | 小程序网站 | 前端 | ✅ 使用中 [后续替换到二级域名] | +| `api-resume.dxz99wyr.cn` | 个人简历后台 API | 后端 | ⏳ 占位,待实现 | +| `api-miniapp.dxz99wyr.cn` | 小程序后台 API | 后端 | ✅ 已接入真实后端 (:3000) | + +### 待开发 + +| 子域名 | 用途 | 类型 | 状态 | +|--------|------|------|------| +| `img.dxz99wyr.cn` | 图床网站 | 服务 | 📋 待开发 | +| `dash.dxz99wyr.cn` | 服务监控网站 | 服务 | 🔧 部署中(详见 `Dash.md`) | +| `logs.dxz99wyr.cn` | 日志监控网站 | 服务 | 📋 待开发 | +| `git.dxz99wyr.cn` | 私有 Git 仓库 + CI/CD | 服务 | 🔧 部署中(详见 `Git.md`) | + +> DNS A 记录:所有子域名均指向 `8.136.137.59`,已经在阿里云域名控制台配置。 +> +> **ICP 备案合规要求**:所有涉及二级域名对外展示的页面,**一律在页面底部中间位置**添加 ICP 备案号 `浙ICP备2026030774号-1`,并链接到 `https://beian.miit.gov.cn`。这是法律合规要求,新增任何服务时不可遗漏。 + +### 待开发服务说明 + +**1. 图床网站 `img.dxz99wyr.cn`** +- 用途:存储个人网站(me.dxz99wyr.cn)上传的图片内容,提供图片外链 +- 需要:图片上传接口、存储管理、访问权限控制 + +**2. 服务监控网站 `dash.dxz99wyr.cn`** +- 用途:在线监控服务器 CPU、内存、磁盘使用率 +- 监控各 Docker 容器的运行状态(up/down/restart) +- 监控系统各端口的占用状态、对应服务 +- 可选方案:Grafana + Prometheus、或轻量自建面板 + +**3. 日志网站 `logs.dxz99wyr.cn`** +- 用途:汇总展示所有 Docker 容器的运行日志 +- 提供历史和实时日志查看 +- 支持按服务、时间过滤 +- 可选方案:ELK (Elasticsearch + Logstash + Kibana)、Grafana Loki、或自建简易面板 + +**4. 私有 Git 仓库 `git.dxz99wyr.cn`** +- 用途:存档所有项目的源代码(包括本 ALiYunManager 项目) +- 配套 CI/CD:配置 Git Webhook + 脚本,实现 `git push` 后自动拉取代码并部署到对应服务,不再需要手动 ssh 部署 +- 可选方案:Gitea(轻量)、GitLab CE、Gogs + +--- + +## 三、端口分配(关键:防止冲突) + +### 对外网开放的端口 + +| 端口 | 用途 | 备注 | +|------|------|------| +| `22` | SSH | 必须保持 | +| `80` | HTTP 入口 | 由 **beian-nginx**(现有)占用 | +| `443` | HTTPS 入口 | 由 **beian-nginx**(现有)占用 | + +### 内部端口(不对外网) + +| 端口 | 用途 | 备注 | +|------|------|------| +| `8080` | main-nginx HTTP | Docker 容器内 80 → 宿主机 8080 | +| `8443` | main-nginx HTTPS | Docker 容器内 443 → 宿主机 8443 | +| `3000` | 小程序后端 | `quanyixiaozhushou-app`,仅本地回环访问 | + +### 端口冲突规则 + +- **绝对不要占用 80/443** — 已被 beian-nginx 使用,新增服务必须挂到 main-nginx 后面(通过 Docker 网络内部 80 通信) +- **绝对不要占用 8080** — 已被 main-nginx 映射使用 +- **绝对不要暴露 3000 到外网** — 小程序后端已关闭外网访问,仅走本地回环 +- 新增服务容器内部一律使用 `80` 端口,通过 Docker 网络互通,**不要额外映射宿主机端口** +- **新增待开发服务(img/dash/logs/git)同理**,全部挂到 main-nginx 后面,内部 80 通信,不暴露新端口到外网 + +--- + +## 四、现有 Nginx 链路(两层代理) + +``` +外网请求 + │ + ▼ +┌─────────────────────────────────────────────────────────┐ +│ beian-nginx (宿主机 :80/:443) │ ← 第1层:入口 +│ 容器名: beian-nginx │ +│ 所属网络: beian-docker_default │ +│ │ +│ 目前已配置中转: │ +│ ✅ me.dxz99wyr.cn → :8080 │ +│ ✅ www.dxz99wyr.cn → :8080 │ +│ ✅ api-resume.dxz99wyr.cn → :8080 │ +│ ✅ api-miniapp.dxz99wyr.cn → :8080 │ +│ ✅ git.dxz99wyr.cn → :8080 │ +│ ✅ dash.dxz99wyr.cn → :8080 │ +│ ✅ /quanyi → 静态页面 (原有服务) │ +└──────────────┬──────────────────────────────────────────┘ + │ 中转请求到 172.19.0.1:8080 (Docker网关=宿主机) + ▼ +┌─────────────────────────────────────────────────────────┐ +│ main-nginx (Docker :8080/:8443) │ ← 第2层:分发 +│ 容器名: main-nginx │ +│ 所属网络: aliyun-app-network │ +│ │ +│ 路由表 (已配置): │ +│ me.dxz99wyr.cn → resume-web:80 │ +│ www.dxz99wyr.cn → miniapp-web:80 │ +│ api-resume.dxz99wyr.cn → resume-api:80 │ +│ api-miniapp.dxz99wyr.cn → host.docker.internal:3000 │ +│ │ +│ 路由表 (待添加,新服务上线时): │ +│ img.dxz99wyr.cn → img-service:80 │ +│ dash.dxz99wyr.cn → dash-service:80 │ +│ logs.dxz99wyr.cn → logs-service:80 │ +│ git.dxz99wyr.cn → git-service:80 │ +└──────────────┬──────────────────────────────────────────┘ + │ Docker 内部网络 + ▼ + ┌──────────┼──────────┬──────────┐ + │ │ │ │ +resume-web miniapp-web resume-api miniapp-api +(进行中) (使用中) (占位) (→宿主机:3000) +``` + +### 关键理解 + +- **beian-nginx 是真正的入口**,main-nginx 只在内部做二级分发 +- **beian-nginx 配置文件位置**: `/opt/beian-docker/nginx.conf`(映射到容器内 `/etc/nginx/conf.d/default.conf`) +- **修改 beian-nginx 前必须先备份**: 备份文件在 `/opt/beian-docker/nginx.conf.bak` +- 重载 beian-nginx: `docker exec beian-nginx nginx -t && docker exec beian-nginx nginx -s reload` + +--- + +## 五、Docker 容器清单 + +| 容器名 | 镜像 | 网络 | 端口映射 | 说明 | +|--------|------|------|----------|------| +| `beian-nginx` | nginx | beian-docker_default | 80:80, 443:443 | **现有,勿动基础配置** | +| `main-nginx` | nginx:alpine | aliyun-app-network | 8080:80, 8443:443 | 主 Nginx,本项目管理 | +| `resume-web` | nginx:alpine | aliyun-app-network | 无(内部80) | 个人简历网站(进行中) | +| `miniapp-web` | nginx:alpine | aliyun-app-network | 无(内部80) | 小程序网站(使用中) | +| `resume-api` | nginx:alpine | aliyun-app-network | 无(内部80) | 个人简历后台(占位) | +| `miniapp-api` | nginx:alpine | aliyun-app-network | 无(内部80) | 小程序后台占位容器 | +| `quanyixiaozhushou-app` | 自有镜像 | beian-docker_default | 3000:3000 | **现有小程序后端,勿动** | +| `quanyixiaozhushou-mongo` | mongo | beian-docker_default | 27018:27017 | **现有 MongoDB,勿动** | + +### Docker 网络 + +| 网络名 | 类型 | 用途 | +|--------|------|------| +| `aliyun-app-network` | bridge | 本项目所有服务容器互通 | +| `beian-docker_default` | bridge | 现有 beian-nginx 及小程序后端 | + +> **注意**: main-nginx 通过 `extra_hosts: host.docker.internal:host-gateway` 访问宿主机端口(如 3000),不需要两个网络互通。 + +--- + +## 六、项目文件结构 + +``` +ALiYunManager/ +├── .env # 环境变量(域名+端口),修改后需重启 +├── .env.example # 环境变量模板 +├── docker-compose.yml # 完整部署(main-nginx + 4个服务) +├── docker-compose.main-nginx-only.yml # 仅主 Nginx(各服务独立部署时用) +├── docker-compose.override.yml # 开发环境覆盖(自动加载) +├── deploy.sh # 一键部署脚本 +├── Makefile # 常用命令快捷方式 +├── nginx/ +│ ├── nginx.conf # 主 Nginx 核心配置(一般不改) +│ ├── conf.d/ +│ │ ├── resume-web.conf # me.dxz99wyr.cn → resume-web:80 +│ │ ├── miniapp-web.conf # www.dxz99wyr.cn → miniapp-web:80 +│ │ ├── resume-api.conf # api-resume.dxz99wyr.cn → resume-api:80 +│ │ ├── miniapp-api.conf # api-miniapp.dxz99wyr.cn → host.docker.internal:3000 +│ │ ├── ssl-template.conf # HTTPS 配置模板(按需取消注释) +│ │ └── port-based-example.conf # 基于端口的备选方案模板 +│ ├── ssl/ # SSL 证书目录(.gitignore 排除) +│ └── logs/ # Nginx 日志目录 +├── services/ +│ ├── resume-web/ # 个人简历前端(进行中) +│ │ ├── html/index.html # 占位页面 → 替换为真实简历 +│ │ ├── nginx.conf # 内部 Nginx 配置 +│ │ ├── Dockerfile # 前端 Dockerfile +│ │ └── docker-compose.yml # 独立部署配置 +│ ├── miniapp-web/ # 小程序前端(使用中) +│ ├── resume-api/ # 个人简历后台(占位) +│ │ ├── nginx.conf # 内部 Nginx(占位) +│ │ ├── Dockerfile # 模板,含 Node/Python/Go 示例 +│ │ └── docker-compose.yml # 独立部署配置 +│ └── miniapp-api/ # 小程序后台(占位 → 实际走宿主机3000) +└── scripts/ + ├── init-server.sh # 新服务器初始化(安装 Docker 等) + ├── setup-ssl.sh # SSL 证书申请(Certbot) + ├── update-service.sh # 更新单个服务 + ├── backup.sh # 备份配置和证书 + └── logrotate-nginx # 日志轮转配置 +``` + +--- + +## 七、环境变量(.env 当前值) + +``` +DOMAIN_RESUME_WEB=me.dxz99wyr.cn +DOMAIN_MINIAPP_WEB=www.dxz99wyr.cn +DOMAIN_RESUME_API=api-resume.dxz99wyr.cn +DOMAIN_MINIAPP_API=api-miniapp.dxz99wyr.cn +NGINX_HTTP_PORT=8080 +NGINX_HTTPS_PORT=8443 +TZ=Asia/Shanghai + +# -- 待开发服务(上线时取消注释) -- +# DOMAIN_IMG=img.dxz99wyr.cn +# DOMAIN_DASHBOARD=dash.dxz99wyr.cn +# DOMAIN_LOGS=logs.dxz99wyr.cn +# DOMAIN_GIT=git.dxz99wyr.cn +``` + +--- + +## 八、操作注意事项(AI 助手必读) + +### 全局铁律(所有新增内容必须遵守) + +**规则 1 — 文件存储路径** +- 所有新增项目的文件**一律存储在 `/home/` 目录下**,子目录以项目名命名(如 `/home/Git/`、`/home/Dash/`)。 +- **能放在 Docker 容器里的,就不要放在宿主机上**。配置文件、脚本等通过 volume 挂载进容器,不要在宿主机直接运行。 + +**规则 2 — 脚本后台运行 & 开机自启** +- 所有需要持续运行的脚本/服务,启动时必须使用后台方式(nohup、screen、tmux 或 Docker 容器),**保证关闭 SSH 会话后不受影响**。 +- 必须配置**开机自启动**,云服务器重启后自动恢复运行。 + - Docker 容器:`restart: always`(已在所有 docker-compose.yml 中统一配置) + - 宿主机脚本/进程:必须配置 systemd service 或 crontab `@reboot` 条目 + - Docker 守护进程自启:`systemctl enable docker`(已由 `scripts/init-server.sh` 配置) + +**规则 3 — SSL 证书自动化** +- 所有涉及在线 Web 访问的服务,**必须通过 Certbot 自动配置 SSL 证书**(参考 `scripts/setup-ssl.sh`)。 +- 证书到期前 3 天**自动续期**,通过 crontab 定时任务实现: + ``` + 0 3 * * * certbot renew --quiet --deploy-hook 'docker exec main-nginx nginx -s reload' + ``` +- 新增服务上线时,同步更新 certbot 证书覆盖的域名列表。 + +**规则 4 — 优先使用国内镜像源** +- 所有涉及下载的操作(pip install、npm install、apt-get、apk add、docker pull、git clone 等),**优先查找并使用国内镜像源**,提升下载速度。 +- 常用国内源: + - Docker Hub:阿里云容器镜像服务、腾讯云 `mirror.ccs.tencentyun.com` + - Python pip:清华 `pypi.tuna.tsinghua.edu.cn`、阿里 `mirrors.aliyun.com/pypi/simple` + - Node.js npm:淘宝 `registry.npmmirror.com` + - Alpine apk:清华 `mirrors.tuna.tsinghua.edu.cn/alpine`、中科大 `mirrors.ustc.edu.cn/alpine` + - Debian/Ubuntu apt:阿里 `mirrors.aliyun.com/ubuntu`、清华 `mirrors.tuna.tsinghua.edu.cn/ubuntu` + - Git clone:优先使用 Docker 内网 HTTP(如 `http://gitea:3000/...`),不走外网 +- Dockerfile 中 `RUN` 命令在安装包前先替换为国内源。 + +**规则 5 — 服务修改隔离** +- 修改某一服务时,**不准修改非该服务的内容**,包括但不限于:其他服务的网页页面、nginx 配置、反向代理规则、重定向、Docker 容器配置。 +- 如果发现其他服务存在问题,**一律先告知用户**,不得自行改动。 +- **用户未正面答复确认的**(如"知道了"、"先不管"、"改"等),AI 助手在之后的每次会话中,**都需要主动提醒用户**,直到用户给出正面答复为止。 + +### 绝对不能违反的合规要求 + +0. **所有二级域名的页面底部中间必须显示 ICP 备案号**:`浙ICP备2026030774号-1`,并链接到 `https://beian.miit.gov.cn`。新增任何服务时不可遗漏。 + +### 绝对不能做的事 + +1. **不要修改 beian-nginx 的基础配置**(default_server、/quanyi 路径等),只能追加新的 server 块做域名中转 +2. **不要改动 `nginx/nginx.conf`**(主 Nginx 核心配置),除非明确需要调整全局参数 +3. **不要将 3000、8080、8443 端口暴露到外网** +4. **不要删除或停用 beian-nginx、quanyixiaozhushou-app、quanyixiaozhushou-mongo 容器** +5. **不要在 main-nginx 容器内直接改配置**,应修改本地 `nginx/conf.d/*.conf` 文件后重载 + +### 新增服务时的标准流程 + +1. 在 `/home/<项目名>/` 下创建项目目录(遵守规则 1) +2. 所有服务逻辑放入 Docker 容器,宿主机仅保留 docker-compose.yml 和配置文件(遵守规则 1) +3. 在 `nginx/conf.d/` 下创建对应的反向代理 `.conf` 文件(参考已有配置) +4. 在 `.env` 中添加新子域名变量 +5. 在本项目 `docker-compose.yml` 中添加新服务定义,确保 `restart: always`(遵守规则 2) +6. 在 beian-nginx 中追加对应的中转 server 块 +7. 在阿里云 DNS 添加子域名 A 记录 + +### 修改 beian-nginx 配置的标准流程 + +```bash +# 1. 备份当前配置 +cp /opt/beian-docker/nginx.conf /opt/beian-docker/nginx.conf.bak.$(date +%Y%m%d) + +# 2. 编辑配置(在 server 块区域追加新的域名中转) +vim /opt/beian-docker/nginx.conf + +# 3. 测试配置 +docker exec beian-nginx nginx -t + +# 4. 重载 +docker exec beian-nginx nginx -s reload +``` + +--- + +## 九、待办清单 + +| # | 事项 | 优先级 | 所属服务 | +|---|------|--------|----------| +| 1 | beian-nginx 补充中转配置(me、www、api-resume) | ✅ 已完成 | 基础设施 | +| 2 | 替换 `services/resume-web/html/` 为真实简历代码 | 🔴 高 | me.dxz99wyr.cn | +| 3 | 实现个人简历后台真实后端代码(`services/resume-api/`) | 🟡 中 | api-resume.dxz99wyr.cn | +| 4 | 配置 HTTPS / SSL 证书(运行 `./scripts/setup-ssl.sh`) | 🟡 中 | 全部 | +| 5 | 新建图床服务 `img.dxz99wyr.cn` | 🟢 低 | img | +| 6 | 部署监控面板 `dash.dxz99wyr.cn`(Dashy + Netdata + 状态API) | 🔧 进行中 | dash | +| 7 | 新建日志面板 `logs.dxz99wyr.cn`(汇总所有 Docker 日志) | 🟢 低 | logs | +| 8 | 部署私有 Git 仓库 `git.dxz99wyr.cn`(Gitea + Webhook 自动部署) | 🔧 进行中 | git | +| 9 | 配置 Git Webhook + 自动部署流水线(git push → 自动拉代码部署) | 🔧 进行中 | git/CICD | +| 10 | 配置日志轮转 (logrotate) | 🟢 低 | 基础设施 | +| 11 | 小程序网站后续替换为二级域名 | 🟢 低 | www.dxz99wyr.cn | diff --git a/QUICKSTART.md b/QUICKSTART.md new file mode 100644 index 0000000..fd721b2 --- /dev/null +++ b/QUICKSTART.md @@ -0,0 +1,122 @@ +# 快速开始指南 + +## 方案一:完整部署(所有服务一起管理) + +适用于所有服务代码都在同一个项目中管理。 + +### 1. 初始化服务器(如果是新服务器) + +```bash +ssh -i "小程序连接.pem" root@8.136.137.59 +cd /opt +git clone <你的仓库地址> ALiYunManager +cd ALiYunManager +./scripts/init-server.sh +``` + +### 2. 部署所有服务 + +```bash +./deploy.sh +``` + +### 3. 配置 DNS + +在阿里云域名控制台添加解析: + +| 记录类型 | 主机记录 | 记录值 | +|---------|---------|--------| +| A | me | 8.136.137.59 | +| A | www | 8.136.137.59 | +| A | api-resume | 8.136.137.59 | +| A | api-miniapp | 8.136.137.59 | + +### 4. 配置 HTTPS + +```bash +./scripts/setup-ssl.sh +``` + +按提示修改 `nginx/conf.d/` 下的配置文件启用 443 端口。 + +--- + +## 方案二:仅部署主 Nginx(各服务独立管理) + +适用于各服务由不同项目/仓库管理,独立部署。 + +### 1. 部署主 Nginx + +```bash +docker-compose -f docker-compose.main-nginx-only.yml up -d +``` + +### 2. 各服务独立部署 + +每个服务在自己的目录下有独立的 `docker-compose.yml`,例如: + +```yaml +# services/resume-web/docker-compose.yml +version: "3.8" +services: + resume-web: + image: nginx:alpine + container_name: resume-web + restart: always + ports: + - "8081:80" + volumes: + - ./html:/usr/share/nginx/html:ro + - ./nginx.conf:/etc/nginx/conf.d/default.conf:ro + networks: + - aliyun-app-network + +networks: + aliyun-app-network: + external: true +``` + +主 Nginx 通过端口 `8081` 反向代理到该服务。 + +--- + +## 常用操作 + +```bash +# 查看所有容器状态 +docker-compose ps + +# 查看主 Nginx 日志 +docker-compose logs -f nginx + +# 查看某个服务日志 +docker-compose logs -f resume-web + +# 重启某个服务 +docker-compose restart resume-web + +# 重载 Nginx 配置(不重启容器) +docker-compose exec nginx nginx -s reload + +# 更新单个服务 +./scripts/update-service.sh resume-web + +# 进入容器调试 +docker-compose exec nginx sh +docker-compose exec resume-web sh +``` + +--- + +## 文件说明 + +| 文件/目录 | 说明 | +|-----------|------| +| `docker-compose.yml` | 完整部署配置(含示例服务) | +| `docker-compose.main-nginx-only.yml` | 仅主 Nginx | +| `nginx/nginx.conf` | 主 Nginx 核心配置 | +| `nginx/conf.d/*.conf` | 各服务的反向代理配置 | +| `nginx/ssl/` | SSL 证书目录 | +| `services/服务名/` | 各服务独立配置 | +| `scripts/` | 辅助脚本 | +| `.env` | 环境变量配置 | diff --git a/README.md b/README.md new file mode 100644 index 0000000..03e5ee9 --- /dev/null +++ b/README.md @@ -0,0 +1,175 @@ +# ALiYunManager - 阿里云多服务 Docker 部署方案 + +## 架构概览 + +``` +┌─────────────────────────────────────────────────────────────┐ +│ 阿里云服务器 (8.136.137.59) │ +│ 主 Nginx (Docker 容器) │ +│ ┌──────────┬──────────┬──────────────┬──────────────┐ │ +│ │ me. │ www. │ api-resume. │api-miniapp. │ │ +│ │dxz99wyr. │dxz99wyr. │ dxz99wyr.cn │dxz99wyr.cn │ │ +│ │cn │cn │ │ │ │ +│ └────┬─────┴────┬─────┴──────┬───────┴──────┬───────┘ │ +│ │ │ │ │ │ +│ ┌────▼─────┐ ┌──▼─────┐ ┌───▼──────┐ ┌────▼──────┐ │ +│ │ Docker 1 │ │Docker 2│ │ Docker 3 │ │ Docker 4 │ │ +│ │个人简历网站│ │小程序网站│ │个人简历后台│ │小程序后台 │ │ +│ │内部Nginx │ │内部Nginx│ │内部Nginx │ │内部Nginx │ │ +│ └──────────┘ └────────┘ └──────────┘ └───────────┘ │ +└─────────────────────────────────────────────────────────────┘ +``` + +## 域名规划 + +| 服务 | 域名 | 类型 | +|------|------|------| +| 个人简历网站 | `me.dxz99wyr.cn` | 前端 | +| 小程序网站 | `www.dxz99wyr.cn` | 前端 | +| 个人简历后台 | `api-resume.dxz99wyr.cn` | API | +| 小程序后台 | `api-miniapp.dxz99wyr.cn` | API | + +## 目录结构 + +``` +ALiYunManager/ +├── docker-compose.yml # 主 Docker Compose 文件 +├── deploy.sh # 部署脚本 +├── README.md # 本文件 +├── nginx/ +│ ├── nginx.conf # 主 Nginx 核心配置(**不要修改**) +│ ├── conf.d/ # 各个服务的反向代理配置(由服务自行管理) +│ │ ├── resume-web.conf +│ │ ├── miniapp-web.conf +│ │ ├── resume-api.conf +│ │ └── miniapp-api.conf +│ ├── ssl/ # SSL 证书目录 +│ └── logs/ # 日志目录 +└── services/ # 各个服务的配置(每个服务自行管理) + ├── resume-web/ + │ ├── nginx.conf # 服务内部 Nginx 配置 + │ └── html/ # 静态文件 + ├── miniapp-web/ + │ ├── nginx.conf + │ └── html/ + ├── resume-api/ + │ ├── nginx.conf # 内部 Nginx 配置或反向代理 + │ └── Dockerfile # 后端 Dockerfile 模板 + └── miniapp-api/ + ├── nginx.conf + └── Dockerfile +``` + +## 核心设计原则 + +1. **主 Nginx 只负责反向代理**:将外部请求按域名分发到各个 Docker 容器 +2. **每个服务独立管理自己的配置**: + - 每个服务在 `nginx/conf.d/` 下放一个 `.conf` 文件(主 Nginx 加载) + - 每个服务在 `services/服务名/` 下放自己的内部 Nginx 配置 +3. **所有服务都在 Docker 容器中运行**:便于管理和隔离 +4. **使用 Docker 内部网络通信**:主 Nginx 通过容器名直接访问服务 + +## 快速开始 + +### 1. 上传到服务器 + +```bash +# 在项目目录打包 +zip -r aliyun-manager.zip ALiYunManager/ + +# 上传到服务器(使用你的密钥) +scp -i "D:\003_Project\小程序连接.pem" aliyun-manager.zip root@8.136.137.59:/opt/ +``` + +### 2. 在服务器上部署 + +```bash +ssh -i "D:\003_Project\小程序连接.pem" root@8.136.137.59 + +cd /opt +unzip aliyun-manager.zip +cd ALiYunManager +chmod +x deploy.sh +./deploy.sh +``` + +### 3. 配置 DNS + +在域名管理后台添加以下解析记录: + +| 记录类型 | 主机记录 | 记录值 | +|---------|---------|--------| +| A | me | 8.136.137.59 | +| A | miniapp | 8.136.137.59 | +| A | api-resume | 8.136.137.59 | +| A | api-miniapp | 8.136.137.59 | + +## 常用命令 + +```bash +# 启动所有服务 +docker-compose up -d + +# 停止所有服务 +docker-compose down + +# 查看主 Nginx 日志 +docker-compose logs -f nginx + +# 重启主 Nginx +docker-compose restart nginx + +# 查看所有容器状态 +docker-compose ps + +# 重载 Nginx 配置(不重启容器) +docker-compose exec nginx nginx -s reload +``` + +## 配置 HTTPS (SSL) + +### 方法一:使用 Certbot (推荐) + +```bash +# 进入容器安装 certbot +docker-compose exec nginx sh +apk add certbot + +# 申请证书(需要先确保 DNS 已解析) +certbot certonly --standalone -d me.dxz99wyr.cn -d www.dxz99wyr.cn -d api-resume.dxz99wyr.cn -d api-miniapp.dxz99wyr.cn +``` + +### 方法二:手动配置 + +将证书文件放入 `nginx/ssl/` 目录: +``` +nginx/ssl/ +├── me.dxz99wyr.cn.crt +├── me.dxz99wyr.cn.key +└── ... +``` + +然后修改对应服务的 `.conf` 文件,添加 443 监听和 SSL 配置。 + +## 各服务如何接入 + +### 前端网站接入 + +1. 将你的构建产物放入 `services/resume-web/html/` 目录 +2. 如需修改内部 Nginx 配置,编辑 `services/resume-web/nginx.conf` +3. 如需修改反向代理规则,编辑 `nginx/conf.d/resume-web.conf` +4. 重启对应容器 + +### 后端 API 接入 + +1. 替换 `services/resume-api/Dockerfile` 为你的后端 Dockerfile +2. 修改 `services/resume-api/nginx.conf` 中的 `upstream` 指向你的应用端口 +3. 如需修改反向代理规则,编辑 `nginx/conf.d/resume-api.conf` +4. 重新构建并启动容器 + +## 注意事项 + +1. **不要修改** `nginx/nginx.conf` 主配置文件,除非你需要调整全局参数 +2. 各个服务的 `.conf` 文件命名不要冲突 +3. 后端服务如果不需要内部 Nginx,可以直接暴露应用端口,主 Nginx 直接代理到应用端口 +4. 生产环境建议开启防火墙,只开放 80 和 443 端口 diff --git a/deploy.sh b/deploy.sh new file mode 100644 index 0000000..8168d24 --- /dev/null +++ b/deploy.sh @@ -0,0 +1,81 @@ +#!/bin/bash + +# ============================================ +# 阿里云服务器 Docker 服务部署脚本 +# ============================================ + +set -e + +# 加载环境变量 +if [ -f .env ]; then + set -a + source .env + set +a +fi + +# 设置默认值 +DOMAIN_RESUME_WEB=${DOMAIN_RESUME_WEB:-me.dxz99wyr.cn} +DOMAIN_MINIAPP_WEB=${DOMAIN_MINIAPP_WEB:-www.dxz99wyr.cn} +DOMAIN_RESUME_API=${DOMAIN_RESUME_API:-api-resume.dxz99wyr.cn} +DOMAIN_MINIAPP_API=${DOMAIN_MINIAPP_API:-api-miniapp.dxz99wyr.cn} + +echo "==========================================" +echo " 阿里云服务器 Docker 服务部署脚本" +echo "==========================================" + +# 检查 Docker 是否安装 +if ! command -v docker &> /dev/null; then + echo "错误:Docker 未安装" + echo "运行 ./scripts/init-server.sh 进行初始化安装" + exit 1 +fi + +# 检查 Docker Compose 是否安装 +if ! command -v docker-compose &> /dev/null; then + echo "错误:Docker Compose 未安装" + echo "运行 ./scripts/init-server.sh 进行初始化安装" + exit 1 +fi + +# 创建必要的目录 +mkdir -p nginx/logs +mkdir -p nginx/ssl +mkdir -p services/resume-web/html +mkdir -p services/miniapp-web/html + +echo "" +echo "检查 Docker 网络..." +if ! docker network ls | grep -q "aliyun-app-network"; then + echo "创建 Docker 网络: aliyun-app-network" + docker network create aliyun-app-network +fi + +echo "" +echo "正在启动主 Nginx 及示例服务..." +docker-compose up -d --build + +echo "" +echo "==========================================" +echo " 部署状态" +echo "==========================================" +docker-compose ps + +echo "" +echo "==========================================" +echo " 服务访问地址" +echo "==========================================" +echo " 个人简历网站: http://${DOMAIN_RESUME_WEB}" +echo " 小程序网站: http://${DOMAIN_MINIAPP_WEB}" +echo " 个人简历后台: http://${DOMAIN_RESUME_API}" +echo " 小程序后台: http://${DOMAIN_MINIAPP_API}" +echo "==========================================" + +echo "" +echo "下一步建议:" +echo " 1. 配置 DNS 解析(将域名指向 8.136.137.59)" +echo " 2. 配置 HTTPS: ./scripts/setup-ssl.sh" +echo "" +echo "常用命令:" +echo " 查看日志: docker-compose logs -f nginx" +echo " 重载配置: docker-compose exec nginx nginx -s reload" +echo "" diff --git a/docker-compose.main-nginx-only.yml b/docker-compose.main-nginx-only.yml new file mode 100644 index 0000000..2fe337f --- /dev/null +++ b/docker-compose.main-nginx-only.yml @@ -0,0 +1,29 @@ +# ============================================ +# 仅主 Nginx 的 Docker Compose 配置 +# 适用场景:各个服务独立部署,不与此文件一起管理 +# ============================================ + +version: "3.8" + +services: + nginx: + image: nginx:alpine + container_name: main-nginx + restart: always + ports: + - "80:80" + - "443:443" + volumes: + - ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro + - ./nginx/conf.d:/etc/nginx/conf.d:ro + - ./nginx/ssl:/etc/nginx/ssl:ro + - ./nginx/logs:/var/log/nginx + networks: + - app-network + extra_hosts: + - "host.docker.internal:host-gateway" + +networks: + app-network: + driver: bridge + name: aliyun-app-network diff --git a/docker-compose.override.yml b/docker-compose.override.yml new file mode 100644 index 0000000..a7eaaad --- /dev/null +++ b/docker-compose.override.yml @@ -0,0 +1,26 @@ +# ============================================ +# Docker Compose 开发环境覆盖配置 +# 此文件会自动被 docker-compose 加载,无需显式指定 +# ============================================ + +version: "3.8" + +services: + nginx: + # 开发环境映射更多日志便于调试 + volumes: + - ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro + - ./nginx/conf.d:/etc/nginx/conf.d:ro + - ./nginx/ssl:/etc/nginx/ssl:ro + - ./nginx/logs:/var/log/nginx + + resume-web: + # 开发环境自动重载静态文件 + volumes: + - ./services/resume-web/html:/usr/share/nginx/html:ro + - ./services/resume-web/nginx.conf:/etc/nginx/conf.d/default.conf:ro + + miniapp-web: + volumes: + - ./services/miniapp-web/html:/usr/share/nginx/html:ro + - ./services/miniapp-web/nginx.conf:/etc/nginx/conf.d/default.conf:ro diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..2ef9521 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,89 @@ +version: "3.8" + +services: + nginx: + image: nginx:alpine + container_name: main-nginx + restart: always + ports: + - "${NGINX_HTTP_PORT:-8080}:80" + - "${NGINX_HTTPS_PORT:-8443}:443" + volumes: + - ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro + - ./nginx/conf.d:/etc/nginx/conf.d:ro + - ./nginx/ssl:/etc/nginx/ssl:ro + - ./nginx/logs:/var/log/nginx + networks: + - app-network + extra_hosts: + - "host.docker.internal:host-gateway" + depends_on: + - resume-web + - miniapp-web + - resume-api + - miniapp-api + env_file: + - .env + + # 示例服务 - 个人简历网站 + resume-web: + image: nginx:alpine + container_name: resume-web + restart: always + volumes: + - ./services/resume-web/html:/usr/share/nginx/html:ro + - ./services/resume-web/nginx.conf:/etc/nginx/conf.d/default.conf + networks: + - app-network + expose: + - "80" + env_file: + - .env + + # 示例服务 - 小程序网站 + miniapp-web: + image: nginx:alpine + container_name: miniapp-web + restart: always + volumes: + - ./services/miniapp-web/html:/usr/share/nginx/html:ro + - ./services/miniapp-web/nginx.conf:/etc/nginx/conf.d/default.conf + networks: + - app-network + expose: + - "80" + env_file: + - .env + + # 示例服务 - 个人简历后台 + resume-api: + image: nginx:alpine + container_name: resume-api + restart: always + volumes: + - ./services/resume-api/nginx.conf:/etc/nginx/conf.d/default.conf + networks: + - app-network + expose: + - "80" + env_file: + - .env + + # 示例服务 - 小程序后台 + miniapp-api: + image: nginx:alpine + container_name: miniapp-api + restart: always + volumes: + - ./services/miniapp-api/nginx.conf:/etc/nginx/conf.d/default.conf + networks: + - app-network + expose: + - "80" + env_file: + - .env + +networks: + app-network: + driver: bridge + name: aliyun-app-network diff --git a/nginx/conf.d/dash.conf b/nginx/conf.d/dash.conf new file mode 100644 index 0000000..09962bc --- /dev/null +++ b/nginx/conf.d/dash.conf @@ -0,0 +1,62 @@ +# ============================================ +# 运维监控面板 - dash.dxz99wyr.cn +# ============================================ + +# 上游定义 +upstream dashy_upstream { + server dashy:8080; +} + +upstream netdata_upstream { + server netdata:19999; +} + +upstream dash_status_upstream { + # dash-status 使用 host 网络模式,通过宿主机访问 + server host.docker.internal:5000; +} + +# Dashy 主面板 +server { + listen 80; + server_name dash.dxz99wyr.cn; + + access_log /var/log/nginx/dash.access.log main; + error_log /var/log/nginx/dash.error.log warn; + + # Dashy Web UI + location / { + proxy_pass http://dashy_upstream; + 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 Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + } + + # Netdata 监控面板 + location /netdata/ { + proxy_pass http://netdata_upstream/; + 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 Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + proxy_read_timeout 86400s; + proxy_buffering off; + } + + # Status API + location /api/ { + proxy_pass http://dash_status_upstream/api/; + 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/nginx/conf.d/git.conf b/nginx/conf.d/git.conf new file mode 100644 index 0000000..e982ae0 --- /dev/null +++ b/nginx/conf.d/git.conf @@ -0,0 +1,35 @@ +# ============================================ +# 私有 Git 仓库 - Gitea +# 服务名: gitea +# 由主 Nginx 反向代理,此文件可独立维护 +# ============================================ + +server { + listen 80; + server_name git.dxz99wyr.cn; + + # 日志 + access_log /var/log/nginx/git.access.log main; + error_log /var/log/nginx/git.error.log warn; + + # Gitea Web UI + location / { + proxy_pass http://gitea:3000; + 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 Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + + # Gitea 需要的较大超时 + proxy_read_timeout 300s; + proxy_send_timeout 300s; + + # 上传限制(Git push 通过 Web 可能较大) + client_max_body_size 512m; + } +} diff --git a/nginx/conf.d/miniapp-api.conf b/nginx/conf.d/miniapp-api.conf new file mode 100644 index 0000000..e4b5cc1 --- /dev/null +++ b/nginx/conf.d/miniapp-api.conf @@ -0,0 +1,42 @@ +# ============================================ +# 小程序后台 - API 服务 +# 接入现有后端 quanyixiaozhushou-app (宿主机3000端口) +# 由主 Nginx 反向代理,此文件可独立维护 +# ============================================ + +server { + listen 80; + server_name api-miniapp.dxz99wyr.cn; + + # 日志 + access_log /var/log/nginx/miniapp-api.access.log main; + error_log /var/log/nginx/miniapp-api.error.log warn; + + location / { + # 反向代理到宿主机的3000端口(quanyixiaozhushou-app后端) + proxy_pass http://host.docker.internal:3000; + 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; + + # WebSocket 支持 + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + + proxy_connect_timeout 60s; + proxy_send_timeout 60s; + proxy_read_timeout 60s; + + # CORS 头部 + add_header Access-Control-Allow-Origin * always; + add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS" always; + add_header Access-Control-Allow-Headers "DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization" always; + + if ($request_method = OPTIONS) { + return 204; + } + } +} diff --git a/nginx/conf.d/miniapp-web.conf b/nginx/conf.d/miniapp-web.conf new file mode 100644 index 0000000..3ad6443 --- /dev/null +++ b/nginx/conf.d/miniapp-web.conf @@ -0,0 +1,36 @@ +# ============================================ +# 小程序网站 - 前端 +# 服务名: miniapp-web +# 由主 Nginx 反向代理,此文件可独立维护 +# ============================================ + +server { + listen 80; + server_name www.dxz99wyr.cn; + + # 日志 + access_log /var/log/nginx/miniapp-web.access.log main; + error_log /var/log/nginx/miniapp-web.error.log warn; + + location / { + proxy_pass http://miniapp-web:80; + 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_connect_timeout 60s; + proxy_send_timeout 60s; + proxy_read_timeout 60s; + } + + # 静态资源缓存 + location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ { + proxy_pass http://miniapp-web:80; + proxy_set_header Host $host; + expires 30d; + add_header Cache-Control "public, immutable"; + } +} diff --git a/nginx/conf.d/port-based-example.conf b/nginx/conf.d/port-based-example.conf new file mode 100644 index 0000000..7751f72 --- /dev/null +++ b/nginx/conf.d/port-based-example.conf @@ -0,0 +1,64 @@ +# ============================================ +# 基于端口的反向代理配置示例(备选方案) +# ============================================ +# 如果各个服务通过宿主机端口暴露(如 -p 8081:80), +# 主 Nginx 可以通过 host.docker.internal 或宿主机 IP 访问 +# ============================================ + +# 示例:假设各服务映射端口如下: +# 简历网站: 8081 +# 小程序网站: 8082 +# 简历后台: 8083 +# 小程序后台: 8084 + +# server { +# listen 80; +# server_name me.dxz99wyr.cn; +# +# location / { +# proxy_pass http://host.docker.internal:8081; +# 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 80; +# server_name www.dxz99wyr.cn; +# +# location / { +# proxy_pass http://host.docker.internal:8082; +# 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 80; +# server_name api-resume.dxz99wyr.cn; +# +# location / { +# proxy_pass http://host.docker.internal:8083; +# 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 80; +# server_name api-miniapp.dxz99wyr.cn; +# +# location / { +# proxy_pass http://host.docker.internal:8084; +# 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/nginx/conf.d/resume-api.conf b/nginx/conf.d/resume-api.conf new file mode 100644 index 0000000..320487a --- /dev/null +++ b/nginx/conf.d/resume-api.conf @@ -0,0 +1,43 @@ +# ============================================ +# 个人简历后台 - API 服务 +# 服务名: resume-api +# 由主 Nginx 反向代理,此文件可独立维护 +# ============================================ + +server { + listen 80; + server_name api-resume.dxz99wyr.cn; + + # 日志 + access_log /var/log/nginx/resume-api.access.log main; + error_log /var/log/nginx/resume-api.error.log warn; + + # 允许跨域(API 服务通常需要) + location / { + proxy_pass http://resume-api:80; + 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; + + # WebSocket 支持(如需要) + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + + proxy_connect_timeout 60s; + proxy_send_timeout 60s; + proxy_read_timeout 60s; + + # CORS 头部 + add_header Access-Control-Allow-Origin * always; + add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS" always; + add_header Access-Control-Allow-Headers "DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization" always; + + # 预检请求处理 + if ($request_method = OPTIONS) { + return 204; + } + } +} diff --git a/nginx/conf.d/resume-web.conf b/nginx/conf.d/resume-web.conf new file mode 100644 index 0000000..683872e --- /dev/null +++ b/nginx/conf.d/resume-web.conf @@ -0,0 +1,36 @@ +# ============================================ +# 个人简历网站 - 前端 +# 服务名: resume-web +# 由主 Nginx 反向代理,此文件可独立维护 +# ============================================ + +server { + listen 80; + server_name me.dxz99wyr.cn; + + # 日志 + access_log /var/log/nginx/resume-web.access.log main; + error_log /var/log/nginx/resume-web.error.log warn; + + location / { + proxy_pass http://resume-web:80; + 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_connect_timeout 60s; + proxy_send_timeout 60s; + proxy_read_timeout 60s; + } + + # 静态资源缓存 + location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ { + proxy_pass http://resume-web:80; + proxy_set_header Host $host; + expires 30d; + add_header Cache-Control "public, immutable"; + } +} diff --git a/nginx/conf.d/ssl-template.conf b/nginx/conf.d/ssl-template.conf new file mode 100644 index 0000000..f822d9a --- /dev/null +++ b/nginx/conf.d/ssl-template.conf @@ -0,0 +1,40 @@ +# ============================================ +# SSL/HTTPS 配置模板 +# ============================================ +# 申请证书后,将证书文件放入 nginx/ssl/ 目录 +# 然后为每个域名添加对应的 server 块 +# ============================================ + +# 示例:me.dxz99wyr.cn 的 HTTPS 配置 +# server { +# listen 443 ssl http2; +# server_name me.dxz99wyr.cn; +# +# ssl_certificate /etc/nginx/ssl/me.dxz99wyr.cn.crt; +# ssl_certificate_key /etc/nginx/ssl/me.dxz99wyr.cn.key; +# +# ssl_protocols TLSv1.2 TLSv1.3; +# ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384; +# ssl_prefer_server_ciphers off; +# ssl_session_cache shared:SSL:10m; +# ssl_session_timeout 1d; +# +# access_log /var/log/nginx/resume-web.access.log main; +# error_log /var/log/nginx/resume-web.error.log warn; +# +# location / { +# proxy_pass http://resume-web:80; +# 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; +# } +# } +# +# # HTTP 自动跳转到 HTTPS +# server { +# listen 80; +# server_name me.dxz99wyr.cn; +# return 301 https://$server_name$request_uri; +# } diff --git a/nginx/logs/.gitkeep b/nginx/logs/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/nginx/nginx.conf b/nginx/nginx.conf new file mode 100644 index 0000000..fece920 --- /dev/null +++ b/nginx/nginx.conf @@ -0,0 +1,43 @@ +user nginx; +worker_processes auto; +error_log /var/log/nginx/error.log notice; +pid /var/run/nginx.pid; + +events { + worker_connections 1024; + use epoll; + multi_accept on; +} + +http { + include /etc/nginx/mime.types; + default_type application/octet-stream; + + # 日志格式 + log_format main '$remote_addr - $remote_user [$time_local] "$request" ' + '$status $body_bytes_sent "$http_referer" ' + '"$http_user_agent" "$http_x_forwarded_for" ' + 'upstream=$upstream_addr response_time=$upstream_response_time'; + + access_log /var/log/nginx/access.log main; + + # 性能优化 + sendfile on; + tcp_nopush on; + tcp_nodelay on; + keepalive_timeout 65; + types_hash_max_size 2048; + + # Gzip 压缩 + gzip on; + gzip_vary on; + gzip_proxied any; + gzip_comp_level 6; + gzip_types text/plain text/css text/xml application/json application/javascript application/rss+xml application/atom+xml image/svg+xml; + + # 防止暴露版本号 + server_tokens off; + + # 引入各个服务的配置文件(每个服务独立管理) + include /etc/nginx/conf.d/*.conf; +} diff --git a/nginx/ssl/.gitkeep b/nginx/ssl/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/scripts/backup.sh b/scripts/backup.sh new file mode 100644 index 0000000..153a758 --- /dev/null +++ b/scripts/backup.sh @@ -0,0 +1,36 @@ +#!/bin/bash + +# ============================================ +# 备份脚本 +# 备份 Nginx 配置和 SSL 证书 +# ============================================ + +BACKUP_DIR="/opt/backups" +DATE=$(date +%Y%m%d_%H%M%S) +BACKUP_NAME="aliyun-manager_backup_$DATE" + +echo "==========================================" +echo " 开始备份" +echo "==========================================" + +mkdir -p "$BACKUP_DIR" + +# 备份配置 +cd "$(dirname "$0")/.." +tar czf "$BACKUP_DIR/${BACKUP_NAME}.tar.gz" \ + nginx/nginx.conf \ + nginx/conf.d/ \ + nginx/ssl/ \ + services/ \ + docker-compose.yml \ + .env \ + 2>/dev/null || true + +# 保留最近 30 天的备份 +cd "$BACKUP_DIR" +ls -t *.tar.gz | tail -n +31 | xargs rm -f 2>/dev/null || true + +echo "备份完成: $BACKUP_DIR/${BACKUP_NAME}.tar.gz" +echo "" +echo "最近备份列表:" +ls -lh "$BACKUP_DIR"/*.tar.gz 2>/dev/null | tail -5 diff --git a/scripts/init-server.sh b/scripts/init-server.sh new file mode 100644 index 0000000..a042e20 --- /dev/null +++ b/scripts/init-server.sh @@ -0,0 +1,108 @@ +#!/bin/bash + +# ============================================ +# 服务器初始化脚本 +# 在全新的阿里云服务器上运行此脚本 +# ============================================ + +set -e + +echo "==========================================" +echo " 阿里云服务器初始化" +echo "==========================================" +echo "" + +# 更新系统 +if command -v apt-get &> /dev/null; then + echo "检测到 Debian/Ubuntu 系统" + apt-get update + apt-get upgrade -y + apt-get install -y curl wget git vim unzip ufw +elif command -v yum &> /dev/null; then + echo "检测到 CentOS/RHEL 系统" + yum update -y + yum install -y curl wget git vim unzip firewalld +fi + +# 安装 Docker +echo "" +echo "正在安装 Docker..." +if ! command -v docker &> /dev/null; then + curl -fsSL https://get.docker.com | sh + systemctl start docker + systemctl enable docker + echo "Docker 安装完成" +else + echo "Docker 已安装,跳过" +fi + +# 安装 Docker Compose +echo "" +echo "正在安装 Docker Compose..." +if ! command -v docker-compose &> /dev/null; then + DOCKER_COMPOSE_VERSION=$(curl -s https://api.github.com/repos/docker/compose/releases/latest | grep -oP '"tag_name": "\K(.*)(?=")') + curl -L "https://github.com/docker/compose/releases/download/${DOCKER_COMPOSE_VERSION}/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose + chmod +x /usr/local/bin/docker-compose + ln -sf /usr/local/bin/docker-compose /usr/bin/docker-compose + echo "Docker Compose 安装完成" +else + echo "Docker Compose 已安装,跳过" +fi + +# 配置防火墙 +echo "" +echo "正在配置防火墙..." +if command -v ufw &> /dev/null; then + ufw default deny incoming + ufw default allow outgoing + ufw allow 22/tcp + ufw allow 80/tcp + ufw allow 443/tcp + ufw --force enable + echo "UFW 防火墙配置完成" +elif command -v firewall-cmd &> /dev/null; then + systemctl start firewalld + systemctl enable firewalld + firewall-cmd --permanent --add-service=ssh + firewall-cmd --permanent --add-service=http + firewall-cmd --permanent --add-service=https + firewall-cmd --reload + echo "Firewalld 防火墙配置完成" +fi + +# 配置时区 +echo "" +echo "设置时区为 Asia/Shanghai..." +timedatectl set-timezone Asia/Shanghai || true + +# Docker 镜像加速(阿里云) +echo "" +echo "配置 Docker 镜像加速..." +mkdir -p /etc/docker +cat > /etc/docker/daemon.json << 'EOF' +{ + "registry-mirrors": [ + "https://mirror.ccs.tencentyun.com", + "https://hub-mirror.c.163.com" + ], + "log-driver": "json-file", + "log-opts": { + "max-size": "10m", + "max-file": "3" + } +} +EOF +systemctl restart docker + +echo "" +echo "==========================================" +echo " 服务器初始化完成" +echo "==========================================" +echo "" +echo "Docker 版本:" +docker --version +echo "Docker Compose 版本:" +docker-compose --version +echo "" +echo "下一步:上传项目文件并运行 ./deploy.sh" +echo "" diff --git a/scripts/logrotate-nginx b/scripts/logrotate-nginx new file mode 100644 index 0000000..5bcd0c1 --- /dev/null +++ b/scripts/logrotate-nginx @@ -0,0 +1,13 @@ +/var/log/nginx/*.log { + daily + missingok + rotate 14 + compress + delaycompress + notifempty + create 0644 nginx nginx + sharedscripts + postrotate + docker exec main-nginx nginx -s reload > /dev/null 2>&1 || true + endscript +} diff --git a/scripts/setup-ssl.sh b/scripts/setup-ssl.sh new file mode 100644 index 0000000..34328af --- /dev/null +++ b/scripts/setup-ssl.sh @@ -0,0 +1,96 @@ +#!/bin/bash + +# ============================================ +# SSL 证书自动配置脚本 (使用 Certbot) +# ============================================ +# 前置条件: +# 1. 域名已解析到服务器 +# 2. 80 端口可从外网访问 +# 3. Docker 和 Docker Compose 已安装 +# ============================================ + +set -e + +DOMAIN_RESUME_WEB=${DOMAIN_RESUME_WEB:-me.dxz99wyr.cn} +DOMAIN_MINIAPP_WEB=${DOMAIN_MINIAPP_WEB:-www.dxz99wyr.cn} +DOMAIN_RESUME_API=${DOMAIN_RESUME_API:-api-resume.dxz99wyr.cn} +DOMAIN_MINIAPP_API=${DOMAIN_MINIAPP_API:-api-miniapp.dxz99wyr.cn} + +# 证书存储目录 +SSL_DIR="$(cd "$(dirname "$0")/.." && pwd)/nginx/ssl" +mkdir -p "$SSL_DIR" + +echo "==========================================" +echo " SSL 证书自动配置" +echo "==========================================" +echo "" +echo "将为以下域名申请证书:" +echo " - $DOMAIN_RESUME_WEB" +echo " - $DOMAIN_MINIAPP_WEB" +echo " - $DOMAIN_RESUME_API" +echo " - $DOMAIN_MINIAPP_API" +echo "" + +# 检查 Certbot 是否安装 +if ! command -v certbot &> /dev/null; then + echo "正在安装 Certbot..." + if command -v apt-get &> /dev/null; then + apt-get update + apt-get install -y certbot + elif command -v yum &> /dev/null; then + yum install -y certbot + elif command -v apk &> /dev/null; then + apk add certbot + else + echo "错误:无法自动安装 Certbot,请手动安装" + exit 1 + fi +fi + +# 使用 Certbot 申请证书(standalone 模式) +echo "正在申请证书..." +certbot certonly \ + --standalone \ + --agree-tos \ + --non-interactive \ + --email admin@dxz99wyr.cn \ + -d "$DOMAIN_RESUME_WEB" \ + -d "$DOMAIN_MINIAPP_WEB" \ + -d "$DOMAIN_RESUME_API" \ + -d "$DOMAIN_MINIAPP_API" \ + || { + echo "" + echo "证书申请失败,可能原因:" + echo " 1. 域名未正确解析到本服务器" + echo " 2. 80 端口被占用或防火墙阻止" + echo " 3. 请确保上述域名都已添加 A 记录指向本服务器 IP" + exit 1 + } + +# 复制证书到项目目录 +CERT_DIR="/etc/letsencrypt/live" +for domain in "$DOMAIN_RESUME_WEB" "$DOMAIN_MINIAPP_WEB" "$DOMAIN_RESUME_API" "$DOMAIN_MINIAPP_API"; do + if [ -d "$CERT_DIR/$domain" ]; then + cp "$CERT_DIR/$domain/fullchain.pem" "$SSL_DIR/$domain.crt" + cp "$CERT_DIR/$domain/privkey.pem" "$SSL_DIR/$domain.key" + echo "已复制证书: $domain" + fi +done + +# 设置自动续期 +echo "" +echo "设置证书自动续期..." +(crontab -l 2>/dev/null | grep -v "certbot renew"; echo "0 3 * * * certbot renew --quiet --deploy-hook 'docker exec main-nginx nginx -s reload'") | crontab - + +echo "" +echo "==========================================" +echo " SSL 证书配置完成" +echo "==========================================" +echo "" +echo "请执行以下步骤启用 HTTPS:" +echo " 1. 将 nginx/conf.d/ssl-template.conf 的内容取消注释" +echo " 2. 根据实际域名修改 server_name 和证书路径" +echo " 3. 重启 Nginx: docker-compose restart nginx" +echo "" +echo "证书将自动续期,每天凌晨 3 点检查" +echo "" diff --git a/scripts/update-service.sh b/scripts/update-service.sh new file mode 100644 index 0000000..3f590de --- /dev/null +++ b/scripts/update-service.sh @@ -0,0 +1,47 @@ +#!/bin/bash + +# ============================================ +# 更新单个服务脚本 +# 用法: ./update-service.sh <服务名> +# 示例: ./update-service.sh resume-web +# ============================================ + +SERVICE_NAME=$1 + +if [ -z "$SERVICE_NAME" ]; then + echo "错误:请指定服务名" + echo "用法: $0 <服务名>" + echo "可用服务: resume-web, miniapp-web, resume-api, miniapp-api" + exit 1 +fi + +if [ ! -d "services/$SERVICE_NAME" ]; then + echo "错误:服务 '$SERVICE_NAME' 不存在" + exit 1 +fi + +echo "==========================================" +echo " 更新服务: $SERVICE_NAME" +echo "==========================================" + +# 如果有 Dockerfile,重新构建 +if [ -f "services/$SERVICE_NAME/Dockerfile" ]; then + echo "检测到 Dockerfile,正在构建镜像..." + docker-compose build "$SERVICE_NAME" +fi + +# 重启指定服务 +echo "正在重启服务..." +docker-compose up -d --no-deps --force-recreate "$SERVICE_NAME" + +# 检查健康状态 +echo "" +echo "等待服务启动..." +sleep 3 + +if docker-compose ps | grep "$SERVICE_NAME" | grep -q "Up"; then + echo "服务 $SERVICE_NAME 更新成功" +else + echo "警告:服务 $SERVICE_NAME 状态异常,请检查日志" + docker-compose logs --tail=50 "$SERVICE_NAME" +fi